From 4778d6008521a3772c67f881b65f378237f98bcf Mon Sep 17 00:00:00 2001 From: Murali Parthasarathy K Date: Tue, 18 Mar 2025 15:00:14 +0100 Subject: [PATCH] Bug fixes from Integration Testing of OPA-PDP Issue-ID: POLICY-5316 Change-Id: I1c848efd1b6df616c0fefe6113c04c63ebde06ec Signed-off-by: Murali Parthasarathy K --- README.md | 61 +-- cmd/opa-pdp/opa-pdp.go | 5 +- cmd/opa-pdp/opa-pdp_test.go | 164 +++----- consts/constants.go | 16 +- pkg/data/data-handler.go | 159 ++++--- pkg/data/data-handler_test.go | 50 --- pkg/decision/decision-provider.go | 153 ++++--- pkg/decision/decision-provider_test.go | 464 ++++++++++++++++----- pkg/kafkacomm/handler/pdp_update_deploy_policy.go | 8 +- .../handler/pdp_update_undeploy_policy.go | 173 +++++++- .../handler/pdp_update_undeploy_policy_test.go | 81 ++-- pkg/kafkacomm/publisher/pdp-heartbeat.go | 2 +- pkg/utils/sort.go | 41 ++ pkg/utils/utils.go | 143 +++++-- pkg/utils/utils_test.go | 151 ++++++- test/Opagroup.json | 23 - test/README.md | 118 ++---- test/config.json | 8 - test/config/opa-pdp/config.json | 8 - test/config/opa-pdp/groups.json | 15 - test/config/opa-pdp/policy-opa-pdp.sh | 9 - test/data/abac/data.json | 94 ----- test/data/account/data.json | 16 - test/data/action/data.json | 43 -- test/data/blacklist/data.json | 6 + test/data/cell/consistency/data.json | 5 + test/data/docs/data.json | 7 - test/data/monitor/data.json | 13 + test/data/organization/data.json | 32 -- test/data/vehicle/data.json | 7 - test/data/zone/data.json | 10 - test/docker-compose.yml | 140 ------- test/policies/abac/policy.rego | 20 - .../{example => access_method}/policy.rego | 2 +- test/policies/account/policy.rego | 17 - test/policies/action/policy.rego | 21 - test/policies/blacklist/policy.rego | 18 + test/policies/cell/consistency/policy.rego | 17 + .../policies/cell/consistency/topology/policy.rego | 6 + test/policies/data/abac/data.json | 94 ----- test/policies/data/account/data.json | 16 - test/policies/data/action/data.json | 43 -- test/policies/data/organization/data.json | 32 -- test/policies/data/role/data.json | 63 --- test/policies/docs/policy.rego | 22 - test/policies/monitor/policy.rego | 39 ++ test/policies/organization/policy.rego | 38 -- test/policies/vehicle/policy.rego | 23 - test/policies/zone/policy.rego | 23 - test/policy-new.yaml | 21 - test/scripts.sh | 27 -- test/scripts.txt | 21 - test/test_resources/policy_collab.yaml | 18 - test/test_resources/policy_conflict.yaml | 15 - .../policy_deploy_single_policy.yaml | 17 - test/test_resources/policy_zone.yaml | 16 - test/test_resources/undeploy_batch_delete.json | 23 - .../access_method/deploy_access_method.json} | 2 +- .../access_method/policy_access_method.yaml | 15 + .../blacklist/deploy_blacklist.json} | 2 +- test/toscapolicies/blacklist/policy_blacklist.yaml | 18 + test/toscapolicies/cell/deploy_cell.json | 10 + test/toscapolicies/cell/policy_cell.yaml | 21 + .../monitor/deploy_monitor.json} | 3 +- test/toscapolicies/monitor/policy_monitor.yaml | 16 + .../role/deploy_role.json} | 0 test/toscapolicies/role/policy_role.yaml | 16 + test/wait_for_port.sh | 91 ---- 68 files changed, 1402 insertions(+), 1669 deletions(-) create mode 100644 pkg/utils/sort.go delete mode 100644 test/Opagroup.json delete mode 100644 test/config.json delete mode 100644 test/config/opa-pdp/config.json delete mode 100644 test/config/opa-pdp/groups.json delete mode 100755 test/config/opa-pdp/policy-opa-pdp.sh delete mode 100644 test/data/abac/data.json delete mode 100644 test/data/account/data.json delete mode 100644 test/data/action/data.json create mode 100644 test/data/blacklist/data.json create mode 100644 test/data/cell/consistency/data.json delete mode 100644 test/data/docs/data.json create mode 100644 test/data/monitor/data.json delete mode 100644 test/data/organization/data.json delete mode 100644 test/data/vehicle/data.json delete mode 100644 test/data/zone/data.json delete mode 100644 test/docker-compose.yml delete mode 100644 test/policies/abac/policy.rego rename test/policies/{example => access_method}/policy.rego (89%) delete mode 100644 test/policies/account/policy.rego delete mode 100644 test/policies/action/policy.rego create mode 100644 test/policies/blacklist/policy.rego create mode 100644 test/policies/cell/consistency/policy.rego create mode 100644 test/policies/cell/consistency/topology/policy.rego delete mode 100644 test/policies/data/abac/data.json delete mode 100644 test/policies/data/account/data.json delete mode 100644 test/policies/data/action/data.json delete mode 100644 test/policies/data/organization/data.json delete mode 100644 test/policies/data/role/data.json delete mode 100644 test/policies/docs/policy.rego create mode 100644 test/policies/monitor/policy.rego delete mode 100644 test/policies/organization/policy.rego delete mode 100644 test/policies/vehicle/policy.rego delete mode 100644 test/policies/zone/policy.rego delete mode 100644 test/policy-new.yaml delete mode 100755 test/scripts.sh delete mode 100644 test/scripts.txt delete mode 100644 test/test_resources/policy_collab.yaml delete mode 100644 test/test_resources/policy_conflict.yaml delete mode 100644 test/test_resources/policy_deploy_single_policy.yaml delete mode 100644 test/test_resources/policy_zone.yaml delete mode 100644 test/test_resources/undeploy_batch_delete.json rename test/{test_resources/deploy_collab.json => toscapolicies/access_method/deploy_access_method.json} (66%) create mode 100644 test/toscapolicies/access_method/policy_access_method.yaml rename test/{test_resources/deploy_conflict.json => toscapolicies/blacklist/deploy_blacklist.json} (68%) create mode 100644 test/toscapolicies/blacklist/policy_blacklist.yaml create mode 100644 test/toscapolicies/cell/deploy_cell.json create mode 100644 test/toscapolicies/cell/policy_cell.yaml rename test/{test_resources/deploy_zone.json => toscapolicies/monitor/deploy_monitor.json} (69%) create mode 100644 test/toscapolicies/monitor/policy_monitor.yaml rename test/{test_resources/deploy.json => toscapolicies/role/deploy_role.json} (100%) create mode 100644 test/toscapolicies/role/policy_role.yaml delete mode 100644 test/wait_for_port.sh diff --git a/README.md b/README.md index f9c7a2c..53a782e 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,50 @@ # Running docker policy-opa-pdp ## Building Docker Image. -docker build -f ./build/Dockerfile -t opa-pdp:1.0.0 . +docker build -t opa-pdp:1.0.0 . -## Running the containers and Testing - -1. docker image ls | grep opa-pdp - -2. inside test directory run - docker-compose down - -3. docker-compose up -d - -4. docker logs -f opa-pdp ## Generating models with openapi.yaml 1. oapi-codegen -package=oapicodegen -generate "models" openapi.yaml > models.go -## Creating new Policy -1. Create a new directory under test/polices. For example - role +## Creating New Policy -2. Inside this directory create a policy [i.e; rego file] named policy.rego. Version 1 i.e v1 is supported for rego files. - -3. For contents you can see example of policy.rego under test/policies/role/policy.rego. +1. Create a tosca policy file that has policy.rego and data.json encoded contents. -3. Inside test/policies/data create a new directory with the package name of policy.rego. For example test/policies/data/role +2. Ensure data key should have node as prefix. For example refer to test/test_resources/blacklist/policy_blacklist.yaml. -4. Create a file data.json under the newly created directory inside data. For example test/policies/data/data.json +3. OPA emphasizes that each policy should have a unique policy-name/policy-id, -5. In policy.rego the package declaration organizes the policy rules. This allows + example: + Not Allowed: + 1. If a policy named onap.org.cell is deployed, then deploying a policy named onap.org.cell.consistency is disallowed because it shares the same hierarchical structure. -6. The Rule allow evaluates to true/false based on the logic defined in policy.rego + 2. If a policy named onap.org.cell is deployed, then deploying a policy named onap.org is disallowed because it is parent directory. -7. Data.json is files is kept within the directory named after policy package name under data folders. For example policies/data/role/data.json. + Allowed: If a policy named onap.org.cell is deployed, then deploying a policy named onap.org.consistency is permitted, as it does not share the same hierarchy. -8. To reference the data inside policy.rego we need to define rule as data.folder-name.attribute. For example you can refer to policy.rego under rules, data.role.user_roles. -9. To deploy a new policy opa-pdp need to be redpolyed i.e; docker-compose down and up need to be executed. +4. Policy key should start (prefixed) with policy-id. For ex refer to test/test_resources/blacklist/policy_blacklist.yaml. -## Deploying New Policy +5. Create a deploy.json file to deploy through pap. Refer to file under test/test_resources/blacklist/deploy_blacklist.json. -1. Create a tosca policy file that has policy.rego and data.json encoded contents. +## Deploy Policy Using Docker Compose -2. For example refer to test/policy_deployment.yaml. +1. Ensure you have docker and docker-compose installed -3. OPA emphasizes that each policy should have a unique policy-name/policy-id, +2. Check out the policy/docker repo from the ONAP gerrit or from github: https://github.com/onap/policy-docker - example: - Not Allowed --> when policy with name onap.org.cell is deployed and when onap.org.cell.consistency not allowed for deployment since it carries the same hierarchy. - Allowed --> Policy with name onap.org.cell is deployed and when onap.org.consistency is allowed for deployment since it does not have the same hierarchy. +3. Latest Docker image created can be updated in compose.yml inside policy/docker repo. +4. Start opa-pdp containers by running the start-compose.sh script -4. Policy and data key should start (prefixed) with policy-id. For ex refer totest/testresources/policy_deploy_single_policy.yaml. +5. Command to start opa-pdp container ./start-compose.sh opa-pdp -5. Create a deploy.json file to deploy through pap. Refer to file under test/testresources/deploy.json. +6. Check the logs. docker logs -f policy-opa-pdp ## Testing Decision Api -send json -{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22 12:08:00.123456+0000 ", "policyName":"role/allow","input":{"user":"alice","action":"write","object":"id123","type":"dog"}} -to opa-pdp as shown in curl commands below. - -"policyName":"[packagename in rego file]/allow" - Policy to be refrenced as policyName:role/allow in case when policy's package name is role. Change it according to your package name of the policy. - -"input":{"user":"alice","action":"read","object":"id123","type":"dog"} - Input defines the specific data to be evaluated by the Rego policy - +To get opa Decision for the deployed policies please refer to test/README.md for the API details. diff --git a/cmd/opa-pdp/opa-pdp.go b/cmd/opa-pdp/opa-pdp.go index 3a8a52f..fa83cdc 100644 --- a/cmd/opa-pdp/opa-pdp.go +++ b/cmd/opa-pdp/opa-pdp.go @@ -164,7 +164,7 @@ func shutdownHTTPServer(server *http.Server) { } func waitForServer() { - time.Sleep(time.Duration(consts.SERVER_WAIT_UP_TIME) * time.Second) + time.Sleep(time.Duration(consts.ServerWaitUpTime) * time.Second) } func initializeOPA() error { @@ -232,6 +232,5 @@ myLoop: handler.SetShutdownFlag() - time.Sleep(time.Duration(consts.SHUTDOWN_WAIT_TIME) * time.Second) + time.Sleep(time.Duration(consts.ShutdownWaitTime) * time.Second) } - diff --git a/cmd/opa-pdp/opa-pdp_test.go b/cmd/opa-pdp/opa-pdp_test.go index bc3aba6..37f4314 100644 --- a/cmd/opa-pdp/opa-pdp_test.go +++ b/cmd/opa-pdp/opa-pdp_test.go @@ -20,9 +20,11 @@ package main import ( - "context" "errors" + "github.com/confluentinc/confluent-kafka-go/v2/kafka" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "net/http" "os" "policy-opa-pdp/consts" @@ -33,9 +35,6 @@ import ( "policy-opa-pdp/pkg/model" "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/confluentinc/confluent-kafka-go/v2/kafka" ) // Mock objects and functions @@ -57,24 +56,23 @@ func (m *MockKafkaConsumerInterface) ReadMessage(kc *kafkacomm.KafkaConsumer) ([ } type MockKafkaProducer struct { - mock.Mock + mock.Mock } func (m *MockKafkaProducer) Produce(message *kafka.Message, evenchan chan kafka.Event) error { - args := m.Called(message) - return args.Error(0) + args := m.Called(message) + return args.Error(0) } func (m *MockKafkaProducer) Close() { - m.Called() + m.Called() } func (m *MockKafkaProducer) Flush(timeout int) int { - m.Called(timeout) - return 0 + m.Called(timeout) + return 0 } - type MockPdpStatusSender struct { mock.Mock } @@ -101,7 +99,7 @@ func (m *MockServer) Shutdown() error { // Test to verify the application handles the shutdown process gracefully. func TestHandleShutdown(t *testing.T) { - consts.SHUTDOWN_WAIT_TIME = 0 + consts.ShutdownWaitTime = 0 mockConsumer := new(mocks.KafkaConsumerInterface) mockConsumer.On("Unsubscribe").Return(nil) mockConsumer.On("Close").Return(nil) @@ -111,15 +109,14 @@ func TestHandleShutdown(t *testing.T) { Consumer: mockConsumer, } // Create the mock producer - mockProducer := new(MockKafkaProducer) + mockProducer := new(MockKafkaProducer) - // Mock the Produce method to simulate success - mockProducer.On("Produce", mock.Anything).Return(nil) - //t.Fatalf("Inside Sender checking for producer , but got: %v", mockProducer) + // Mock the Produce method to simulate success + mockProducer.On("Produce", mock.Anything).Return(nil) + //t.Fatalf("Inside Sender checking for producer , but got: %v", mockProducer) - - // Create the RealPdpStatusSender with the mocked producer - kafkaProducer = &kafkacomm.KafkaProducer{} + // Create the RealPdpStatusSender with the mocked producer + kafkaProducer = &kafkacomm.KafkaProducer{} interruptChannel := make(chan os.Signal, 1) _, cancel := context.WithCancel(context.Background()) @@ -144,15 +141,16 @@ func TestHandleShutdown(t *testing.T) { } } -var testServer *http.Server +var testServer *http.Server var kafkaConsumer *kafkacomm.KafkaConsumer var kafkaProducer *kafkacomm.KafkaProducer + // Test the main function to ensure it's initialization, startup, and shutdown correctly. func SetupMocks() { // Mock dependencies and expected behavior - testServer = &http.Server{} - kafkaConsumer= &kafkacomm.KafkaConsumer{} - kafkaProducer= &kafkacomm.KafkaProducer{} + testServer = &http.Server{} + kafkaConsumer = &kafkacomm.KafkaConsumer{} + kafkaProducer = &kafkacomm.KafkaProducer{} // Mock initializeHandlers initializeHandlersFunc = func() { log.Debug("Handlers initialized") @@ -181,15 +179,14 @@ func SetupMocks() { return nil // no error expected } - registerPDPFunc = func(sender publisher.PdpStatusSender) bool { // Simulate the registration logic here - return false// Simulate successful registration + return false // Simulate successful registration } - handleMessagesFunc = func(ctx context.Context, kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) { - return - } + handleMessagesFunc = func(ctx context.Context, kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) { + return + } // Mock handleShutdown interruptChannel := make(chan os.Signal, 1) @@ -199,14 +196,13 @@ func SetupMocks() { } } -func TestKafkaConsumerInitializationFailure(t *testing.T){ - +func TestKafkaConsumerInitializationFailure(t *testing.T) { - SetupMocks() + SetupMocks() startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) { - return nil, nil, assert.AnError // return mocked consumer and producer - } + return nil, nil, assert.AnError // return mocked consumer and producer + } // Run main function in a goroutine done := make(chan struct{}) @@ -219,83 +215,54 @@ func TestKafkaConsumerInitializationFailure(t *testing.T){ interruptChannel := make(chan os.Signal, 1) interruptChannel <- os.Interrupt - // Wait for main to complete or timeout - select { - case <-done: - // Success, verify if mocks were called as expected - // mockServer.AssertCalled(t, "Shutdown") - case <-time.After(1 * time.Second): - // t.Error("main function timed out") - } - // Verify assertions assert.True(t, true, "main function executed successfully") } -func TestKafkaConsumerInitializationSuccess(t *testing.T){ - +func TestKafkaConsumerInitializationSuccess(t *testing.T) { - SetupMocks() + SetupMocks() - startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) { - return kafkaConsumer, kafkaProducer, nil // return mocked consumer and producer - } - - // Run main function in a goroutine - done := make(chan struct{}) - go func() { - main() - close(done) - }() + startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) { + return kafkaConsumer, kafkaProducer, nil // return mocked consumer and producer + } - // Simulate an interrupt to trigger shutdown - interruptChannel := make(chan os.Signal, 1) - interruptChannel <- os.Interrupt + // Run main function in a goroutine + done := make(chan struct{}) + go func() { + main() + close(done) + }() - // Wait for main to complete or timeout - select { - case <-done: - // Success, verify if mocks were called as expected - // mockServer.AssertCalled(t, "Shutdown") - case <-time.After(1 * time.Second): - // t.Error("main function timed out") - } + // Simulate an interrupt to trigger shutdown + interruptChannel := make(chan os.Signal, 1) + interruptChannel <- os.Interrupt - // Verify assertions - assert.True(t, true, "main function executed successfully") + // Verify assertions + assert.True(t, true, "main function executed successfully") } -func TestKafkaNilConsumerInitialization(t *testing.T){ - - - SetupMocks() +func TestKafkaNilConsumerInitialization(t *testing.T) { - startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) { - return nil, kafkaProducer, nil // return mocked consumer and producer - } + SetupMocks() - // Run main function in a goroutine - done := make(chan struct{}) - go func() { - main() - close(done) - }() + startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) { + return nil, kafkaProducer, nil // return mocked consumer and producer + } - // Simulate an interrupt to trigger shutdown - interruptChannel := make(chan os.Signal, 1) - interruptChannel <- os.Interrupt + // Run main function in a goroutine + done := make(chan struct{}) + go func() { + main() + close(done) + }() - // Wait for main to complete or timeout - select { - case <-done: - // Success, verify if mocks were called as expected - // mockServer.AssertCalled(t, "Shutdown") - case <-time.After(1 * time.Second): - // t.Error("main function timed out") - } + // Simulate an interrupt to trigger shutdown + interruptChannel := make(chan os.Signal, 1) + interruptChannel <- os.Interrupt - // Verify assertions - assert.True(t, true, "main function executed successfully") + // Verify assertions + assert.True(t, true, "main function executed successfully") } // Test to verify that the HTTP server starts successfully. @@ -311,8 +278,6 @@ func TestInitializeOPA(t *testing.T) { assert.Error(t, err, "Expected error from initializeOPA") } - - // Test to ensure the application correctly waits for the server to be ready. func TestWaitForServer(t *testing.T) { waitForServerFunc = func() { @@ -592,7 +557,6 @@ func TestStartKafkaProducerFailure(t *testing.T) { assert.Nil(t, consumer) assert.Nil(t, producer) - NewKafkaConsumer = originalNewKafkaConsumer GetKafkaProducer = originalGetKafkaProducer }) @@ -625,12 +589,12 @@ func TestStartKafkaAndProdSuccess(t *testing.T) { // Test to verify that the shutdown process handles a nil Kafka consumer gracefully func TestHandleShutdownWithNilConsumer(t *testing.T) { - consts.SHUTDOWN_WAIT_TIME = 0 + consts.ShutdownWaitTime = 0 interruptChannel := make(chan os.Signal, 1) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - kafkaProducer := &kafkacomm.KafkaProducer{} + kafkaProducer := &kafkacomm.KafkaProducer{} // Simulate sending an interrupt signal go func() { time.Sleep(500 * time.Millisecond) @@ -668,7 +632,7 @@ func TestHandleMessages_ErrorInPdpMessageHandler(t *testing.T) { } originalPdpMessageHandler := PdpMessageHandler - PdpMessageHandler = func(ctx context.Context, kc *kafkacomm.KafkaConsumer, topic string, p publisher.PdpStatusSender) error { + PdpMessageHandler = func(ctx context.Context, kc *kafkacomm.KafkaConsumer, topic string, p publisher.PdpStatusSender) error { return errors.New("simulated error in PdpMessageHandler") } diff --git a/consts/constants.go b/consts/constants.go index d800e0d..617d2df 100644 --- a/consts/constants.go +++ b/consts/constants.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telekom +// Copyright (C) 2024-2025: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ package consts // BuildBundle - The command to build the bundle. // Policies - The directory path for policies. // Data - The directory path for policy data. +// DataNode - The directory path for policy data with node. // Output - The output flag for bundle commands. // BundleTarGz - The name of the bundle tar.gz file. // BundleTarGzFile - The file path for the bundle tar.gz file. @@ -38,8 +39,8 @@ package consts // PdpType - The type of PDP. // ServerPort - The port on which the server listens. // SERVER_WAIT_UP_TIME - The time to wait for the server to be up, in seconds. -// SHUTDOWN_WAIT_TIME - The time to wait for the server to shut down, in seconds. -// V1_COMPATIBLE - The flag for v1 compatibility. +// ShutdownWaitTime - The time to wait for the server to shut down, in seconds. +// V1Compatible - The flag for v1 compatibility. // LatestVersion - The Version set in response for decision // MinorVersion - The Minor version set in response header for decision // PatchVersion - The Patch Version set in response header for decison @@ -47,6 +48,7 @@ package consts // HealtCheckStatus - The bool flag for Healthy field in HealtCheck response // OkCode - The Code for HealthCheck response // HealthCheckMessage - The Healtcheck Message +// SingleHierarchy - The Counter indicates the length of datakey path var ( LogFilePath = "/var/logs/logs.log" LogMaxSize = 10 @@ -56,6 +58,7 @@ var ( BuildBundle = "build" Policies = "/opt/policies" Data = "/opt/data" + DataNode = "/opt/data/node" Output = "-o" BundleTarGz = "bundle.tar.gz" BundleTarGzFile = "/app/bundles/bundle.tar.gz" @@ -63,9 +66,9 @@ var ( //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 - SHUTDOWN_WAIT_TIME = 5 - V1_COMPATIBLE = "--v1-compatible" + ServerWaitUpTime = 5 + ShutdownWaitTime = 5 + V1Compatible = "--v1-compatible" LatestVersion = "1.0.0" MinorVersion = "0" PatchVersion = "0" @@ -73,4 +76,5 @@ var ( HealtCheckStatus = true OkCode = int32(200) HealthCheckMessage = "alive" + SingleHierarchy = 4 ) diff --git a/pkg/data/data-handler.go b/pkg/data/data-handler.go index 69c0500..673f247 100644 --- a/pkg/data/data-handler.go +++ b/pkg/data/data-handler.go @@ -21,8 +21,10 @@ package data import ( "context" "encoding/json" + "fmt" "github.com/google/uuid" openapi_types "github.com/oapi-codegen/runtime/types" + "github.com/open-policy-agent/opa/storage" "net/http" "path/filepath" "policy-opa-pdp/consts" @@ -30,11 +32,9 @@ import ( "policy-opa-pdp/pkg/metrics" "policy-opa-pdp/pkg/model/oapicodegen" "policy-opa-pdp/pkg/opasdk" + "policy-opa-pdp/pkg/policymap" "policy-opa-pdp/pkg/utils" "strings" - - "github.com/open-policy-agent/opa/storage" - "policy-opa-pdp/pkg/policymap" ) var ( @@ -78,60 +78,30 @@ func createOPADataUpdateExceptionResponse(statusCode int, errorMessage string, p } } -// Validate OPADataUpdateRequest function -func validateOPADataUpdateRequest(request *oapicodegen.OPADataUpdateRequest) []string { - var validationErrors []string - - // Check if required fields are populated - dateString := (request.CurrentDate).String() - if !(utils.IsValidCurrentDate(&dateString)) { - validationErrors = append(validationErrors, "CurrentDate is required") - } - - // Validate CurrentDateTime format - if !(utils.IsValidTime(request.CurrentDateTime)) { - validationErrors = append(validationErrors, "CurrentDateTime is invalid or missing") - } - - // Validate CurrentTime format - if !(utils.IsValidCurrentTime(request.CurrentTime)) { - validationErrors = append(validationErrors, "CurrentTime is invalid or missing") - } - - // Validate Data field (ensure it's not nil and has items) - if !(utils.IsValidData(request.Data)) { - validationErrors = append(validationErrors, "Data is required and cannot be empty") - } - - // Validate TimeOffset format (e.g., +02:00 or -05:00) - if !(utils.IsValidTimeOffset(request.TimeOffset)) { - validationErrors = append(validationErrors, "TimeOffset is invalid or missing") - } - - // Validate TimeZone format (e.g., 'America/New_York') - if !(utils.IsValidTimeZone(request.TimeZone)) { - validationErrors = append(validationErrors, "TimeZone is invalid or missing") - } - - // Optionally, check if 'OnapComponent', 'OnapInstance', 'OnapName', and 'PolicyName' are provided - if !(utils.IsValidString(request.OnapComponent)) { - validationErrors = append(validationErrors, "OnapComponent is required") - } +type Policy struct { + Data []string `json:"data"` + Policy []string `json:"policy"` + PolicyID string `json:"policy-id"` + PolicyVersion string `json:"policy-version"` +} - if !(utils.IsValidString(request.OnapInstance)) { - validationErrors = append(validationErrors, "OnapInstance is required") +// Function to extract the policy by policyId +func getPolicyByID(policiesMap string, policyId string) (*Policy, error) { + var policies struct { + DeployedPolicies []Policy `json:"deployed_policies_dict"` } - if !(utils.IsValidString(request.OnapName)) { - validationErrors = append(validationErrors, "OnapName is required") + if err := json.Unmarshal([]byte(policiesMap), &policies); err != nil { + return nil, fmt.Errorf("failed to unmarshal policies: %v", err) } - if !(utils.IsValidString(request.PolicyName)) { - validationErrors = append(validationErrors, "PolicyName is required and cannot be empty") + for _, policy := range policies.DeployedPolicies { + if policy.PolicyID == policyId { + return &policy, nil + } } - // Return all validation errors (if any) - return validationErrors + return nil, fmt.Errorf("policy '%s' not found", policyId) } func patchHandler(res http.ResponseWriter, req *http.Request) { @@ -150,7 +120,12 @@ func patchHandler(res http.ResponseWriter, req *http.Request) { log.Infof("dataDir : %s", dataDir) // Validate the request - validationErrors := validateOPADataUpdateRequest(&requestBody) + validationErrors := utils.ValidateOPADataRequest(&requestBody) + + // Validate Data field (ensure it's not nil and has items) + if !(utils.IsValidData(requestBody.Data)) { + validationErrors = append(validationErrors, "Data is required and cannot be empty") + } // Print validation errors if len(validationErrors) > 0 { @@ -159,7 +134,7 @@ func patchHandler(res http.ResponseWriter, req *http.Request) { sendErrorResponse(res, errMsg, http.StatusBadRequest) return } else { - log.Errorf("All fields are valid!") + log.Debug("All fields are valid!") // Access the data part data := requestBody.Data log.Infof("data : %s", data) @@ -172,6 +147,42 @@ func patchHandler(res http.ResponseWriter, req *http.Request) { log.Errorf(errMsg) return } + + // Checking if the data operation is performed for a deployed policy with policymap.CheckIfPolicyAlreadyExists and getPolicyByID + // if a match is found, we will join the url path with dots and check for the data key from the policiesMap whether utl path is a + // prefix of data key. we will proceed for Patch Operation if this matches, else return error + if len(dirParts) > 0 && dirParts[0] == "" { + dirParts = dirParts[1:] + } + finalDirParts := strings.Join(dirParts, ".") + + policiesMap := policymap.LastDeployedPolicies + + matchedPolicy, err := getPolicyByID(policiesMap, *policyId) + if err != nil { + sendErrorResponse(res, err.Error(), http.StatusBadRequest) + log.Errorf(err.Error()) + return + } + + log.Infof("Matched policy: %+v", matchedPolicy) + + // Check if finalDirParts starts with any data key + matchFound := false + for _, dataKey := range matchedPolicy.Data { + if strings.HasPrefix(finalDirParts, dataKey) { + matchFound = true + break + } + } + + if !matchFound { + errMsg := fmt.Sprintf("Dynamic Data add/replace/remove for policy '%s' expected under url path '%v'", *policyId, matchedPolicy.Data) + sendErrorResponse(res, errMsg, http.StatusBadRequest) + log.Errorf(errMsg) + return + } + if err := patchData(dataDir, data, res); err != nil { // Handle the error, for example, log it or return an appropriate response log.Errorf("Error encoding JSON response: %s", err) @@ -215,7 +226,7 @@ func extractPatchInfo(res http.ResponseWriter, ops *[]map[string]interface{}, ro // PATCH request with add or replace opType, MUST contain a "value" member whose content specifies the value to be added / replaced. For remove opType, value does not required if optypeString == "add" || optypeString == "replace" { value, valueErr = op["value"] - if !valueErr { + if !valueErr || isEmpty(value) { valueErrMsg := "Error in getting data value. Value is not given in request body" sendErrorResponse(res, valueErrMsg, http.StatusInternalServerError) log.Errorf(valueErrMsg) @@ -225,7 +236,7 @@ func extractPatchInfo(res http.ResponseWriter, ops *[]map[string]interface{}, ro impl.Value = value opPath, opPathErr := op["path"].(string) - if !opPathErr { + if !opPathErr || len(opPath) == 0 { opPathErrMsg := "Error in getting data path. Path is not given in request body" sendErrorResponse(res, opPathErrMsg, http.StatusInternalServerError) log.Errorf(opPathErrMsg) @@ -243,6 +254,35 @@ func extractPatchInfo(res http.ResponseWriter, ops *[]map[string]interface{}, ro return result } +func isEmpty(data interface{}) bool { + if data == nil { + return true // Nil values are considered empty + } + + switch v := data.(type) { + case string: + return len(v) == 0 // Check if string is empty + case []interface{}: + return len(v) == 0 // Check if slice is empty + case map[string]interface{}: + return len(v) == 0 // Check if map is empty + case []byte: + return len(v) == 0 // Check if byte slice is empty + case int, int8, int16, int32, int64: + return v == 0 // Zero integers are considered empty + case uint, uint8, uint16, uint32, uint64: + return v == 0 // Zero unsigned integers are considered empty + case float32, float64: + return v == 0.0 // Zero floats are considered empty + case bool: + return !v // `false` is considered empty + case nil: + return true // Explicitly checking nil again + default: + return false // Other data types are not considered empty + } +} + func constructPath(opPath string, opType string, root string, res http.ResponseWriter) (storagePath storage.Path) { // Construct patch path. log.Debugf("root: %s", root) @@ -269,13 +309,10 @@ func constructPath(opPath string, opType string, root string, res http.ResponseW path = root + "/" + path } } else { - if opType == "remove" { - valueErrMsg := "Error in getting data path - Invalid path (/) is used." - sendErrorResponse(res, valueErrMsg, http.StatusInternalServerError) - log.Errorf(valueErrMsg) - return nil - } - path = root + valueErrMsg := "Error in getting data path - Invalid path (/) is used." + sendErrorResponse(res, valueErrMsg, http.StatusInternalServerError) + log.Errorf(valueErrMsg) + return nil } log.Infof("calling ParsePatchPathEscaped to check the path") diff --git a/pkg/data/data-handler_test.go b/pkg/data/data-handler_test.go index 41be361..e8dcb17 100644 --- a/pkg/data/data-handler_test.go +++ b/pkg/data/data-handler_test.go @@ -56,56 +56,6 @@ func TestGetErrorResponseCodeForOPADataUpdate(t *testing.T) { } } -func TestValidateOPADataUpdateRequest(t *testing.T) { - ctime := "12:00:00" - timeZone := "America_New_York" - timeOffset := "$02:00" - onapComp := " " - onapIns := " " - onapName := " " - policyName := " " - var currentDate openapi_types.Date - currentDate = openapi_types.Date{} - var currentDateTime time.Time - currentDateTime = time.Time{} - - var data []map[string]interface{} - - data = nil - - inValidRequest := &oapicodegen.OPADataUpdateRequest{ - CurrentDate: ¤tDate, - CurrentDateTime: ¤tDateTime, - CurrentTime: &ctime, - TimeOffset: &timeOffset, - TimeZone: &timeZone, - OnapComponent: &onapComp, - OnapInstance: &onapIns, - OnapName: &onapName, - PolicyName: &policyName, - Data: &data, - } - - inValidErr := []string{"CurrentTime is invalid or missing", "Data is required and cannot be empty", "TimeOffset is invalid or missing", "TimeZone is invalid or missing", "OnapComponent is required", "OnapInstance is required", "OnapName is required", "PolicyName is required and cannot be empty"} - - tests := []struct { - name string - request *oapicodegen.OPADataUpdateRequest - expectedErr []string - }{ - {"Valid Request", inValidRequest, inValidErr}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - errors := validateOPADataUpdateRequest(tt.request) - fmt.Printf("error : %s", errors) - fmt.Printf("error len : %d", len(errors)) - assert.Equal(t, tt.expectedErr, errors) - }) - } -} - func TestPatchHandler_InvalidJSON(t *testing.T) { req := httptest.NewRequest("PATCH", "/policy/pdpo/v1/data/", bytes.NewBuffer([]byte("{invalid_json}"))) res := httptest.NewRecorder() diff --git a/pkg/decision/decision-provider.go b/pkg/decision/decision-provider.go index 463f731..2f56a5b 100644 --- a/pkg/decision/decision-provider.go +++ b/pkg/decision/decision-provider.go @@ -38,6 +38,7 @@ import ( "policy-opa-pdp/pkg/pdpstate" "policy-opa-pdp/pkg/policymap" "policy-opa-pdp/pkg/utils" + "sort" "strings" ) @@ -77,8 +78,8 @@ func writeErrorJSONResponse(res http.ResponseWriter, status int, errorDescriptio // creates a success decision response func createSuccessDecisionResponse(policyName string, output map[string]interface{}) *oapicodegen.OPADecisionResponse { return &oapicodegen.OPADecisionResponse{ - PolicyName: policyName, - Output: output, + PolicyName: policyName, + Output: output, } } @@ -135,17 +136,21 @@ func handleDecisionRequest(res http.ResponseWriter, req *http.Request, errorDtls return } - if decisionReq.PolicyName == "" { - *errorDtls = "Policy Name is nil which is invalid." - *httpStatus = http.StatusBadRequest - return - } + // Validate the request body + validationErrors := utils.ValidateOPADataRequest(decisionReq) if decisionReq.PolicyFilter == nil || len(decisionReq.PolicyFilter) == 0 { - *errorDtls = "Policy Filter is nil." + validationErrors = append(validationErrors, "PolicyFilter is required and cannot be empty") + } + if len(validationErrors) > 0 { + *errorDtls = strings.Join(validationErrors, ", ") + log.Errorf("Facing validation error in requestbody - %s", *errorDtls) *httpStatus = http.StatusBadRequest return } + log.Debugf("Validation successful for request fields") + // If validation passes, handle the decision request + decisionReq.PolicyName = strings.ReplaceAll(decisionReq.PolicyName, ".", "/") handlePolicyValidation(res, decisionReq, errorDtls, httpStatus, policyId) } @@ -195,7 +200,7 @@ func policyExists(policyName string, extractedPolicies []model.ToscaConceptIdent return false } -//This function processes the request headers +// This function processes the request headers func processRequestHeaders(req *http.Request, res http.ResponseWriter) (string, *oapicodegen.DecisionParams) { requestId := req.Header.Get("X-ONAP-RequestID") var parsedUUID *uuid.UUID @@ -229,7 +234,7 @@ func isSystemActive() bool { return pdpstate.GetCurrentState() == model.Active } -//This method parses the body and checks whether it is properly formatted JSON or not +// This method parses the body and checks whether it is properly formatted JSON or not func parseRequestBody(req *http.Request) (*oapicodegen.OPADecisionRequest, error) { var decisionReq oapicodegen.OPADecisionRequest if err := json.NewDecoder(req.Body).Decode(&decisionReq); err != nil { @@ -238,7 +243,7 @@ func parseRequestBody(req *http.Request) (*oapicodegen.OPADecisionRequest, error return &decisionReq, nil } -//This function sends the error response +// This function sends the error response func sendDecisionErrorResponse(msg string, res http.ResponseWriter, httpStatus int, policyName string) { log.Warnf("%s", msg) decisionExc := createDecisionExceptionResponse(httpStatus, msg, policyName) @@ -247,34 +252,33 @@ func sendDecisionErrorResponse(msg string, res http.ResponseWriter, httpStatus i writeErrorJSONResponse(res, httpStatus, msg, *decisionExc) } - type OPASingletonInstanceFunc func() (*sdk.OPA, error) + var OPASingletonInstance OPASingletonInstanceFunc = opasdk.GetOPASingletonInstance -//This function returns the opasdk instance +// This function returns the opasdk instance func getOpaInstance() (*sdk.OPA, error) { return OPASingletonInstance() } - - type OPADecisionFunc func(opa *sdk.OPA, ctx context.Context, options sdk.DecisionOptions) (*sdk.DecisionResult, error) + var OPADecision OPADecisionFunc = (*sdk.OPA).Decision -//This function processes the OPA decision +// This function processes the OPA decision func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapicodegen.OPADecisionRequest) { ctx := context.Background() log.Debugf("SDK making a decision") - var decisionRes *oapicodegen.OPADecisionResponse + var decisionRes *oapicodegen.OPADecisionResponse //OPA is seding success with a warning message if "input" parameter is missing, so we need to send success response inputBytes, err := json.Marshal(decisionReq.Input) - if err != nil{ - log.Warnf("Failed to unmarshal decision Request Input: %vg", err) - return - } - if inputBytes == nil || len(inputBytes) == 0 { - statusMessage := "{\"warning\":{\"code\":\"api_usage_warning\",\"message\":\"'input' key missing from the request\"}}" - decisionRes = createSuccessDecisionResponseWithStatus(decisionReq.PolicyName, nil, statusMessage) + if err != nil { + log.Warnf("Failed to unmarshal decision Request Input: %vg", err) + return + } + if inputBytes == nil || len(inputBytes) == 0 { + statusMessage := "{\"warning\":{\"code\":\"api_usage_warning\",\"message\":\"'input' key missing from the request\"}}" + decisionRes = createSuccessDecisionResponseWithStatus(decisionReq.PolicyName, nil, statusMessage) } else { options := sdk.DecisionOptions{Path: decisionReq.PolicyName, Input: decisionReq.Input} decisionResult, decisionErr := OPADecision(opa, ctx, options) @@ -285,20 +289,22 @@ func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapi } log.Debugf("RAW opa Decision output:\n%s\n", string(jsonOutput)) + //while making decision . is replaced by /. reverting back. + decisionReq.PolicyName = strings.ReplaceAll(decisionReq.PolicyName, "/", ".") + if decisionErr != nil { - handleOpaDecisionError(res, decisionErr, decisionReq.PolicyName) + sendDecisionErrorResponse(decisionErr.Error(), res, http.StatusInternalServerError, decisionReq.PolicyName) return } - var policyFilter []string if decisionReq.PolicyFilter != nil { policyFilter = decisionReq.PolicyFilter } result, _ := decisionResult.Result.(map[string]interface{}) - outputMap, unmatchedFilters := processPolicyFilter(result, policyFilter) + outputMap, unmatchedFilters, validPolicyFilters := processPolicyFilter(result, policyFilter) if len(unmatchedFilters) > 0 { - message := fmt.Sprintf("Policy Filter(s) not matching: [%s]", strings.Join(unmatchedFilters, ", ")) + message := fmt.Sprintf("Policy Filter(s) not matching, Valid Filter(s) are: [%s]", strings.Join(validPolicyFilters, ", ")) decisionRes = createSuccessDecisionResponseWithStatus(decisionReq.PolicyName, outputMap, message) } else { decisionRes = createSuccessDecisionResponse(decisionReq.PolicyName, outputMap) @@ -308,52 +314,73 @@ func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapi writeOpaJSONResponse(res, http.StatusOK, *decisionRes) } -//This function validates the errors during decision process -func handleOpaDecisionError(res http.ResponseWriter, err error, policyName string) { - //As per the opa documentation in https://www.openpolicyagent.org/docs/latest/rest-api/#get-a-document-with-input - //when the path refers to an undefined document it will return 200 with no result. - //opasdk is returning opa_undefined_error for such case, so need to give sucess for such case and - //for other cases we have to send error response - if strings.Contains(err.Error(), string(oapicodegen.OpaUndefinedError)) { - decisionExc := createSuccessDecisionResponse(policyName, nil) - metrics.IncrementDecisionSuccessCount() - writeOpaJSONResponse(res, http.StatusOK, *decisionExc) - } else { - sendDecisionErrorResponse(err.Error(), res, http.StatusInternalServerError, policyName) - } -} - -//This function processes the policy filters -func processPolicyFilter(result map[string]interface{}, policyFilter []string) (map[string]interface{}, []string) { +// This function processes the policy filters +func processPolicyFilter(result map[string]interface{}, policyFilter []string) (map[string]interface{}, []string, []string) { if len(policyFilter) > 0 { - filteredResult, unmatchedFilters := applyPolicyFilter(result, policyFilter) + filteredResult, unmatchedFilters, validfilters := applyPolicyFilter(result, policyFilter) if len(filteredResult) > 0 { - return filteredResult, unmatchedFilters + return filteredResult, unmatchedFilters, validfilters } } - return nil, policyFilter + return nil, policyFilter, getValidPolicyFilters(result) } -// Function to apply policy filter to decision result -func applyPolicyFilter(result map[string]interface{}, filters []string) (map[string]interface{}, []string) { +// Get Valid Filters and collects unmatched filters +func applyPolicyFilter(result map[string]interface{}, filters []string) (map[string]interface{}, []string, []string) { filteredOutput := make(map[string]interface{}) - unmatchedFilters := make(map[string]struct{}) + unmatchedFilters := []string{} + + validFilters := getValidPolicyFilters(result) for _, filter := range filters { - unmatchedFilters[filter] = struct{}{} + // Try to find the value in the result map + if value := findNestedValue(result, strings.Split(filter, "/")); value != nil { + filteredOutput[filter] = value // Store using full path + } else if value, exists := result[filter]; exists { + // Allow direct key match (for non-nested filters) + filteredOutput[filter] = value + } else { + unmatchedFilters = append(unmatchedFilters, filter) // Collect unmatched filters + } } - for key, value := range result { - for _, filter := range filters { - if (key == filter || strings.TrimSpace(filter) == "") { - filteredOutput[key] = value - delete(unmatchedFilters, filter) - } - } + + return filteredOutput, unmatchedFilters, validFilters +} + +// handles the nested Policy Filters available when multiple rego files are included. +func findNestedValue(opaSdkResult map[string]interface{}, keys []string) interface{} { + if len(keys) == 0 { + return nil } + currentMap := opaSdkResult - unmatchedList := make([]string, 0, len(unmatchedFilters)) - for filter := range unmatchedFilters { - unmatchedList = append(unmatchedList, filter) + for _, key := range keys { + value, exists := currentMap[key] + if !exists { + return nil // Key doesn't exist + } + + // If it's a nested map, continue traversal + if nextNestedMap, ok := value.(map[string]interface{}); ok { + currentMap = nextNestedMap + } else { + return value // Return final value (non-map) + } } + return currentMap +} - return filteredOutput, unmatchedList +// returns the valid Policy Filters available +func getValidPolicyFilters(opaSdkResult map[string]interface{}) []string { + keys := make([]string, 0) + + for k, v := range opaSdkResult { + keys = append(keys, k) + if nestedMap, ok := v.(map[string]interface{}); ok { + for nestedKey := range nestedMap { + keys = append(keys, k+"/"+nestedKey) + } + } + } + sort.Strings(keys) + return keys } diff --git a/pkg/decision/decision-provider_test.go b/pkg/decision/decision-provider_test.go index aac543b..8610d4b 100644 --- a/pkg/decision/decision-provider_test.go +++ b/pkg/decision/decision-provider_test.go @@ -25,7 +25,9 @@ import ( "encoding/json" "errors" "fmt" + openapi_types "github.com/oapi-codegen/runtime/types" "github.com/open-policy-agent/opa/sdk" + "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "os" @@ -35,10 +37,10 @@ import ( "policy-opa-pdp/pkg/pdpstate" "policy-opa-pdp/pkg/policymap" "testing" - "github.com/stretchr/testify/assert" + "time" ) -//Test for Invalid request method +// Test for Invalid request method func TestOpaDecision_MethodNotAllowed(t *testing.T) { originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { @@ -54,7 +56,7 @@ func TestOpaDecision_MethodNotAllowed(t *testing.T) { assert.Contains(t, rec.Body.String(), "MethodNotAllowed") } -//Test for invalid JSON request +// Test for invalid JSON request func TestOpaDecision_InvalidJSON(t *testing.T) { originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { @@ -69,53 +71,135 @@ func TestOpaDecision_InvalidJSON(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rec.Code) } -//Test for Missing Policy +// Test for Missing Policy func TestOpaDecision_MissingPolicyPath(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyFilter := []string{"filter1", "filter2"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - body := map[string]interface{}{"onapName": "CDS", "onapComponent": "CDS", "onapInstance": "CDS", "requestId": "8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1", "input": nil} - jsonBody, _ := json.Marshal(body) + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyFilter: policyFilter, + } + + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody)) rec := httptest.NewRecorder() OpaDecision(rec, req) assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.Contains(t, rec.Body.String(), "Policy Name is nil which is invalid") + assert.Contains(t, rec.Body.String(), "PolicyName is required and cannot be empty") } -//Test for Missing Policy Filter +// Test for Missing Policy Filter func TestOpaDecision_MissingPolicyFilter(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "ONAP" + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - body := map[string]interface{}{"onapName": "CDS", "policyName": "datapolicy", "onapComponent": "CDS", "onapInstance": "CDS", "requestId": "8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1", "input": nil} - - jsonBody, _ := json.Marshal(body) + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + } + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody)) rec := httptest.NewRecorder() OpaDecision(rec, req) assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.Contains(t, rec.Body.String(), "Policy Filter is nil") + assert.Contains(t, rec.Body.String(), "PolicyFilter is required and cannot be empty") } -//Test for OPA Instance Error +// Test for OPA Instance Error func TestOpaDecision_GetInstanceError(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "data.policy" + policyFilter := []string{"filter1", "filter2"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - body := map[string]interface{}{"policy": "data.policy"} - jsonBody, _ := json.Marshal(body) + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody)) rec := httptest.NewRecorder() @@ -124,15 +208,44 @@ func TestOpaDecision_GetInstanceError(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rec.Code) } -//Test for OPA decision Error +// Test for OPA decision Error func TestOpaDecision_OPADecisionError(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "data.policy" + policyFilter := []string{"filter1", "filter2"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - body := map[string]interface{}{"policy": "data.policy"} - jsonBody, _ := json.Marshal(body) + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody)) rec := httptest.NewRecorder() @@ -149,7 +262,7 @@ func TestOpaDecision_OPADecisionError(t *testing.T) { assert.Equal(t, http.StatusBadRequest, rec.Code) } -//Test for system in passive State +// Test for system in passive State func TestOpaDecision_PassiveState(t *testing.T) { originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { @@ -174,6 +287,7 @@ func ptrString(s string) string { func ptrStringEx(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 @@ -184,8 +298,8 @@ func TestWriteOpaJSONResponse(t *testing.T) { rec := httptest.NewRecorder() data := &oapicodegen.OPADecisionResponse{ - PolicyName: ptrString("test-policy"), - Output: ptrMap(map[string]interface{}{"key": "value"}), + PolicyName: ptrString("test-policy"), + Output: ptrMap(map[string]interface{}{"key": "value"}), } writeOpaJSONResponse(rec, http.StatusOK, *data) @@ -194,7 +308,7 @@ func TestWriteOpaJSONResponse(t *testing.T) { assert.Contains(t, rec.Body.String(), `"policyName":"test-policy"`) } -//Test for JSON response error +// Test for JSON response error func TestWriteErrorJSONResponse(t *testing.T) { rec := httptest.NewRecorder() @@ -209,7 +323,7 @@ func TestWriteErrorJSONResponse(t *testing.T) { assert.Contains(t, rec.Body.String(), `"errorMessage":"Bad Request"`) } -//Test for Success Decision Response +// Test for Success Decision Response func TestCreateSuccessDecisionResponse(t *testing.T) { // Input values for creating the response policyName := "policy-name" @@ -217,7 +331,7 @@ func TestCreateSuccessDecisionResponse(t *testing.T) { // Call the createSuccessDecisionResponse function response := createSuccessDecisionResponse( - policyName, output) + policyName, output) // Assertions @@ -228,21 +342,21 @@ func TestCreateSuccessDecisionResponse(t *testing.T) { assert.Equal(t, response.Output, output, "Output should match") } -//Test for policy filter +// Test for policy filter 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) + result, _, _ := applyPolicyFilter(originalPolicy, filter) assert.NotNil(t, result) assert.Len(t, result, 1) assert.Contains(t, result, "policy1") } -//Test for Opa response error +// Test for Opa response error func TestWriteOpaJSONResponse_Error(t *testing.T) { rec := httptest.NewRecorder() @@ -252,8 +366,8 @@ func TestWriteOpaJSONResponse_Error(t *testing.T) { // Create a response object for error scenario data := &oapicodegen.OPADecisionResponse{ - PolicyName: ptrString(policyName), - Output: ptrMap(output), + PolicyName: ptrString(policyName), + Output: ptrMap(output), } writeOpaJSONResponse(rec, http.StatusBadRequest, *data) @@ -264,12 +378,12 @@ func TestWriteOpaJSONResponse_Error(t *testing.T) { assert.Contains(t, rec.Body.String(), `"errorDetail":"Invalid input"`, "Response should contain the error detail") } -//Test for JSON response success +// Test for JSON response success func TestWriteOpaJSONResponse_Success(t *testing.T) { // Prepare test data decisionRes := oapicodegen.OPADecisionResponse{ - PolicyName: ptrString("TestPolicy"), - Output: map[string]interface{}{"key": "value"}, + PolicyName: ptrString("TestPolicy"), + Output: map[string]interface{}{"key": "value"}, } // Create a mock HTTP response writer @@ -297,8 +411,8 @@ func TestWriteOpaJSONResponse_Success(t *testing.T) { // Test for JSON encoding errors func TestWriteOpaJSONResponse_EncodingError(t *testing.T) { - // Prepare invalid test data to trigger JSON encoding error - decisionRes := oapicodegen.OPADecisionResponse { + // 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)}, } @@ -321,6 +435,7 @@ func TestWriteOpaJSONResponse_EncodingError(t *testing.T) { } // Mocks for test cases +//var GetOPASingletonInstance = opasdk.GetOPASingletonInstance var mockDecisionResult = &sdk.DecisionResult{ Result: map[string]interface{}{ @@ -352,12 +467,12 @@ var mockDecisionReq3 = oapicodegen.OPADecisionRequest{ PolicyName: ptrString("opa/mockPolicy"), PolicyFilter: []string{"allow", "filter2"}, } + // Test to check invalid UUID in request func Test_Invalid_request_UUID(t *testing.T) { policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}` - originalFunc := OPASingletonInstance // Mock the function OPASingletonInstance = func() (*sdk.OPA, error) { @@ -368,7 +483,7 @@ func Test_Invalid_request_UUID(t *testing.T) { jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}` var decisionReq oapicodegen.OPADecisionRequest json.Unmarshal([]byte(jsonString), &decisionReq) - body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,} + body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter} jsonBody, _ := json.Marshal(body) req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) req.Header.Set("X-ONAP-RequestID", "invalid-uuid") @@ -399,23 +514,50 @@ func Test_passive_system_state(t *testing.T) { // Test for valid HTTP Method (POST) func Test_valid_HTTP_method(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "s3" + policyFilter := []string{"allow"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}` + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } originalOPADecision := OPADecision OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { - return mockDecisionResult, nil + return mockDecisionResult, nil } defer func() { OPADecision = originalOPADecision }() - policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}` - originalFunc := OPASingletonInstance // Mock the function OPASingletonInstance = func() (*sdk.OPA, error) { @@ -423,10 +565,7 @@ func Test_valid_HTTP_method(t *testing.T) { } defer func() { OPASingletonInstance = originalFunc }() - var decisionReq oapicodegen.OPADecisionRequest - json.Unmarshal([]byte(jsonString), &decisionReq) - body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,} - jsonBody, _ := json.Marshal(body) + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) res := httptest.NewRecorder() OpaDecision(res, req) @@ -436,22 +575,49 @@ func Test_valid_HTTP_method(t *testing.T) { // Test for Marshalling error in Decision Result func Test_Error_Marshalling(t *testing.T) { + + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "s3" + policyFilter := []string{"allow"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}` + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + originalOPADecision := OPADecision OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { - mockDecisionResult := &sdk.DecisionResult{ - Result: map[string]interface{}{ - "key": make(chan int), - }, - } return mockDecisionResult, nil } defer func() { OPADecision = originalOPADecision }() + policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}` originalFunc := OPASingletonInstance @@ -461,10 +627,7 @@ func Test_Error_Marshalling(t *testing.T) { } defer func() { OPASingletonInstance = originalFunc }() - var decisionReq oapicodegen.OPADecisionRequest - json.Unmarshal([]byte(jsonString), &decisionReq) - body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,} - jsonBody, _ := json.Marshal(body) + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) res := httptest.NewRecorder() @@ -472,52 +635,110 @@ func Test_Error_Marshalling(t *testing.T) { assert.Equal(t, http.StatusOK, res.Code) } - func mockGetOpaInstance() (*sdk.OPA, error) { // Return a mock OPA instance instead of reading from a file return &sdk.OPA{}, nil } + // Test for Invalid Decision error in Decision Result func Test_Invalid_Decision(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "s3" + policyFilter := []string{"allow"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - // Define a request body that matches expected input format - jsonString := `{ - "policyName": "s3", - "policyFilter": ["allow"], - "input": {"content": "content"} - }` + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + + originalOPADecision := OPADecision + OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { + return nil, fmt.Errorf("opa_undefined_error") + } + defer func() { OPADecision = originalOPADecision }() + + policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}` + originalFunc := OPASingletonInstance // Mock the function OPASingletonInstance = func() (*sdk.OPA, error) { return &sdk.OPA{}, nil // Mocked OPA instance } defer func() { OPASingletonInstance = originalFunc }() - - // Patch the OPA Decision method to return an error - originalOPADecision := OPADecision - OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { - return nil, fmt.Errorf("opa_undefined_error") - } - defer func() { OPADecision = originalOPADecision }() - + + jsonBody, _ := json.Marshal(validRequest) // Create a test HTTP request - req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer([]byte(jsonString))) + req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) req.Header.Set("Content-Type", "application/json") res := httptest.NewRecorder() // Call the handler function that processes OPA decision OpaDecision(res, req) // Assert that the response status code is 200 - assert.Equal(t, 200, res.Code) + assert.Equal(t, 500, res.Code) } // Test for Invalid Decision error in Decision Result func Test_Valid_Decision_String(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "s3" + policyFilter := []string{"allow"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + // Mock PDP state originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { @@ -525,17 +746,11 @@ func Test_Valid_Decision_String(t *testing.T) { } defer func() { pdpstate.GetCurrentState = originalGetState }() - jsonString := `{ - "policyName": "s3", - "policyFilter": ["allow"], - "input": {"content": "content"} - }` - // Patch the OPA Decision method to return an error originalOPADecision := OPADecision OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { // Return an explicit error - mockDecisionResult := &sdk.DecisionResult{ + mockDecisionResult := &sdk.DecisionResult{ Result: map[string]interface{}{ "allowed": "true", }, @@ -543,7 +758,7 @@ func Test_Valid_Decision_String(t *testing.T) { return mockDecisionResult, nil } defer func() { OPADecision = originalOPADecision }() - + policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}` originalFunc := OPASingletonInstance @@ -552,9 +767,10 @@ func Test_Valid_Decision_String(t *testing.T) { return &sdk.OPA{}, nil // Mocked OPA instance } defer func() { OPASingletonInstance = originalFunc }() - + + jsonBody, _ := json.Marshal(validRequest) // Create a test HTTP request - req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer([]byte(jsonString))) + req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) req.Header.Set("Content-Type", "application/json") res := httptest.NewRecorder() @@ -567,19 +783,49 @@ func Test_Valid_Decision_String(t *testing.T) { // Test with OPA Decision of boolean type true func Test_with_boolean_OPA_Decision(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "s3" + policyFilter := []string{"allow"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}` originalOPADecision := OPADecision OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { - return mockDecisionResultBool, nil + return mockDecisionResultBool, nil } defer func() { OPADecision = originalOPADecision }() - + policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}` originalFunc := OPASingletonInstance @@ -588,10 +834,7 @@ func Test_with_boolean_OPA_Decision(t *testing.T) { return &sdk.OPA{}, nil // Mocked OPA instance } defer func() { OPASingletonInstance = originalFunc }() - var decisionReq oapicodegen.OPADecisionRequest - json.Unmarshal([]byte(jsonString), &decisionReq) - body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,} - jsonBody, _ := json.Marshal(body) + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) res := httptest.NewRecorder() OpaDecision(res, req) @@ -599,15 +842,44 @@ func Test_with_boolean_OPA_Decision(t *testing.T) { assert.Equal(t, http.StatusOK, res.Code) } - // Test with OPA Decision with String type func Test_decision_Result_String(t *testing.T) { + ctime := "08:26:41.857Z" + timeZone := "America/New_York" + timeOffset := "+02:00" + onapComp := "COMPONENT" + onapIns := "INSTANCE" + onapName := "ONAP" + policyName := "s3" + policyFilter := []string{"allow"} + parsedDate, err := time.Parse("2006-01-02", "2024-02-12") + if err != nil { + fmt.Println("error in parsedDate") + } + currentDate := openapi_types.Date{Time: parsedDate} + currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z") + if err != nil { + fmt.Println("error in currentDateTime") + } + + validRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: policyName, + PolicyFilter: policyFilter, + } + originalGetState := pdpstate.GetCurrentState pdpstate.GetCurrentState = func() model.PdpState { return model.Active } defer func() { pdpstate.GetCurrentState = originalGetState }() - jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allowed"],"input":{"content" : "content"}}` originalOPADecision := OPADecision OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) { @@ -627,11 +899,8 @@ func Test_decision_Result_String(t *testing.T) { return &sdk.OPA{}, nil // Mocked OPA instance } defer func() { OPASingletonInstance = originalFunc }() - - var decisionReq oapicodegen.OPADecisionRequest - json.Unmarshal([]byte(jsonString), &decisionReq) - body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,} - jsonBody, _ := json.Marshal(body) + + jsonBody, _ := json.Marshal(validRequest) req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody)) res := httptest.NewRecorder() @@ -640,8 +909,6 @@ func Test_decision_Result_String(t *testing.T) { assert.Equal(t, http.StatusOK, res.Code) } - - var mockPoliciesMap string func mockLastDeployedPolicies() { @@ -701,7 +968,4 @@ func TestHandlePolicyValidation_OPAInstanceFailure(t *testing.T) { defer func() { OPASingletonInstance = originalFunc }() handlePolicyValidation(res, req, &errorDtls, &httpStatus, &policyId) - - assert.Equal(t, http.StatusInternalServerError, httpStatus) } - diff --git a/pkg/kafkacomm/handler/pdp_update_deploy_policy.go b/pkg/kafkacomm/handler/pdp_update_deploy_policy.go index b7b9901..6f073d5 100644 --- a/pkg/kafkacomm/handler/pdp_update_deploy_policy.go +++ b/pkg/kafkacomm/handler/pdp_update_deploy_policy.go @@ -36,6 +36,7 @@ import ( "policy-opa-pdp/pkg/opasdk" "policy-opa-pdp/pkg/policymap" "policy-opa-pdp/pkg/utils" + "sort" "strings" ) @@ -228,7 +229,7 @@ func getDirName(policy model.ToscaPolicy) []string { for key, _ := range policy.Properties.Data { - dirNames = append(dirNames, strings.ReplaceAll(consts.Data+"/"+key, ".", "/")) + dirNames = append(dirNames, strings.ReplaceAll(consts.DataNode+key, ".", "/")) } for key, _ := range policy.Properties.Policy { @@ -258,13 +259,14 @@ func upsertPolicy(policy model.ToscaPolicy) error { // handles writing data to sdk. func upsertData(policy model.ToscaPolicy) error { decodedDataContent, dataKeys, _ := extractAndDecodeDataVar(policy) + sort.Sort(utils.ByDotCount{Keys: dataKeys, Ascend: true}) for _, dataKey := range dataKeys { dataContent := decodedDataContent[dataKey] reader := bytes.NewReader([]byte(dataContent)) decoder := json.NewDecoder(reader) decoder.UseNumber() - var wdata map[string]interface{} + var wdata interface{} err := decoder.Decode(&wdata) if err != nil { log.Errorf("Failed to Insert Data: %s: %v", policy.Name, err) @@ -365,7 +367,7 @@ func checkIfPolicyAlreadyDeployed(pdpUpdate model.PdpUpdate) []model.ToscaPolicy // verfies policy by creating bundle. func verifyPolicyByBundleCreation(policy model.ToscaPolicy) error { // get directory name - dirNames := []string{strings.ReplaceAll(consts.Data+"/"+policy.Name, ".", "/"), strings.ReplaceAll(consts.Policies+"/"+policy.Name, ".", "/")} + dirNames := []string{strings.ReplaceAll(consts.DataNode+"/"+policy.Name, ".", "/"), strings.ReplaceAll(consts.Policies+"/"+policy.Name, ".", "/")} // create bundle output, err := createBundleFuncVar(exec.Command, policy) if err != nil { diff --git a/pkg/kafkacomm/handler/pdp_update_undeploy_policy.go b/pkg/kafkacomm/handler/pdp_update_undeploy_policy.go index b714ec6..4e72619 100644 --- a/pkg/kafkacomm/handler/pdp_update_undeploy_policy.go +++ b/pkg/kafkacomm/handler/pdp_update_undeploy_policy.go @@ -21,6 +21,7 @@ package handler import ( "context" + "encoding/json" "fmt" "path/filepath" "policy-opa-pdp/consts" @@ -28,14 +29,17 @@ import ( "policy-opa-pdp/pkg/log" "policy-opa-pdp/pkg/metrics" "policy-opa-pdp/pkg/model" + "policy-opa-pdp/pkg/model/oapicodegen" "policy-opa-pdp/pkg/opasdk" "policy-opa-pdp/pkg/policymap" "policy-opa-pdp/pkg/utils" + "sort" "strings" ) type ( HandlePolicyUndeploymentFunc func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) + opasdkGetDataFunc func(ctx context.Context, dataPath string) (data *oapicodegen.OPADataResponse_Data, err error) ) var ( @@ -47,6 +51,8 @@ var ( deletePolicySdkFunc = opasdk.DeletePolicy + opasdkGetData opasdkGetDataFunc = opasdk.GetDataInfo + removeDataDirectoryFunc = removeDataDirectory removePolicyDirectoryFunc = removePolicyDirectory @@ -144,11 +150,29 @@ func removeDataFromSdkandDir(policy map[string]interface{}) []string { var failureMessages []string if dataKeys, ok := policy["data"].([]interface{}); ok { + var dataKeysSlice []string for _, dataKey := range dataKeys { - keyPath := dataKey.(string) + if strKey, ok := dataKey.(string); ok { + dataKeysSlice = append(dataKeysSlice, strKey) + } else { + failureMessages = append(failureMessages, fmt.Sprintf("Invalid Key :%s", dataKey)) + } + } + sort.Sort(utils.ByDotCount{Keys: dataKeysSlice, Ascend: false}) + + for _, keyPath := range dataKeysSlice { keyPath = "/" + strings.Replace(keyPath, ".", "/", -1) log.Debugf("Deleting data from OPA : %s", keyPath) - if err := deleteDataSdkFunc(context.Background(), keyPath); err != nil { + // Prepare to handle any errors + var err error + var dataPath string + // Fetch data first + // Call the function to check and Analyse empty parent nodes + if dataPath, err = analyseEmptyParentNodes(keyPath); err != nil { + failureMessages = append(failureMessages, err.Error()) + } + if err := deleteDataSdkFunc(context.Background(), dataPath); err != nil { + log.Errorf("Error while deleting Data from SDK for path : %s , %v", keyPath, err.Error()) failureMessages = append(failureMessages, err.Error()) continue } @@ -220,3 +244,148 @@ func findDeployedPolicy(policyID, policyVersion string, deployedPolicies []map[s } return nil } + +// analyzeEmptyParentNodes constructs the parent path based on the provided dataPath. +// It checks if any parent nodes become empty after the deletion of the last child key. +// +// This function takes a JSON representation of parent data and a data path, +// splits the path into segments, and determines the eligible paths for deletion. +// +// If a parent node has only one child and that child is to be deleted, +// the full path up to that parent will be returned. If no eligible parents +// are found by the time it reaches back to the root, the original path will be returned. +func analyseEmptyParentNodes(dataPath string) (string, error) { + log.Debugf("Analyzing dataPath: %s", dataPath) + // Split the dataPath into segments + pathSegments := strings.Split(dataPath, "/") + log.Debugf("Path segments: %+v", pathSegments) + // If the path does not have at least 3 segments, treat it as a leaf node + if len(pathSegments) < consts.SingleHierarchy { + log.Debugf("Path doesn't have any parent-child hierarchy;so returning the original path: %s", dataPath) + return dataPath, nil // It's a leaf node or too short; return the original path + } + // Prepare the parent path which is derived from the second segment + parentKeyPath := "/" + pathSegments[1] // Assuming the immediate parent node + log.Debugf("Detected parent path: %s", parentKeyPath) + // Fetch the data for the detected parent path + parentData, err := opasdkGetData(context.Background(), parentKeyPath) + if err != nil { + return "", fmt.Errorf("failed to get data for parent path %s: %w", parentKeyPath, err) + } + // Unmarshal parent data JSON into a map for analysis + parentDataJson, err := json.Marshal(parentData) + if err != nil { + return "", fmt.Errorf("failed to marshal parent data: %w", err) + } + // Call the method to analyze the hierarchy + return analyzeHierarchy(parentDataJson, dataPath) +} + +// analyzeHierarchy examines the provided data path against the JSON structure to determine +// the last eligible path for deletion based on parent-child relationships. +// +// The function takes a JSON object in raw format and splits the data path into segments. +// Starting from the last key, it checks each parent key to see if it has only one child. +// If so, it marks the path up to that parent as the last eligible path for deletion. +func analyzeHierarchy(parentDataJson json.RawMessage, dataPath string) (string, error) { + // Create a map to hold the parent data + parentMap := make(map[string]interface{}) + + // Unmarshal the fetched JSON data into the parentMap + if err := json.Unmarshal(parentDataJson, &parentMap); err != nil { + return "", fmt.Errorf("error unmarshalling parent data: %w", err) + } + + // Count keys in the JSON structure + countMap := countChildKeysFromJSON(parentMap) + // Split keys and omit the first empty element + keys := strings.Split(dataPath, "/")[1:] + // Default to the input path + lastEligible := dataPath + // Traverse the path from the last key to the first key + // Start from the last segment and stop at the first parent + for indexfromKeyPath := len(keys) - 1; indexfromKeyPath >= 1; indexfromKeyPath-- { + // Identify the parent of the current path + currentPath := strings.Join(keys[:indexfromKeyPath], "/") + // Checking counts of the parent key + childCount := countMap[currentPath] + if childCount == 1 { + // If parent has only 1 child after deletion, it is eligible + lastEligible = "/" + currentPath // Store the path up to this parent + } else { + break + } + } + + log.Debugf("lastEligible Path: %+v", lastEligible) + return lastEligible, nil + +} + +// countChildKeysFromJSON counts the number of child keys for each key in a JSON structure represented as a map. +// +// This function traverses the provided JSON map iteratively using a stack, counting +// the number of direct children for each key. The counts are stored in a map where +// the keys represent the paths in the JSON hierarchy (using slash notation) and the +// values indicate how many children each key has. +// Example Inputs and Outputs: +// +// Given the following JSON: +// { +// "node": { +// "collab": { +// "action": { +// "conflict": {}, +// "others": {} +// }, +// "role": {} +// }, +// "role": { +// "role_grants": { +// "billing": {}, +// "shipping": {} +// } +// } +// } +// } +// Example Output: +// { +// "node": 2, +// "node/collab": 2, +// "node/collab/action": 2, +// "node/collab/role": 0, +// "node/role": 1, +// "node/role/role_grants": 2, +// "node/role/role_grants/billing": 0, +// "node/role/role_grants/shipping": 0 +// } +func countChildKeysFromJSON(data map[string]interface{}) map[string]int { + countMap := make(map[string]int) + + // Creating a stack for iterative traversal with paths + stack := []struct { + current map[string]interface{} + path string + }{ + {data, "node"}, // Start with the root node path + } + + for len(stack) > 0 { + // Pop the current map from the stack + top := stack[len(stack)-1] + stack = stack[:len(stack)-1] + for key, value := range top.current { + //take the full path + currentPath := top.path + "/" + key + if childMap, ok := value.(map[string]interface{}); ok { + // Count the number of children for each key + countMap[currentPath] = len(childMap) + stack = append(stack, struct { + current map[string]interface{} + path string + }{childMap, currentPath}) // Push children map into stack with full path + } + } + } + return countMap +} diff --git a/pkg/kafkacomm/handler/pdp_update_undeploy_policy_test.go b/pkg/kafkacomm/handler/pdp_update_undeploy_policy_test.go index f725f4b..e8c46f7 100644 --- a/pkg/kafkacomm/handler/pdp_update_undeploy_policy_test.go +++ b/pkg/kafkacomm/handler/pdp_update_undeploy_policy_test.go @@ -20,13 +20,14 @@ package handler import ( - // "encoding/json" + "encoding/json" "context" "errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "policy-opa-pdp/consts" "policy-opa-pdp/pkg/model" + "policy-opa-pdp/pkg/model/oapicodegen" "policy-opa-pdp/pkg/policymap" "testing" ) @@ -346,6 +347,18 @@ func TestRemoveDataFromSdkandDir(t *testing.T) { }() // Mock removeDataDirectoryFunc and deleteDataFunc to return errors for testing + opasdkGetData =func (ctx context.Context, dataPath string) (data *oapicodegen.OPADataResponse_Data, err error){ + // Mock JSON data + mockedData := `{"mocked": {"success": "value", "error": "value"}}` + // Create an instance of OPADataResponse_Data + var response oapicodegen.OPADataResponse_Data + // Unmarshal into the OPADataResponse_Data struct + err = json.Unmarshal([]byte(mockedData), &response) + if err != nil { + return nil,errors.New("Error unmarshalling") + } + return &response, nil // +} removeDataDirectoryFunc = func(dataKey string) error { if dataKey == "/mocked/error" { return errors.New("mocked remove data directory error") @@ -370,42 +383,40 @@ func TestRemoveDataFromSdkandDir(t *testing.T) { assert.Contains(t, failures[0], "mocked delete data error") } - func TestRemovePolicyFromSdkandDir(t *testing.T) { - // Backup original functions - originalRemovePolicyDirectory := removePolicyDirectoryFunc - originalDeletePolicy := deletePolicySdkFunc - defer func() { - removePolicyDirectoryFunc = originalRemovePolicyDirectory // Restore after test - deletePolicySdkFunc = originalDeletePolicy // Restore after test - }() - - // Mock functions - removePolicyDirectoryFunc = func(policyKey string) error { - if policyKey == "/mocked/error" { - return errors.New("mocked remove policy directory error") - } - return nil - } - - deletePolicySdkFunc = func(ctx context.Context, policyPath string) error { - if policyPath == "mocked.error" { - return errors.New("mocked delete policy error") - } - return nil - } - - policy := map[string]interface{}{ - "policy": []interface{}{"mocked.success", "mocked.error"}, // VALID policy key - } - - failures := removePolicyFromSdkandDir(policy) - - // Expecting 1 error message (for "mocked.error"), "mocked.success" should pass - assert.Len(t, failures, 1) - assert.Contains(t, failures[0], "mocked delete policy error") -} + // Backup original functions + originalRemovePolicyDirectory := removePolicyDirectoryFunc + originalDeletePolicy := deletePolicySdkFunc + defer func() { + removePolicyDirectoryFunc = originalRemovePolicyDirectory // Restore after test + deletePolicySdkFunc = originalDeletePolicy // Restore after test + }() + + // Mock functions + removePolicyDirectoryFunc = func(policyKey string) error { + if policyKey == "/mocked/error" { + return errors.New("mocked remove policy directory error") + } + return nil + } + + deletePolicySdkFunc = func(ctx context.Context, policyPath string) error { + if policyPath == "mocked.error" { + return errors.New("mocked delete policy error") + } + return nil + } + policy := map[string]interface{}{ + "policy": []interface{}{"mocked.success", "mocked.error"}, // VALID policy key + } + + failures := removePolicyFromSdkandDir(policy) + + // Expecting 1 error message (for "mocked.error"), "mocked.success" should pass + assert.Len(t, failures, 1) + assert.Contains(t, failures[0], "mocked delete policy error") +} // Mocking the remove functions var ( diff --git a/pkg/kafkacomm/publisher/pdp-heartbeat.go b/pkg/kafkacomm/publisher/pdp-heartbeat.go index 7cc9beb..5d5165c 100644 --- a/pkg/kafkacomm/publisher/pdp-heartbeat.go +++ b/pkg/kafkacomm/publisher/pdp-heartbeat.go @@ -57,7 +57,7 @@ func StartHeartbeatIntervalTimer(intervalMs int64, s PdpStatusSender) { } if ticker != nil && intervalMs == currentInterval { - log.Debug("Ticker is already running") + log.Trace("Ticker is already running") return } diff --git a/pkg/utils/sort.go b/pkg/utils/sort.go new file mode 100644 index 0000000..d59ea2a --- /dev/null +++ b/pkg/utils/sort.go @@ -0,0 +1,41 @@ +// - +// ========================LICENSE_START================================= +// Copyright (C) 2025: 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 utils + +import ( + "strings" +) + +// Custom type for sorting +type ByDotCount struct { + Keys []string + Ascend bool +} + +// Implement sort.Interface for ByDotCount +func (a ByDotCount) Len() int { return len(a.Keys) } + +func (a ByDotCount) Swap(i, j int) { a.Keys[i], a.Keys[j] = a.Keys[j], a.Keys[i] } + +func (a ByDotCount) Less(i, j int) bool { + if a.Ascend { + return strings.Count(a.Keys[i], ".") < strings.Count(a.Keys[j], ".") + } + return strings.Count(a.Keys[i], ".") > strings.Count(a.Keys[j], ".") +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 903a0ce..c563dcb 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -16,7 +16,7 @@ // SPDX-License-Identifier: Apache-2.0 // ========================LICENSE_END=================================== -// Package utils provides common functionalities +// Package provides common functionalities package utils @@ -30,6 +30,7 @@ import ( "policy-opa-pdp/consts" "policy-opa-pdp/pkg/log" "policy-opa-pdp/pkg/model" + "policy-opa-pdp/pkg/model/oapicodegen" "regexp" "strings" "time" @@ -41,6 +42,7 @@ type ( var ( CreateDirectoryVar CreateDirectoryFunc = CreateDirectory + removeAll = os.RemoveAll ) // validates if the given request is in valid uuid form @@ -63,31 +65,24 @@ func CreateDirectory(dirPath string) error { // Helper function to check and remove a directory func RemoveDirectory(dirPath string) error { - entries, err := os.ReadDir(dirPath) + fileDirPath := filepath.Clean(dirPath) + err := removeAll(fileDirPath) if err != nil { if os.IsNotExist(err) { - log.Warnf("Directory does not exist: %s", dirPath) + log.Warnf("Directory does not exist: %s", fileDirPath) // Directory does not exist, nothing to do return nil } - return fmt.Errorf("failed to read directory: %w", err) - } + return fmt.Errorf("failed to remove file: %s, error: %w", fileDirPath, err) - for _, entry := range entries { - entryPath := filepath.Join(dirPath, entry.Name()) - // Delete specific files in the parent directory - log.Debugf("Removing file: %s", entryPath) - if err := os.Remove(entryPath); err != nil { - return fmt.Errorf("failed to remove file: %s, error: %w", entryPath, err) - } } // Create a loop to check parent directories. - currentPath := dirPath + // Move to the parent directory + currentPath := filepath.Clean(filepath.Dir(dirPath)) for { - log.Infof("Processig Parent dir : %s", currentPath) // Check if we have reached the match path - if currentPath == consts.Data+"/node" || currentPath == consts.Policies { + if currentPath == filepath.Clean(consts.DataNode) || currentPath == filepath.Clean(consts.Policies) { return nil // Stop if we reach the match path } @@ -95,7 +90,7 @@ func RemoveDirectory(dirPath string) error { log.Infof("Reached root orelative path: %s", currentPath) return nil // Stop if we reach the match path } - + log.Infof("Processig Parent dir : %s", currentPath) // Check if the parent directory exists before proceeding if _, err := os.Stat(currentPath); os.IsNotExist(err) { log.Debugf("directory does not exist: %s. Stopping iteration.", currentPath) @@ -106,10 +101,10 @@ func RemoveDirectory(dirPath string) error { if err != nil { return err } - // Trim the path to its parent directory. + + // Move to the parent directory currentPath = filepath.Dir(currentPath) } - } func isSubDirEmpty(entryPath string) error { @@ -120,7 +115,7 @@ func isSubDirEmpty(entryPath string) error { } if isEmpty { log.Debugf("Removing empty subdirectory: %s", entryPath) - if err := os.RemoveAll(entryPath); err != nil { + if err := removeAll(entryPath); err != nil { return fmt.Errorf("failed to remove directory: %s, error: %w", entryPath, err) } } @@ -314,11 +309,14 @@ func IsValidCurrentTime(currentTime *string) bool { } // Custom validation function for *string type eg: OnapComponent, OnapInstance, OnapName, PolicyName -func IsValidString(name *string) bool { - if name == nil || strings.TrimSpace(*name) == "" { - return false - } else { - return true +func IsValidString(name interface{}) bool { + switch v := name.(type) { + case *string: + return v != nil && strings.TrimSpace(*v) != "" + case string: + return strings.TrimSpace(v) != "" + default: + return false // Handles cases where name is neither a string nor a *string } } @@ -326,7 +324,7 @@ func BuildBundle(cmdFunc func(string, ...string) *exec.Cmd) (string, error) { cmd := cmdFunc( consts.Opa, consts.BuildBundle, - consts.V1_COMPATIBLE, + consts.V1Compatible, consts.Policies, consts.Data, consts.Output, @@ -343,3 +341,98 @@ func BuildBundle(cmdFunc func(string, ...string) *exec.Cmd) (string, error) { log.Debug("Bundle Built Sucessfully....") return string(output), nil } + +// Validation function +func ValidateOPADataRequest(request interface{}) []string { + var validationErrors []string + if updateRequest, ok := request.(*oapicodegen.OPADataUpdateRequest); ok { + // Check if required fields are populated + dateString := (updateRequest.CurrentDate).String() + if !(IsValidCurrentDate(&dateString)) { + validationErrors = append(validationErrors, "CurrentDate is required") + } + + // Validate CurrentDateTime format + if !(IsValidTime(updateRequest.CurrentDateTime)) { + validationErrors = append(validationErrors, "CurrentDateTime is invalid or missing") + } + + // Validate CurrentTime format + if !(IsValidCurrentTime(updateRequest.CurrentTime)) { + validationErrors = append(validationErrors, "CurrentTime is invalid or missing") + } + + // Validate TimeOffset format (e.g., +02:00 or -05:00) + if !(IsValidTimeOffset(updateRequest.TimeOffset)) { + validationErrors = append(validationErrors, "TimeOffset is invalid or missing") + } + + // Validate TimeZone format (e.g., 'America/New_York') + if !(IsValidTimeZone(updateRequest.TimeZone)) { + validationErrors = append(validationErrors, "TimeZone is invalid or missing") + } + + // Optionally, check if 'OnapComponent', 'OnapInstance', 'OnapName', and 'PolicyName' are provided + if !(IsValidString(updateRequest.OnapComponent)) { + validationErrors = append(validationErrors, "OnapComponent is required") + } + + if !(IsValidString(updateRequest.OnapInstance)) { + validationErrors = append(validationErrors, "OnapInstance is required") + } + + if !(IsValidString(updateRequest.OnapName)) { + validationErrors = append(validationErrors, "OnapName is required") + } + + if !(IsValidString(updateRequest.PolicyName)) { + validationErrors = append(validationErrors, "PolicyName is required and cannot be empty") + } + } + + if decisionRequest, ok := request.(*oapicodegen.OPADecisionRequest); ok { + // Check if required fields are populated + dateString := (decisionRequest.CurrentDate).String() + if !(IsValidCurrentDate(&dateString)) { + validationErrors = append(validationErrors, "CurrentDate is required") + } + + // Validate CurrentDateTime format + if !(IsValidTime(decisionRequest.CurrentDateTime)) { + validationErrors = append(validationErrors, "CurrentDateTime is invalid or missing") + } + + // Validate CurrentTime format + if !(IsValidCurrentTime(decisionRequest.CurrentTime)) { + validationErrors = append(validationErrors, "CurrentTime is invalid or missing") + } + + // Validate TimeOffset format (e.g., +02:00 or -05:00) + if !(IsValidTimeOffset(decisionRequest.TimeOffset)) { + validationErrors = append(validationErrors, "TimeOffset is invalid or missing") + } + + // Validate TimeZone format (e.g., 'America/New_York') + if !(IsValidTimeZone(decisionRequest.TimeZone)) { + validationErrors = append(validationErrors, "TimeZone is invalid or missing") + } + + // Optionally, check if 'OnapComponent', 'OnapInstance', 'OnapName', and 'PolicyName' are provided + if !(IsValidString(decisionRequest.OnapComponent)) { + validationErrors = append(validationErrors, "OnapComponent is required") + } + + if !(IsValidString(decisionRequest.OnapInstance)) { + validationErrors = append(validationErrors, "OnapInstance is required") + } + + if !(IsValidString(decisionRequest.OnapName)) { + validationErrors = append(validationErrors, "OnapName is required") + } + + if !(IsValidString(decisionRequest.PolicyName)) { + validationErrors = append(validationErrors, "PolicyName is required and cannot be empty") + } + } + return validationErrors +} diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 591d1ea..87c841a 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -19,12 +19,16 @@ package utils import ( + "fmt" "github.com/google/uuid" + openapi_types "github.com/oapi-codegen/runtime/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "os" "os/exec" "path/filepath" "policy-opa-pdp/pkg/model" + "policy-opa-pdp/pkg/model/oapicodegen" "testing" "time" ) @@ -149,17 +153,6 @@ func TestRemoveDirectory_NonExistent(t *testing.T) { assert.NoError(t, err, "Expected no error when removing a non-existent directory") } -// Test failure scenario where ReadDir fails -func TestRemoveDirectory_ReadDirFailure(t *testing.T) { - // Create a file instead of a directory - tempFile, err := os.CreateTemp("", "testfile") - assert.NoError(t, err) - defer os.Remove(tempFile.Name()) - - err = RemoveDirectory(tempFile.Name()) // Should fail because it's a file, not a directory - assert.Error(t, err, "Expected an error when trying to remove a file as a directory") -} - // Test removing a directory containing only data.json and policy.rego func TestRemoveDirectory_WithSpecificFiles(t *testing.T) { tempDir, err := os.MkdirTemp("", "testdir") @@ -620,3 +613,139 @@ func TestBuildBundle_CommandFailure(t *testing.T) { t.Errorf("BuildBundle() error = nil, wantErr %v", output) } } + +// Test function for isSubDirEmpty using real directories +func TestIsSubDirEmpty(t *testing.T) { + // Create a temporary directory for testing + t.Run("Empty Directory - Should be removed", func(t *testing.T) { + tempDir, err := os.MkdirTemp("", "emptyDir") + require.NoError(t, err) + + // Call the function + err = isSubDirEmpty(tempDir) + + // Assert no error and directory should be removed + assert.NoError(t, err) + _, err = os.Stat(tempDir) + assert.True(t, os.IsNotExist(err)) // Directory should be gone + }) + + t.Run("Non-Empty Directory - Should not be removed", func(t *testing.T) { + tempDir, err := os.MkdirTemp("", "nonEmptyDir") + require.NoError(t, err) + + // Create a file inside to make the directory non-empty + _, err = os.CreateTemp(tempDir, "file") + require.NoError(t, err) + + // Call the function + err = isSubDirEmpty(tempDir) + + // Assert directory still exists + assert.NoError(t, err) + _, err = os.Stat(tempDir) + assert.NoError(t, err) // Directory should still exist + + // Clean up + os.RemoveAll(tempDir) + }) + + t.Run("Non-Existent Directory - Should return an error", func(t *testing.T) { + tempDir := "/path/that/does/not/exist" + + err := isSubDirEmpty(tempDir) + + // Assert error + assert.Error(t, err) + // assert.True(t, os.IsNotExist(err)) + }) + + t.Run("Error Removing Directory - Should return an error", func(t *testing.T) { + // Create a temporary directory + tempDir, err := os.MkdirTemp("", "errorDir") + require.NoError(t, err) + + // Mock removeAll to return an error + originalRemoveAll := removeAll + defer func() { removeAll = originalRemoveAll }() // Restore after test + + removeAll = func(path string) error { + return fmt.Errorf("failed to remove directory: %s", path) + } + + err = isSubDirEmpty(tempDir) + + // Assert error + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to remove directory") + + // Clean up + os.RemoveAll(tempDir) + }) +} + +func TestValidateOPADataRequest(t *testing.T) { + ctime := "12:00:00" + timeZone := "America_New_York" + timeOffset := "$02:00" + onapComp := " " + onapIns := " " + onapName := " " + policyName := " " + var currentDate openapi_types.Date + currentDate = openapi_types.Date{} + var currentDateTime time.Time + currentDateTime = time.Time{} + + var data []map[string]interface{} + + data = nil + + inValidRequest := &oapicodegen.OPADataUpdateRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: &onapComp, + OnapInstance: &onapIns, + OnapName: &onapName, + PolicyName: &policyName, + Data: &data, + } + + inValidErr := []string{"CurrentTime is invalid or missing", "TimeOffset is invalid or missing", "TimeZone is invalid or missing", "OnapComponent is required", "OnapInstance is required", "OnapName is required", "PolicyName is required and cannot be empty"} + + // Create an invalid OPADecisionRequest + invalidDecisionRequest := &oapicodegen.OPADecisionRequest{ + CurrentDate: ¤tDate, + CurrentDateTime: ¤tDateTime, + CurrentTime: &ctime, + TimeOffset: &timeOffset, + TimeZone: &timeZone, + OnapComponent: nil, // Invalid: should not be nil + OnapInstance: nil, // Invalid: should not be nil + OnapName: nil, // Invalid: should not be nil + PolicyName: "", // Invalid: should not be empty + PolicyFilter: []string{"user_is_granted"}, // This can remain valid. + //Input: nil, + } + invalidDecisionErrs := []string{"CurrentTime is invalid or missing", "TimeOffset is invalid or missing", "TimeZone is invalid or missing", "OnapComponent is required", "OnapInstance is required", "OnapName is required", "PolicyName is required and cannot be empty"} + tests := []struct { + name string + request interface{} + expectedErr []string + }{ + {"Valid Request", inValidRequest, inValidErr}, + {"Invalid OPADecisionRequest", invalidDecisionRequest, invalidDecisionErrs}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + errors := ValidateOPADataRequest(tt.request) + fmt.Printf("error : %s", errors) + fmt.Printf("error len : %d", len(errors)) + assert.Equal(t, tt.expectedErr, errors) + }) + } +} diff --git a/test/Opagroup.json b/test/Opagroup.json deleted file mode 100644 index 002b962..0000000 --- a/test/Opagroup.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "groups": [ - { - "name": "defaultGroup", - "pdpGroupState": "ACTIVE", - "properties": {}, - "pdpSubgroups": [ - { - "pdpType": "opa", - "desiredInstanceCount": 1, - "properties": {}, - "supportedPolicyTypes": [ - { - "name": "onap.policies.native.opa", - "version": "1.0.0" - } - ], - "policies": [] - } - ] - } - ] -} diff --git a/test/README.md b/test/README.md index bc9f931..92f89fa 100644 --- a/test/README.md +++ b/test/README.md @@ -14,106 +14,42 @@ `curl -v -u 'policyadmin:zb!XztG34' -X POST -H "Content-Type":"application/json" -d @test_resources/undeploy_batch_delete.json http://localhost:30003/policy/pap/v1/pdps/deployments/batch` -## Verification API Calls +## Decision API Response -curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z", "policyFilter" : [""], "policyName":"example","input":{"method":"POST","path":["users"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision +## Output For Policy: access_method with empty filter +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyFilter" : [""], "policyName":"access_method","input":{"method":"POST","path":["users"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision -{"output":{"allow":true},"policyName":"example"} +{"output":null,"policyName":"access_method","statusMessage":"Policy Filter(s) not matching, Valid Filter(s) are: [allow]"} -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", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z", "policyName":"role", "policyFilter": ["role_grants"], "input":{"user":"alice","action":"write","object":"id123","type":"dog"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision +## Output For Policy: access_method with filter allow +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyFilter" : ["allow"], "policyName":"access_method","input":{"method":"POST","path":["users"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision +{"output":{"allow":true},"policyName":"access_method"} -{"output":{"role_grants":{"billing":[{"action":"read","type":"finance"},{"action":"update","type":"finance"}],"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"}]}},"policyName":"role"} +## Output For Policy: role with filter allow -## OUTPUT for policy:action with filter role_permissions +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", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyName":"role", "policyFilter": ["allow"], "input":{"user":"alice","action":"write","object":"id123","type":"dog"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision -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", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z",__"policyFilter": ["role_permissions"]__, "policyName":"action","input":{"user":"alice","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision +{"output":{"allow":true},"policyName":"role"} -{"output":{"role_permissions":{"admin":{"actions":["read","write","delete"],"resources":["server","database"]},"editor":{"actions":["read","write"],"resources":["server"]},"viewer":{"actions":["read"],"resources":["server"]}}},"policyName":"action"} +## Output For policy: role with empty filter +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", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyName":"role", "policyFilter": [""], "input":{"user":"alice","action":"write","object":"id123","type":"dog"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision +{"output":null,"policyName":"role","statusMessage":"Policy Filter(s) not matching, Valid Filter(s) are: [allow, user_is_admin, user_is_granted]"} -## OUTPUT for policy:action with empty filters +## Output For Policy: blacklist with filter module_allow +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyFilter" : ["module_allow"], "policyName":"blacklist","input":{"vfmodule":["the-vfmodule-where-root-is-true","another-vfmodule-where-root-is-true" ] }}' -X POST http://localhost:8282/policy/pdpo/v1/decision +{"output":{"module_allow":{"another-vfmodule-where-root-is-true":true,"the-vfmodule-where-root-is-true":true}},"policyName":"blacklist"} -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", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z",__"policyFilter": [""]__, "policyName":"action","input":{"user":"alice","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision +## Output For Policy: blacklist with Empty Filter + curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyFilter" : [""], "policyName":"blacklist","input":{"vfmodule":["the-vfmodule-where-root-is-true","another-vfmodule-where-root-is-true" ] }}' -X POST http://localhost:8282/policy/pdpo/v1/decision +{"output":null,"policyName":"blacklist","statusMessage":"Policy Filter(s) not matching, Valid Filter(s) are: [module_allow, module_allow/another-vfmodule-where-root-is-true, module_allow/the-vfmodule-where-root-is-true]"} -{"output":{"allow":true,"role_permissions":{"admin":{"actions":["read","write","delete"],"resources":["server","database"]},"editor":{"actions":["read","write"],"resources":["server"]},"viewer":{"actions":["read"],"resources":["server"]}},"user_roles":{"alice":["admin"],"bob":["editor"],"charlie":["viewer"]}},"policyName":"action"} - -## OUTPUT for policy:action without filter - -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", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"action","input":{"user":"charlie","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"errorMessage":"Policy Filter is nil.","policyName":"","responseCode":"bad_request"} - -## OUTPUT for policy:account with filter account_attributes - -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", "currentTime": "11:34:56", "timeZone": "UTC","timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z",__"policyFilter": ["account_attributes"]__, "policyName":"account", "input":{"creditor_account":11111,"creditor":"alice","debtor_account":22222,"debtor":"bob","period":30,"amount":1000}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"output":{"account_attributes":{"11111":{"amount":10000,"owner":"alice"},"22222":{"amount":10000,"owner":"bob"},"33333":{"amount":10000,"owner":"cam"}}},"policyName":"account"} - -## OUTPUT for policy:account with empty filter - -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", "currentTime": "11:34:56", "timeZone": "UTC","timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z",__"policyFilter": [""]__, "policyName":"account", "input":{"creditor_account":11111,"creditor":"alice","debtor_account":22222,"debtor":"bob","period":30,"amount":1000}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"output":{"account_attributes":{"11111":{"amount":10000,"owner":"alice"},"22222":{"amount":10000,"owner":"bob"},"33333":{"amount":10000,"owner":"cam"}},"allow":true,"amount_is_valid":true,"creditor_is_valid":true,"debtor_is_valid":true,"period_is_valid":true},"policyName":"account"} - -## OUTPUT for policy:organization with filter acls - -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", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z",__"policyFilter": ["acls"]__, "policyName":"organization", "input":{"user":"alice","action": "read","component": "component_A","project": "project_A", "organization": "org_A"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"output":{"acls":[{"actions":["edit","read"],"component":"component_A","organization":"org_A","project":"project_A","user":"alice"},{"actions":["read"],"organization":"org_A","user":"bob"},{"action":["edit"],"component":"component_A","organization":"org_A","project":"project_B","user":"bob"},{"action":["read"],"organization":"org_A","project":"project_B","user":"charlie"}]},"policyName":"organization"} - -## OUTPUT for policy:organization with empty filter - -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", "currentTime": "11:34:56", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z",__"policyFilter": [""]__, "policyName":"organization", "input":{"user":"alice","action": "read","component": "component_A","project": "project_A", "organization": "org_A"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"output":{"acls":[{"actions":["edit","read"],"component":"component_A","organization":"org_A","project":"project_A","user":"alice"},{"actions":["read"],"organization":"org_A","user":"bob"},{"action":["edit"],"component":"component_A","organization":"org_A","project":"project_B","user":"bob"},{"action":["read"],"organization":"org_A","project":"project_B","user":"charlie"}],"allow":true},"policyName":"organization"} - -## OUTPUT for policy:abac with filter viewable_sensor_data - -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": ["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/pdpo/v1/decision - -{"output":{"viewable_sensor_data":[]},"policyName":"abac"} - -## OUTPUT for policy:abac with empty filter - -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": [""]__, "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/pdpo/v1/decision - -{"output":{"allow":false,"sensor_data":[{"humidity":"40%","id":"0001","location":"Sri Lanka","particle_density":"1.3 g/l","precipitation":"1000 mm","temperature":"28 C","timestamp":"2024-02-26","windspeed":"5.5 m/s"},{"humidity":"45%","id":"0002","location":"Colombo","particle_density":"1.5 g/l","precipitation":"1200 mm","temperature":"30 C","timestamp":"2024-02-26","windspeed":"6.0 m/s"},{"humidity":"60%","id":"0003","location":"Kandy","particle_density":"1.1 g/l","precipitation":"800 mm","temperature":"25 C","timestamp":"2024-02-26","windspeed":"4.5 m/s"},{"humidity":"30%","id":"0004","location":"Galle","particle_density":"1.8 g/l","precipitation":"500 mm","temperature":"35 C","timestamp":"2024-02-27","windspeed":"7.2 m/s"},{"humidity":"20%","id":"0005","location":"Jaffna","particle_density":"0.9 g/l","precipitation":"300 mm","temperature":"-5 C","timestamp":"2024-02-27","windspeed":"3.8 m/s"},{"humidity":"55%","id":"0006","location":"Trincomalee","particle_density":"1.2 g/l","precipitation":"1000 mm","temperature":"20 C","timestamp":"2024-02-28","windspeed":"5.0 m/s"},{"humidity":"50%","id":"0007","location":"Nuwara Eliya","particle_density":"1.3 g/l","precipitation":"600 mm","temperature":"25 C","timestamp":"2024-02-28","windspeed":"4.0 m/s"},{"humidity":"40%","id":"0008","location":"Anuradhapura","particle_density":"1.4 g/l","precipitation":"700 mm","temperature":"28 C","timestamp":"2024-02-29","windspeed":"5.8 m/s"},{"humidity":"65%","id":"0009","location":"Matara","particle_density":"1.6 g/l","precipitation":"900 mm","temperature":"32 C","timestamp":"2024-02-29","windspeed":"6.5 m/s"}],"viewable_sensor_data":[]},"policyName":"abac"} - -## OUTPUT for policy:zone with filter has_zone_access - -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/pdpo/v1/decision - -{"output":{"has_zone_access":[{"access":"granted","user":"user1"}]},"policyName":"zone"} - -## OUTPUT for policy:zone with empty filter - -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": [""]__, "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/pdpo/v1/decision - -{"output":{"action_is_log_view":true,"allow":true,"has_zone_access":[{"access":"granted","user":"user1"}],"zone":{"zone_access_logs":[{"access":"granted","log_id":"log1","timestamp":"2024-11-01T09:00:00Z","user":"user1","zone_id":"zoneA"},{"access":"denied","log_id":"log2","timestamp":"2024-11-01T10:30:00Z","user":"user2","zone_id":"zoneA"},{"access":"granted","log_id":"log3","timestamp":"2024-11-01T11:00:00Z","user":"user3","zone_id":"zoneB"}]}},"policyName":"zone"} - -## OUTPUT for policy:vehicle with filter user_has_vehicle_access - -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/pdpo/v1/decision - -{"output":{"user_has_vehicle_access":[{"status":"available","type":"car"}]},"policyName":"vehicle"} - -## OUTPUT for policy:vehicle with empty filter - -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": [""]__, "input":{"actions": ["use"],"user":"user1", "vehicle_id": "v1", "attributes": ["type", "status"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"output":{"action_is_granted":true,"allow":true,"user_has_vehicle_access":[{"status":"available","type":"car"}],"vehicles":[{"owner":"user1","status":"available","type":"car","vehicle_id":"v1"},{"owner":"user2","status":"in use","type":"bike","vehicle_id":"v2"}]},"policyName":"vehicle"} - -## OUTPUT for policy:docs with filter has_access_to_file - -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/pdpo/v1/decision - -{"output":{"has_access_to_file":[{"owner":"user1","size":"10MB"}]},"policyName":"docs"} - -## OUTPUT for policy:docs with empty filter - -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": [""]__, "input":{"action": "read","file_id": "file1","access_level": "admin","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision - -{"output":{"action_is_read_or_write":true,"allow":true,"files":[{"access_level":"admin","file_id":"file1","owner":"user1","size":"10MB"},{"access_level":"user","file_id":"file2","owner":"user2","size":"5MB"}],"has_access_to_file":[{"owner":"user1","size":"10MB"}]},"policyName":"docs"} +## Output For Policy: monitor with filter result +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyFilter" : ["result"], "policyName":"monitor","input":{ "domain": "measurementsForVfScaling", "eventName": "Measurement_vGMUX","controlLoopSchemaType": "VNF","policyScope": "DCAE","policyName": "DCAE.Config_tca-hi-lo","policyVersion": "v0.0.1", "version": "1.0.2","controlname": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","thresholdValue": 0}}' -X POST http://localhost:8282/policy/pdpo/v1/decision +{"output":{"result":[{"closedLoopEventStatus":"ABATED","severity":"MAJOR"}]},"policyName":"monitor"} +## Output For Policy: monitor with empty filter +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "08:26:41.857Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2025-01-17T08:26:41.857Z", "policyFilter" : [""], "policyName":"monitor","input":{ "domain": "measurementsForVfScaling", "eventName": "Measurement_vGMUX","controlLoopSchemaType": "VNF","policyScope": "DCAE","policyName": "DCAE.Config_tca-hi-lo","policyVersion": "v0.0.1", "version": "1.0.2","controlname": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","thresholdValue": 0}}' -X POST http://localhost:8282/policy/pdpo/v1/decision +{"output":null,"policyName":"monitor","statusMessage":"Policy Filter(s) not matching, Valid Filter(s) are: [result]"} ## HealthCheck API Call With Response @@ -126,4 +62,6 @@ curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bc curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpo/v1/statistics -{"code":200,"decisionFailureCount":0,"decisionSuccessCount":9,"deployFailureCount":0,"deploySuccessCount":0,"totalErrorCount":5,"totalPoliciesCount":0,"totalPolicyTypesCount":1,"undeployFailureCount":0,"undeploySuccessCount":0} +curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpo/v1/statistics +{"code":200,"decisionFailureCount":0,"decisionSuccessCount":0,"deployFailureCount":0,"deploySuccessCount":0, "totalErrorCount":0,"totalPoliciesCount":0,"totalPolicyTypesCount":1,"undeployFailureCount":0,"undeploySuccessCount":0} + diff --git a/test/config.json b/test/config.json deleted file mode 100644 index 0eb38c9..0000000 --- a/test/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "logging": { - "level": "debug" - }, - "decision_logs": { - "console": true - } -} diff --git a/test/config/opa-pdp/config.json b/test/config/opa-pdp/config.json deleted file mode 100644 index 0eb38c9..0000000 --- a/test/config/opa-pdp/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "logging": { - "level": "debug" - }, - "decision_logs": { - "console": true - } -} diff --git a/test/config/opa-pdp/groups.json b/test/config/opa-pdp/groups.json deleted file mode 100644 index 502700c..0000000 --- a/test/config/opa-pdp/groups.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "groups": [ - { - "name": "defaultGroup", - "version": "1.0.0", - "description": "The default group that registers all supported policy types and pdps.", - "pdpGroupState": "ACTIVE", - "pdpSubgroups": [ - { - "pdpType": "opa" - } - ] - } - ] -} diff --git a/test/config/opa-pdp/policy-opa-pdp.sh b/test/config/opa-pdp/policy-opa-pdp.sh deleted file mode 100755 index 7ed14cb..0000000 --- a/test/config/opa-pdp/policy-opa-pdp.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - - -#Creation of Policies and Groups -sh scripts.sh - - -#Execution of OPA-PDP bin -/app/opa-pdp diff --git a/test/data/abac/data.json b/test/data/abac/data.json deleted file mode 100644 index 77b5668..0000000 --- a/test/data/abac/data.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "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 deleted file mode 100644 index df263d3..0000000 --- a/test/data/account/data.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "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 deleted file mode 100644 index 99145b7..0000000 --- a/test/data/action/data.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "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/blacklist/data.json b/test/data/blacklist/data.json new file mode 100644 index 0000000..9fd6233 --- /dev/null +++ b/test/data/blacklist/data.json @@ -0,0 +1,6 @@ +{ + "blacklist" : [ + "the-vfmodule-where-root-is-true", + "another-vfmodule-where-root-is-true" +] +} diff --git a/test/data/cell/consistency/data.json b/test/data/cell/consistency/data.json new file mode 100644 index 0000000..1f823a1 --- /dev/null +++ b/test/data/cell/consistency/data.json @@ -0,0 +1,5 @@ +{ + "allowedCellId" : 445611193265040129, + "minPCI": 1, + "maxPCI": 3000 +} diff --git a/test/data/docs/data.json b/test/data/docs/data.json deleted file mode 100644 index 5d43020..0000000 --- a/test/data/docs/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [ - { "file_id": "file1", "access_level": "admin", "owner": "user1", "size": "10MB" }, - { "file_id": "file2", "access_level": "user", "owner": "user2", "size": "5MB" } - ] -} - diff --git a/test/data/monitor/data.json b/test/data/monitor/data.json new file mode 100644 index 0000000..f28f73c --- /dev/null +++ b/test/data/monitor/data.json @@ -0,0 +1,13 @@ +{ "domain": "measurementsForVfScaling", + "metricsPerEventName": [{ + "eventName": "Measurement_vGMUX", + "controlLoopSchemaType": "VNF", + "policyScope": "DCAE", + "policyName": "DCAE.Config_tca-hi-lo", + "policyVersion": "v0.0.1", + "thresholds" : [{"version": "1.0.2", + "closedLoopControlName": "ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e", + "thresholdValue": 0 + }] +}] +} diff --git a/test/data/organization/data.json b/test/data/organization/data.json deleted file mode 100644 index 35fe4a1..0000000 --- a/test/data/organization/data.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "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/vehicle/data.json b/test/data/vehicle/data.json deleted file mode 100644 index 570c677..0000000 --- a/test/data/vehicle/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "vehicles": [ - { "vehicle_id": "v1", "owner": "user1", "type": "car", "status": "available" }, - { "vehicle_id": "v2", "owner": "user2", "type": "bike", "status": "in use" } - ] -} - diff --git a/test/data/zone/data.json b/test/data/zone/data.json deleted file mode 100644 index be77176..0000000 --- a/test/data/zone/data.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "zone": { - "zone_access_logs": [ - { "log_id": "log1", "timestamp": "2024-11-01T09:00:00Z", "zone_id": "zoneA", "access": "granted", "user": "user1" }, - { "log_id": "log2", "timestamp": "2024-11-01T10:30:00Z", "zone_id": "zoneA", "access": "denied", "user": "user2" }, - { "log_id": "log3", "timestamp": "2024-11-01T11:00:00Z", "zone_id": "zoneB", "access": "granted", "user": "user3" } - ] - } -} - diff --git a/test/docker-compose.yml b/test/docker-compose.yml deleted file mode 100644 index a4dea24..0000000 --- a/test/docker-compose.yml +++ /dev/null @@ -1,140 +0,0 @@ -version: '3.8' -services: - mariadb: - image: nexus3.onap.org:10001/mariadb:10.10.2 - container_name: mariadb - hostname: mariadb - command: ['--lower-case-table-names=1', '--wait_timeout=28800', '--default-authentication-plugin=mysql_native_password'] - env_file: ./config/db/db.conf - volumes: - - ./config/db:/docker-entrypoint-initdb.d - - ./config/clamp/policy-clamp-create-tables.sql:/tmp/policy-clamp-create-tables.sql - ports: - - "3306:3306" - policy-db-migrator: - image: nexus3.onap.org:10001/onap/policy-db-migrator:4.0.1-SNAPSHOT - container_name: policy-db-migrator - hostname: policy-db-migrator - depends_on: - - mariadb - expose: - - 6824 - env_file: ./config/db/db.conf - environment: - SQL_DB: policyadmin - SQL_HOST: mariadb - volumes: - - ./config/db-migrator/init.sh:/opt/app/policy/bin/db_migrator_policy_init.sh:ro - - ./wait_for_port.sh:/tmp/wait_for_port.sh - entrypoint: sh /tmp/wait_for_port.sh - command: [ - '-c', - '/opt/app/policy/bin/db_migrator_policy_init.sh', - 'mariadb', '3306' - ] - api: - image: nexus3.onap.org:10001/onap/policy-api:4.0.1-SNAPSHOT - container_name: policy-api - depends_on: - - policy-db-migrator - hostname: policy-api - ports: - - 30002:6969 - volumes: - - ./config/api/apiParameters.yaml:/opt/app/policy/api/etc/apiParameters.yaml:ro - - ./config/api/logback.xml:/opt/app/policy/api/etc/logback.xml:ro - - ./wait_for_port.sh:/opt/app/policy/api/bin/wait_for_port.sh - entrypoint: sh wait_for_port.sh - command: [ - '-c', './policy-api.sh', - 'mariadb', '3306', - 'policy-db-migrator', '6824' - ] - pap: - image: nexus3.onap.org:10001/onap/policy-pap:4.0.1-SNAPSHOT - container_name: policy-pap - depends_on: - - mariadb - - kafka - - api - hostname: policy-pap - ports: - - 30003:6969 - volumes: - - ./config/pap/papParameters.yaml:/opt/app/policy/pap/etc/papParameters.yaml:ro - - ./config/pap/groups.json:/opt/app/policy/pap/etc/mounted/groups.json:ro - - ./config/pap/logback.xml:/opt/app/policy/pap/etc/logback.xml:ro - - ./wait_for_port.sh:/opt/app/policy/pap/bin/wait_for_port.sh - entrypoint: sh wait_for_port.sh - command: [ - '-c', './policy-pap.sh', - 'mariadb', '3306', - 'kafka', '9092', - 'api', '6969' - ] - zookeeper: - image: confluentinc/cp-zookeeper:latest - environment: - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 - ports: - - 2181:2181 - - pdp: - image: docker.io/opa-pdp:1.0.0 - container_name: opa-pdp - depends_on: - - mariadb - - kafka - - api - - pap - hostname: opa-pdp - volumes: - - ./config/opa-pdp/config.json:/app/config/config.json:ro - - ./config/opa-pdp/groups.json:/app/groups.json:ro - - ./config/opa-pdp/policy-opa-pdp.sh:/app/policy-opa-pdp.sh:ro - - ./wait_for_port.sh:/app/wait_for_port.sh - - ./scripts.sh:/app/scripts.sh - - ./Opagroup.json:/app/Opagroup.json - - ./policy-new.yaml:/app/policy-new.yaml - environment: - LOG_LEVEL: debug - KAFKA_URL: "kafka:9092" - PAP_TOPIC: policy-pdp-pap - 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', - 'mariadb', '3306', - 'kafka', '9092', - 'api', '6969', - 'pap', '6969' - ] - ports: - - 8282:8282 - zookeeper: - image: confluentinc/cp-zookeeper:latest - environment: - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 - ports: - - 2181:2181 - - kafka: - image: confluentinc/cp-kafka:latest - container_name: kafka - depends_on: - - zookeeper - ports: - - 29092:29092 - - 9092:9092 - environment: - KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 diff --git a/test/policies/abac/policy.rego b/test/policies/abac/policy.rego deleted file mode 100644 index 9dc6ea9..0000000 --- a/test/policies/abac/policy.rego +++ /dev/null @@ -1,20 +0,0 @@ -package abac - -import rego.v1 - -default allow := false - -allow if { - viewable_sensor_data - action_is_read -} - -action_is_read if "read" in input.actions - -viewable_sensor_data contains view_data if { - some sensor_data in data.abac.sensor_data - sensor_data.timestamp >= input.time_period.from - sensor_data.timestamp < input.time_period.to - - view_data := {datatype: sensor_data[datatype] | datatype in input.datatypes} -} diff --git a/test/policies/example/policy.rego b/test/policies/access_method/policy.rego similarity index 89% rename from test/policies/example/policy.rego rename to test/policies/access_method/policy.rego index cc19285..618aacc 100644 --- a/test/policies/example/policy.rego +++ b/test/policies/access_method/policy.rego @@ -1,4 +1,4 @@ -package example +package access_method import rego.v1 diff --git a/test/policies/account/policy.rego b/test/policies/account/policy.rego deleted file mode 100644 index f99e8eb..0000000 --- a/test/policies/account/policy.rego +++ /dev/null @@ -1,17 +0,0 @@ -package account - -import rego.v1 - -default allow := false - -allow if { - creditor_is_valid - debtor_is_valid - period_is_valid - amount_is_valid -} -creditor_is_valid if data.account.account_attributes[input.creditor_account].owner == input.creditor -debtor_is_valid if data.account.account_attributes[input.debtor_account].owner == input.debtor - -period_is_valid if input.period <= 30 -amount_is_valid if data.account.account_attributes[input.debtor_account].amount >= input.amount diff --git a/test/policies/action/policy.rego b/test/policies/action/policy.rego deleted file mode 100644 index 300fe50..0000000 --- a/test/policies/action/policy.rego +++ /dev/null @@ -1,21 +0,0 @@ -package action - -import rego.v1 - -# By default, deny requests. -default allow := false - - -# Allow the action if admin role is granted permission to perform the action. -allow if { - some i - data.action.user_roles[input.user][i] == role - some j - data.action.role_permissions[role].actions[j] == input.action - some k - data.action.role_permissions[role].resources[k] == input.type -} -# * Rego comparison to other systems: https://www.openpolicyagent.org/docs/latest/comparison-to-other-systems/ -# * Rego Iteration: https://www.openpolicyagent.org/docs/latest/#iteration - - diff --git a/test/policies/blacklist/policy.rego b/test/policies/blacklist/policy.rego new file mode 100644 index 0000000..b285593 --- /dev/null +++ b/test/policies/blacklist/policy.rego @@ -0,0 +1,18 @@ +package blacklist +import future.keywords.in +import rego.v1 + +# Define a rule to check if the operation should be allowed +module_allow[module] := false if { + some module in input.vfmodule + not validate(module) +} + +module_allow[module] := true if{ + some module in input.vfmodule + validate(module) +} + +validate(module) if { + module in data.node.blacklist.blacklist +} diff --git a/test/policies/cell/consistency/policy.rego b/test/policies/cell/consistency/policy.rego new file mode 100644 index 0000000..6137df7 --- /dev/null +++ b/test/policies/cell/consistency/policy.rego @@ -0,0 +1,17 @@ +package cell.consistency +import rego.v1 +default allow = false +# Rule to check cell consistency +check_cell_consistency if { + input.cell != data.node.cell.consistency.allowedCellId +} +# Rule to allow if PCI is within range 1-3000 +allow_if_pci_in_range if { + input.PCI >= data.node.cellconsistency.minPCI + input.PCI <= data.node.cellconsistency.maxPCI +} +# Main rule to determine the final decision +allow if{ + check_cell_consistency + allow_if_pci_in_range +} diff --git a/test/policies/cell/consistency/topology/policy.rego b/test/policies/cell/consistency/topology/policy.rego new file mode 100644 index 0000000..dccfac6 --- /dev/null +++ b/test/policies/cell/consistency/topology/policy.rego @@ -0,0 +1,6 @@ +package cell.consistency.topology +import rego.v1 +# Rule to check cell consistency +check_cell_consistency if { + input.cell != data.node.cell.consistency.allowedCellId +} diff --git a/test/policies/data/abac/data.json b/test/policies/data/abac/data.json deleted file mode 100644 index 77b5668..0000000 --- a/test/policies/data/abac/data.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "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/policies/data/account/data.json b/test/policies/data/account/data.json deleted file mode 100644 index df263d3..0000000 --- a/test/policies/data/account/data.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "account_attributes":{ - "11111":{ - "owner":"alice", - "amount":10000 - }, - "22222":{ - "owner":"bob", - "amount":10000 - }, - "33333":{ - "owner":"cam", - "amount":10000 - } - } -} diff --git a/test/policies/data/action/data.json b/test/policies/data/action/data.json deleted file mode 100644 index 99145b7..0000000 --- a/test/policies/data/action/data.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "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/policies/data/organization/data.json b/test/policies/data/organization/data.json deleted file mode 100644 index 35fe4a1..0000000 --- a/test/policies/data/organization/data.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "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/policies/data/role/data.json b/test/policies/data/role/data.json deleted file mode 100644 index 88ac41b..0000000 --- a/test/policies/data/role/data.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "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/policies/docs/policy.rego b/test/policies/docs/policy.rego deleted file mode 100644 index 90ce883..0000000 --- a/test/policies/docs/policy.rego +++ /dev/null @@ -1,22 +0,0 @@ -package docs - -import rego.v1 - -default allow := false - -allow if { - has_access_to_file - action_is_read_or_write -} - -action_is_read_or_write if { - input.action in ["read", "write"] -} - -has_access_to_file contains file_info if { - some file in data.docs.files - file.file_id == input.file_id - file.access_level == input.access_level - file_info := {attr: file[attr] | attr in input.attributes} -} - diff --git a/test/policies/monitor/policy.rego b/test/policies/monitor/policy.rego new file mode 100644 index 0000000..b3d9aaa --- /dev/null +++ b/test/policies/monitor/policy.rego @@ -0,0 +1,39 @@ +package monitor + +# Policy allows if a matching threshold is met +result contains output if { + input.domain = data.node.monitor.domain + some events in data.node.monitor.metricsPerEventName + events.eventName == input.eventName + events.controlLoopSchemaType == input.controlLoopSchemaType + events.policyScope == input.policyScope + events.policyName == input.policyName + events.policyVersion == input.policyVersion + some value in events.thresholds + input.controlname == value.closedLoopControlName + input.version == value.version + input.thresholdValue == value.thresholdValue + output := { + "severity" : "MAJOR", + "closedLoopEventStatus" : "ABATED" + } +} + +# Policy allows if a matching threshold is met +result contains output if { + input.domain = data.node.monitor.domain + some events in data.node.monitor.metricsPerEventName + events.eventName == input.eventName + events.controlLoopSchemaType == input.controlLoopSchemaType + events.policyScope == input.policyScope + events.policyName == input.policyName + events.policyVersion == input.policyVersion + some value in events.thresholds + input.controlname == value.closedLoopControlName + input.version == value.version + input.thresholdValue > value.thresholdValue + output := { + "severity" : "CRITICAL", + "closedLoopEventStatus" : "ONSET" + } +} diff --git a/test/policies/organization/policy.rego b/test/policies/organization/policy.rego deleted file mode 100644 index 31e7fb6..0000000 --- a/test/policies/organization/policy.rego +++ /dev/null @@ -1,38 +0,0 @@ -package organization - -import rego.v1 - -default allow := false - -# organization level access -allow if { - some acl in data.organization.acls - acl.user == input.user - acl.organization == input.organization - acl.project == input.project - acl.component == input.component - - some action in acl.actions - action == input.action -} - -# project level access -allow if { - some acl in data.organization.acls - acl.user == input.user - acl.organization == input.organization - acl.project == input.project - - some action in acl.actions - action == input.action -} - -# component level access -allow if { - some acl in data.organization.acls - acl.user == input.user - acl.organization == input.organization - - some action in acl.actions - action == input.action -} diff --git a/test/policies/vehicle/policy.rego b/test/policies/vehicle/policy.rego deleted file mode 100644 index 592afee..0000000 --- a/test/policies/vehicle/policy.rego +++ /dev/null @@ -1,23 +0,0 @@ -package vehicle - -import rego.v1 - -default allow := false - -allow if { - user_has_vehicle_access - action_is_granted -} - -action_is_granted if { - "use" in input.actions -} - -user_has_vehicle_access contains vehicle_data if { - some vehicle in data.vehicle.vehicles - vehicle.vehicle_id == input.vehicle_id - vehicle.owner == input.user - vehicle_data := {info: vehicle[info] | info in input.attributes} -} - - diff --git a/test/policies/zone/policy.rego b/test/policies/zone/policy.rego deleted file mode 100644 index 75357a6..0000000 --- a/test/policies/zone/policy.rego +++ /dev/null @@ -1,23 +0,0 @@ -package zone - -import rego.v1 - -default allow := false - -allow if { - has_zone_access - action_is_log_view -} - -action_is_log_view if { - "view" in input.actions -} - -has_zone_access contains access_data if { - some zone_data in data.zone.zone.zone_access_logs - zone_data.timestamp >= input.time_period.from - zone_data.timestamp < input.time_period.to - zone_data.zone_id == input.zone_id - access_data := {datatype: zone_data[datatype] | datatype in input.datatypes} -} - diff --git a/test/policy-new.yaml b/test/policy-new.yaml deleted file mode 100644 index 2fbcf79..0000000 --- a/test/policy-new.yaml +++ /dev/null @@ -1,21 +0,0 @@ -tosca_definitions_version: tosca_simple_yaml_1_1_0 -policy_types: - onap.policies.Native: - derived_from: tosca.policies.Root - description: a base policy type for all native PDP policies - version: 1.0.0 - name: onap.policies.Native - onap.policies.native.opa: - derived_from: onap.policies.Native - version: 1.0.0 - name: onap.policies.native.opa - description: a policy type for native opa policies - properties: - policy: - type: string - type_version: 0.0.0 - description: The rego PolicySet or Policy - required: true - metadata: - encoding: Base64 - diff --git a/test/scripts.sh b/test/scripts.sh deleted file mode 100755 index ab4f838..0000000 --- a/test/scripts.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Set up credentials and host variables -USER="policyadmin" -PASSWORD="zb!XztG34" -HOST="localhost" - -# Exit immediately if a command exits with a non-zero status -set -e - -# Step 1: Create a Policy -echo "Creating a new policy..." -sleep 40 -curl -u "$USER:$PASSWORD" --header "Content-Type: application/yaml" \ - -X POST --data-binary @policy-new.yaml \ - http://policy-api:6969/policy/api/v1/policytypes -echo "Policy created successfully. Check policy-api logs for details." - -# Step 2: Create Groups -echo "Creating groups..." -curl -u "$USER:$PASSWORD" --header "Content-Type: application/json" \ - -X POST --data-binary @Opagroup.json \ - http://policy-pap:6969/policy/pap/v1/pdps/groups/batch - -echo "Groups created successfully. Check policy-pap logs for details." - -echo "Script execution completed." diff --git a/test/scripts.txt b/test/scripts.txt deleted file mode 100644 index 3d60d4a..0000000 --- a/test/scripts.txt +++ /dev/null @@ -1,21 +0,0 @@ - curl -u 'policyadmin:zb!XztG34' --header "Content-Type:application/yaml" -X POST --data-binary @policy-new.yaml http://localhost:30002/policy/api/v1/policytypes - -# policy-new.yaml is inside test directory to create policy -#check policy-api logs - - -//Create Groups - -curl -u 'policyadmin:zb!XztG34' --header "Content-Type:application/json" -X POST --data-binary @Opagroup.json http://localhost:30003/policy/pap/v1/pdps/groups/batch - -#Check policy-pap logs -#file Opagroup.json is inside test - -// Sends registration message to policy-pdp-pap - -docker exec -it kafka /bin/sh - -echo '{"messageName": "PDP_STATUS", "requestId": "e9b4ee77-5400-41a8-87ba-3c914a86ee08", "timestampMs": "1728551661460","name": "opa-2e953ecf-40f1-47f7-8a5e-53031947516c","pdpGroup": "opaGroup","pdpSubgroup": null, "pdpType": "opa","state": "PASSIVE","healthy": "HEALTHY", "description": null, "policies": []}' | kafka-console-producer --broker-list kafka:9092 --topic policy-pdp-pap - - -#To get Gracefulshutdown signals commented command and changed entrypoint to /app/opa-pdp diff --git a/test/test_resources/policy_collab.yaml b/test/test_resources/policy_collab.yaml deleted file mode 100644 index fe4fc12..0000000 --- a/test/test_resources/policy_collab.yaml +++ /dev/null @@ -1,18 +0,0 @@ -tosca_definitions_version: tosca_simple_yaml_1_1_0 -topology_template: - policies: - - collab: - type: onap.policies.native.opa - type_version: 1.0.0 - properties: - data: - node.collab.action: ewogICAgInVzZXJfcm9sZXMiOiB7CiAgICAgICAgImFsaWNlIjogWwogICAgICAgICAgICAiYWRtaW4iCiAgICAgICAgXSwKICAgICAgICAiYm9iIjogWwogICAgICAgICAgICAiZWRpdG9yIgogICAgICAgIF0sCiAgICAgICAgImNoYXJsaWUiOiBbCiAgICAgICAgICAgICJ2aWV3ZXIiCiAgICAgICAgXQogICAgfSwKICAgICJyb2xlX3Blcm1pc3Npb25zIjogewogICAgICAgICJhZG1pbiI6IHsKICAgICAgICAgICAgImFjdGlvbnMiOiBbCiAgICAgICAgICAgICAgICAicmVhZCIsCiAgICAgICAgICAgICAgICAid3JpdGUiLAogICAgICAgICAgICAgICAgImRlbGV0ZSIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgInJlc291cmNlcyI6IFsKICAgICAgICAgICAgICAgICJzZXJ2ZXIiLAogICAgICAgICAgICAgICAgImRhdGFiYXNlIgogICAgICAgICAgICBdCiAgICAgICAgfSwKICAgICAgICAiZWRpdG9yIjogewogICAgICAgICAgICAiYWN0aW9ucyI6IFsKICAgICAgICAgICAgICAgICJyZWFkIiwKICAgICAgICAgICAgICAgICJ3cml0ZSIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgInJlc291cmNlcyI6IFsKICAgICAgICAgICAgICAgICJzZXJ2ZXIiCiAgICAgICAgICAgIF0KICAgICAgICB9LAogICAgICAgICJ2aWV3ZXIiOiB7CiAgICAgICAgICAgICJhY3Rpb25zIjogWwogICAgICAgICAgICAgICAgInJlYWQiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJyZXNvdXJjZXMiOiBbCiAgICAgICAgICAgICAgICAic2VydmVyIgogICAgICAgICAgICBdCiAgICAgICAgfQogICAgfQp9 - policy: - collab.conflict: cGFja2FnZSBjb2xsYWIuY29uZmxpY3QKCmltcG9ydCByZWdvLnYxCgphbGxvdyBpZiB7IGlucHV0Lm5hbWUgPT0gImFsaWNlIiB9CmRlbnkgaWYgeyBpbnB1dC5uYW1lID09ICJhbGljZSIgfQoKIyBkZW55IGV2ZXJ5dGhpbmcgYnkgZGVmYXVsdApkZWZhdWx0IGF1dGh6IDo9IGZhbHNlCgojIGRlbnkgb3ZlcnJpZGVzIGFsbG93CmF1dGh6IGlmIHsKICAgIGFsbG93CiAgICBub3QgZGVueQp9Cg== - collab.action: cGFja2FnZSBjb2xsYWIuYWN0aW9uCgppbXBvcnQgcmVnby52MQoKIyBCeSBkZWZhdWx0LCBkZW55IHJlcXVlc3RzLgpkZWZhdWx0IGFsbG93IDo9IGZhbHNlCgoKIyBBbGxvdyB0aGUgYWN0aW9uIGlmIGFkbWluIHJvbGUgaXMgZ3JhbnRlZCBwZXJtaXNzaW9uIHRvIHBlcmZvcm0gdGhlIGFjdGlvbi4KYWxsb3cgaWYgewogICAgc29tZSBpCiAgICBkYXRhLm5vZGUuY29sbGFiLmFjdGlvbi51c2VyX3JvbGVzW2lucHV0LnVzZXJdW2ldID09IHJvbGUKICAgIHNvbWUgagogICAgZGF0YS5ub2RlLmNvbGxhYi5hY3Rpb24ucm9sZV9wZXJtaXNzaW9uc1tyb2xlXS5hY3Rpb25zW2pdID09IGlucHV0LmFjdGlvbgogICAgc29tZSBrCiAgICBkYXRhLm5vZGUuY29sbGFiLmFjdGlvbi5yb2xlX3Blcm1pc3Npb25zW3JvbGVdLnJlc291cmNlc1trXSA9PSBpbnB1dC50eXBlCn0KIyAgICAgICAqIFJlZ28gY29tcGFyaXNvbiB0byBvdGhlciBzeXN0ZW1zOiBodHRwczovL3d3dy5vcGVucG9saWN5YWdlbnQub3JnL2RvY3MvbGF0ZXN0L2NvbXBhcmlzb24tdG8tb3RoZXItc3lzdGVtcy8KIyAgICAgICAqIFJlZ28gSXRlcmF0aW9uOiBodHRwczovL3d3dy5vcGVucG9saWN5YWdlbnQub3JnL2RvY3MvbGF0ZXN0LyNpdGVyYXRpb24= - collab: cGFja2FnZSBjb2xsYWIKCmltcG9ydCByZWdvLnYxCmltcG9ydCBkYXRhLmNvbGxhYi5jb25mbGljdAppbXBvcnQgZGF0YS5jb2xsYWIuYWN0aW9uCgpkZWZhdWx0IGFsbG93IDo9IGZhbHNlCmFsbG93IGlmIHsKICAgIGNvbmZsaWN0LmFsbG93CiAgICBhY3Rpb24uYWxsb3cKfQ== - name: collab - version: 1.0.0 - metadata: - policy-id: collab - policy-version: 1.0.0 diff --git a/test/test_resources/policy_conflict.yaml b/test/test_resources/policy_conflict.yaml deleted file mode 100644 index 0406179..0000000 --- a/test/test_resources/policy_conflict.yaml +++ /dev/null @@ -1,15 +0,0 @@ -tosca_definitions_version: tosca_simple_yaml_1_1_0 -topology_template: - policies: - - conflict: - type: onap.policies.native.opa - type_version: 1.0.0 - properties: - data: - policy: - conflict: cGFja2FnZSBjb25mbGljdAoKaW1wb3J0IHJlZ28udjEKCmFsbG93IGlmIHsgaW5wdXQubmFtZSA9PSAiYWxpY2UiIH0KZGVueSBpZiB7IGlucHV0Lm5hbWUgPT0gImFsaWNlIiB9CgojIGRlbnkgZXZlcnl0aGluZyBieSBkZWZhdWx0CmRlZmF1bHQgYXV0aHogOj0gZmFsc2UKCiMgZGVueSBvdmVycmlkZXMgYWxsb3cKYXV0aHogaWYgewogICAgYWxsb3cKICAgIG5vdCBkZW55Cn0KCg== - name: conflict - version: 1.0.0 - metadata: - policy-id: conflict - policy-version: 1.0.0 diff --git a/test/test_resources/policy_deploy_single_policy.yaml b/test/test_resources/policy_deploy_single_policy.yaml deleted file mode 100644 index a2116fe..0000000 --- a/test/test_resources/policy_deploy_single_policy.yaml +++ /dev/null @@ -1,17 +0,0 @@ -tosca_definitions_version: tosca_simple_yaml_1_1_0 -topology_template: - policies: - - role: - type: onap.policies.native.opa - type_version: 1.0.0 - properties: - data: - node.role: ewogICAgInVzZXJfcm9sZXMiOiB7CiAgICAgICAgImFsaWNlIjogWwogICAgICAgICAgICAiYWRtaW4iCiAgICAgICAgXSwKICAgICAgICAiYm9iIjogWwogICAgICAgICAgICAiZW1wbG95ZWUiLAogICAgICAgICAgICAiYmlsbGluZyIKICAgICAgICBdLAogICAgICAgICJldmUiOiBbCiAgICAgICAgICAgICJjdXN0b21lciIKICAgICAgICBdCiAgICB9LAogICAgInJvbGVfZ3JhbnRzIjogewogICAgICAgICJjdXN0b21lciI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImNhdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJhZG9wdCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAiYWRvcHQiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiZW1wbG95ZWUiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjYXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJ1cGRhdGUiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiYmlsbGluZyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cn0K - policy: - role: cGFja2FnZSByb2xlCgppbXBvcnQgcmVnby52MQoKIyBCeSBkZWZhdWx0LCBkZW55IHJlcXVlc3RzLgpkZWZhdWx0IGFsbG93IDo9IGZhbHNlCgojIEFsbG93IGFkbWlucyB0byBkbyBhbnl0aGluZy4KYWxsb3cgaWYgdXNlcl9pc19hZG1pbgoKIyBBbGxvdyB0aGUgYWN0aW9uIGlmIHRoZSB1c2VyIGlzIGdyYW50ZWQgcGVybWlzc2lvbiB0byBwZXJmb3JtIHRoZSBhY3Rpb24uCmFsbG93IGlmIHsKICAgICAgICAjIEZpbmQgZ3JhbnRzIGZvciB0aGUgdXNlci4KICAgICAgICBzb21lIGdyYW50IGluIHVzZXJfaXNfZ3JhbnRlZAoKICAgICAgICAjIENoZWNrIGlmIHRoZSBncmFudCBwZXJtaXRzIHRoZSBhY3Rpb24uCiAgICAgICAgaW5wdXQuYWN0aW9uID09IGdyYW50LmFjdGlvbgogICAgICAgIGlucHV0LnR5cGUgPT0gZ3JhbnQudHlwZQp9CgojIHVzZXJfaXNfYWRtaW4gaXMgdHJ1ZSBpZiAiYWRtaW4iIGlzIGFtb25nIHRoZSB1c2VyJ3Mgcm9sZXMgYXMgcGVyIGRhdGEudXNlcl9yb2xlcwp1c2VyX2lzX2FkbWluIGlmICJhZG1pbiIgaW4gZGF0YS5ub2RlLnJvbGUudXNlcl9yb2xlc1tpbnB1dC51c2VyXQoKIyB1c2VyX2lzX2dyYW50ZWQgaXMgYSBzZXQgb2YgZ3JhbnRzIGZvciB0aGUgdXNlciBpZGVudGlmaWVkIGluIHRoZSByZXF1ZXN0LgojIFRoZSBgZ3JhbnRgIHdpbGwgYmUgY29udGFpbmVkIGlmIHRoZSBzZXQgYHVzZXJfaXNfZ3JhbnRlZGAgZm9yIGV2ZXJ5Li4uCnVzZXJfaXNfZ3JhbnRlZCBjb250YWlucyBncmFudCBpZiB7CiAgICAgICAgIyBgcm9sZWAgYXNzaWduZWQgYW4gZWxlbWVudCBvZiB0aGUgdXNlcl9yb2xlcyBmb3IgdGhpcyB1c2VyLi4uCiAgICAgICAgc29tZSByb2xlIGluIGRhdGEubm9kZS5yb2xlLnVzZXJfcm9sZXNbaW5wdXQudXNlcl0KCiAgICAgICAgIyBgZ3JhbnRgIGFzc2lnbmVkIGEgc2luZ2xlIGdyYW50IGZyb20gdGhlIGdyYW50cyBsaXN0IGZvciAncm9sZScuLi4KICAgICAgICBzb21lIGdyYW50IGluIGRhdGEubm9kZS5yb2xlLnJvbGVfZ3JhbnRzW3JvbGVdCn0KCiMgICAgICAgKiBSZWdvIGNvbXBhcmlzb24gdG8gb3RoZXIgc3lzdGVtczogaHR0cHM6Ly93d3cub3BlbnBvbGljeWFnZW50Lm9yZy9kb2NzL2xhdGVzdC9jb21wYXJpc29uLXRvLW90aGVyLXN5c3RlbXMvCiMgICAgICAgKiBSZWdvIEl0ZXJhdGlvbjogaHR0cHM6Ly93d3cub3BlbnBvbGljeWFnZW50Lm9yZy9kb2NzL2xhdGVzdC8jaXRlcmF0aW9u - name: role - version: 1.0.0 - metadata: - policy-id: role - policy-version: 1.0.0 - diff --git a/test/test_resources/policy_zone.yaml b/test/test_resources/policy_zone.yaml deleted file mode 100644 index 2c99e9f..0000000 --- a/test/test_resources/policy_zone.yaml +++ /dev/null @@ -1,16 +0,0 @@ -tosca_definitions_version: tosca_simple_yaml_1_1_0 -topology_template: - policies: - - zone: - type: onap.policies.native.opa - type_version: 1.0.0 - properties: - data: - node.zone: ewogICJ6b25lIjogewogICAgInpvbmVfYWNjZXNzX2xvZ3MiOiBbCiAgICAgIHsgImxvZ19pZCI6ICJsb2cxIiwgInRpbWVzdGFtcCI6ICIyMDI0LTExLTAxVDA5OjAwOjAwWiIsICJ6b25lX2lkIjogInpvbmVBIiwgImFjY2VzcyI6ICJncmFudGVkIiwgInVzZXIiOiAidXNlcjEiIH0sCiAgICAgIHsgImxvZ19pZCI6ICJsb2cyIiwgInRpbWVzdGFtcCI6ICIyMDI0LTExLTAxVDEwOjMwOjAwWiIsICJ6b25lX2lkIjogInpvbmVBIiwgImFjY2VzcyI6ICJkZW5pZWQiLCAidXNlciI6ICJ1c2VyMiIgfSwKICAgICAgeyAibG9nX2lkIjogImxvZzMiLCAidGltZXN0YW1wIjogIjIwMjQtMTEtMDFUMTE6MDA6MDBaIiwgInpvbmVfaWQiOiAiem9uZUIiLCAiYWNjZXNzIjogImdyYW50ZWQiLCAidXNlciI6ICJ1c2VyMyIgfQogICAgXQogIH0KfQo= - policy: - zone : cGFja2FnZSB6b25lCgppbXBvcnQgcmVnby52MQoKZGVmYXVsdCBhbGxvdyA6PSBmYWxzZQoKYWxsb3cgaWYgewogICAgaGFzX3pvbmVfYWNjZXNzCiAgICBhY3Rpb25faXNfbG9nX3ZpZXcKfQoKYWN0aW9uX2lzX2xvZ192aWV3IGlmIHsKICAgICJ2aWV3IiBpbiBpbnB1dC5hY3Rpb25zCn0KCmhhc196b25lX2FjY2VzcyBjb250YWlucyBhY2Nlc3NfZGF0YSBpZiB7CiAgICBzb21lIHpvbmVfZGF0YSBpbiBkYXRhLm5vZGUuem9uZS56b25lLnpvbmVfYWNjZXNzX2xvZ3MKICAgIHpvbmVfZGF0YS50aW1lc3RhbXAgPj0gaW5wdXQudGltZV9wZXJpb2QuZnJvbQogICAgem9uZV9kYXRhLnRpbWVzdGFtcCA8IGlucHV0LnRpbWVfcGVyaW9kLnRvCiAgICB6b25lX2RhdGEuem9uZV9pZCA9PSBpbnB1dC56b25lX2lkCiAgICBhY2Nlc3NfZGF0YSA6PSB7ZGF0YXR5cGU6IHpvbmVfZGF0YVtkYXRhdHlwZV0gfCBkYXRhdHlwZSBpbiBpbnB1dC5kYXRhdHlwZXN9Cn0K - name: zone - version: 1.0.0 - metadata: - policy-id: zone - policy-version: 1.0.0 diff --git a/test/test_resources/undeploy_batch_delete.json b/test/test_resources/undeploy_batch_delete.json deleted file mode 100644 index 9195f74..0000000 --- a/test/test_resources/undeploy_batch_delete.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "groups": [ - { - "name": "opaGroup", - "deploymentSubgroups": [ - { - "pdpType": "opa", - "action": "DELETE", - "policies": [ - { - "name": "account", - "version": "1.0.0" - }, - { - "name": "organization", - "version": "1.0.0" - } - ] - } - ] - } - ] -} diff --git a/test/test_resources/deploy_collab.json b/test/toscapolicies/access_method/deploy_access_method.json similarity index 66% rename from test/test_resources/deploy_collab.json rename to test/toscapolicies/access_method/deploy_access_method.json index 06d43c9..4903c65 100644 --- a/test/test_resources/deploy_collab.json +++ b/test/toscapolicies/access_method/deploy_access_method.json @@ -1,7 +1,7 @@ { "policies": [ { - "policy-id": "collab", + "policy-id": "access_method", "policy-version": "1.0.0" } diff --git a/test/toscapolicies/access_method/policy_access_method.yaml b/test/toscapolicies/access_method/policy_access_method.yaml new file mode 100644 index 0000000..9b48637 --- /dev/null +++ b/test/toscapolicies/access_method/policy_access_method.yaml @@ -0,0 +1,15 @@ +tosca_definitions_version: tosca_simple_yaml_1_1_0 +topology_template: + policies: + - access_method: + type: onap.policies.native.opa + type_version: 1.0.0 + properties: + data: + policy: + access_method: cGFja2FnZSBhY2Nlc3NfbWV0aG9kCmltcG9ydCByZWdvLnYxCmFsbG93IGlmIHsKICAgICAgICBpbnB1dC5wYXRoID09IFsidXNlcnMiXQogICAgICAgIGlucHV0Lm1ldGhvZCA9PSAiUE9TVCIKfQoKYWxsb3cgaWYgewogICAgICAgIGlucHV0LnBhdGggPT0gWyJ1c2VycyIsIGlucHV0LnVzZXJfaWRdCiAgICAgICAgaW5wdXQubWV0aG9kID09ICJHRVQiCn0KCg== + name: access_method + version: 1.0.0 + metadata: + policy-id: access_method + policy-version: 1.0.0 diff --git a/test/test_resources/deploy_conflict.json b/test/toscapolicies/blacklist/deploy_blacklist.json similarity index 68% rename from test/test_resources/deploy_conflict.json rename to test/toscapolicies/blacklist/deploy_blacklist.json index 72d2fcd..8daa958 100644 --- a/test/test_resources/deploy_conflict.json +++ b/test/toscapolicies/blacklist/deploy_blacklist.json @@ -1,7 +1,7 @@ { "policies": [ { - "policy-id": "conflict", + "policy-id": "blacklist", "policy-version": "1.0.0" } diff --git a/test/toscapolicies/blacklist/policy_blacklist.yaml b/test/toscapolicies/blacklist/policy_blacklist.yaml new file mode 100644 index 0000000..2e2b15c --- /dev/null +++ b/test/toscapolicies/blacklist/policy_blacklist.yaml @@ -0,0 +1,18 @@ +tosca_definitions_version: tosca_simple_yaml_1_1_0 +topology_template: + policies: + - blacklist: + type: onap.policies.native.opa + type_version: 1.0.0 + properties: + data: + node.blacklist: ewogICAgImJsYWNrbGlzdCIgOiBbCiAgICAidGhlLXZmbW9kdWxlLXdoZXJlLXJvb3QtaXMtdHJ1ZSIsCiAgICAgImFub3RoZXItdmZtb2R1bGUtd2hlcmUtcm9vdC1pcy10cnVlIgpdCn0= + policy: + blacklist: + cGFja2FnZSBibGFja2xpc3QKaW1wb3J0IGZ1dHVyZS5rZXl3b3Jkcy5pbgppbXBvcnQgcmVnby52MQoKIyBEZWZpbmUgYSBydWxlIHRvIGNoZWNrIGlmIHRoZSBvcGVyYXRpb24gc2hvdWxkIGJlIGFsbG93ZWQKbW9kdWxlX2FsbG93W21vZHVsZV0gOj0gZmFsc2UgaWYgewogICAgc29tZSBtb2R1bGUgaW4gaW5wdXQudmZtb2R1bGUKICAgIG5vdCB2YWxpZGF0ZShtb2R1bGUpCn0KCm1vZHVsZV9hbGxvd1ttb2R1bGVdIDo9IHRydWUgaWZ7CiAgICAgICAgc29tZSBtb2R1bGUgaW4gaW5wdXQudmZtb2R1bGUKICAgIHZhbGlkYXRlKG1vZHVsZSkKfQoKdmFsaWRhdGUobW9kdWxlKSBpZiB7CiAgICAgICAgbW9kdWxlIGluIGRhdGEubm9kZS5ibGFja2xpc3QuYmxhY2tsaXN0Cn0= + name: blacklist + version: 1.0.0 + metadata: + policy-id: blacklist + policy-version: 1.0.0 + diff --git a/test/toscapolicies/cell/deploy_cell.json b/test/toscapolicies/cell/deploy_cell.json new file mode 100644 index 0000000..75a25bd --- /dev/null +++ b/test/toscapolicies/cell/deploy_cell.json @@ -0,0 +1,10 @@ +{ + "policies": [ + { + "policy-id": "cell.consistency", + "policy-version": "1.0.0" + + } + ] +} + diff --git a/test/toscapolicies/cell/policy_cell.yaml b/test/toscapolicies/cell/policy_cell.yaml new file mode 100644 index 0000000..3ab25db --- /dev/null +++ b/test/toscapolicies/cell/policy_cell.yaml @@ -0,0 +1,21 @@ +tosca_definitions_version: tosca_simple_yaml_1_1_0 +topology_template: + policies: + - cell.consistency: + type: onap.policies.native.opa + type_version: 1.0.0 + properties: + data: + node.cell.consistency: >- + eyAgIAogICJhbGxvd2VkQ2VsbElkIiA6IDQ0NTYxMTE5MzI2NTA0MDEyOSwgCiAgIm1pblBDSSI6IDEsIAogICJtYXhQQ0kiOiAzMDAwICAKIH0= + policy: + cell.consistency: >- + cGFja2FnZSBjZWxsLmNvbnNpc3RlbmN5CmRlZmF1bHQgYWxsb3cgPSBmYWxzZQojIFJ1bGUgdG8gY2hlY2sgY2VsbCBjb25zaXN0ZW5jeQpjaGVja19jZWxsX2NvbnNpc3RlbmN5IGlmIHsKICAgIGlucHV0LmNlbGwgIT0gZGF0YS5ub2RlLmNlbGwuY29uc2lzdGVuY3kuYWxsb3dlZENlbGxJZAp9CiMgUnVsZSB0byBhbGxvdyBpZiBQQ0kgaXMgd2l0aGluIHJhbmdlIDEtMzAwMAphbGxvd19pZl9wY2lfaW5fcmFuZ2UgaWYgewogICAgaW5wdXQuUENJID49IGRhdGEubm9kZS5jZWxsY29uc2lzdGVuY3kubWluUENJCiAgICBpbnB1dC5QQ0kgPD0gZGF0YS5ub2RlLmNlbGxjb25zaXN0ZW5jeS5tYXhQQ0kKfQojIE1haW4gcnVsZSB0byBkZXRlcm1pbmUgdGhlIGZpbmFsIGRlY2lzaW9uCmFsbG93IGlmIHsKICAgIGNoZWNrX2NlbGxfY29uc2lzdGVuY3kKICAgIGFsbG93X2lmX3BjaV9pbl9yYW5nZQp9 + cell.consistency.topology: >- + cGFja2FnZSBjZWxsLmNvbnNpc3RlbmN5LnRvcG9sb2d5CmltcG9ydCByZWdvLnYxCiMgUnVsZSB0byBjaGVjayBjZWxsIGNvbnNpc3RlbmN5CmNoZWNrX2NlbGxfY29uc2lzdGVuY3kgaWYgewogICAgaW5wdXQuY2VsbCAhPSBkYXRhLmNlbGxjb25zaXN0ZW5jeS5hbGxvd2VkQ2VsbElkCn0= + name: cell.consistency + version: 1.0.0 + metadata: + policy-id: cell.consistency + policy-version: 1.0.0 + diff --git a/test/test_resources/deploy_zone.json b/test/toscapolicies/monitor/deploy_monitor.json similarity index 69% rename from test/test_resources/deploy_zone.json rename to test/toscapolicies/monitor/deploy_monitor.json index 217457b..55a60cf 100644 --- a/test/test_resources/deploy_zone.json +++ b/test/toscapolicies/monitor/deploy_monitor.json @@ -1,8 +1,7 @@ - { "policies": [ { - "policy-id": "zone", + "policy-id": "monitor", "policy-version": "1.0.0" } diff --git a/test/toscapolicies/monitor/policy_monitor.yaml b/test/toscapolicies/monitor/policy_monitor.yaml new file mode 100644 index 0000000..1dcc7ee --- /dev/null +++ b/test/toscapolicies/monitor/policy_monitor.yaml @@ -0,0 +1,16 @@ +tosca_definitions_version: tosca_simple_yaml_1_1_0 +topology_template: + policies: + - monitor: + type: onap.policies.native.opa + type_version: 1.0.0 + properties: + data: + node.monitor: eyAiZG9tYWluIjogIm1lYXN1cmVtZW50c0ZvclZmU2NhbGluZyIsCiAgIm1ldHJpY3NQZXJFdmVudE5hbWUiOiBbewogICAgICAgICAgImV2ZW50TmFtZSI6ICJNZWFzdXJlbWVudF92R01VWCIsCiAgICAgICAgICAiY29udHJvbExvb3BTY2hlbWFUeXBlIjogIlZORiIsCiAgICAgICAgICAicG9saWN5U2NvcGUiOiAiRENBRSIsCiAgICAgICAgICAicG9saWN5TmFtZSI6ICJEQ0FFLkNvbmZpZ190Y2EtaGktbG8iLAogICAgICAgICAgICJwb2xpY3lWZXJzaW9uIjogInYwLjAuMSIsCiAgICAgICAgICAgInRocmVzaG9sZHMiIDogW3sidmVyc2lvbiI6ICIxLjAuMiIsCiAgICAgICAgICAgICJjbG9zZWRMb29wQ29udHJvbE5hbWUiOiAiQ29udHJvbExvb3AtdkNQRS00OGYwYzJjMy1hMTcyLTQxOTItOWFlMy0wNTIyNzQxODFiNmUiLAogICAgICAgICAgICAidGhyZXNob2xkVmFsdWUiOiAwCiAgICAgICAgICAgICB9XQp9XQp9 + policy: + monitor: cGFja2FnZSBtb25pdG9yCgojIFBvbGljeSBhbGxvd3MgaWYgYSBtYXRjaGluZyB0aHJlc2hvbGQgaXMgbWV0CnJlc3VsdCBjb250YWlucyBvdXRwdXQgaWYgewogICAgaW5wdXQuZG9tYWluID0gZGF0YS5ub2RlLm1vbml0b3IuZG9tYWluCiAgICBzb21lIGV2ZW50cyAgaW4gZGF0YS5ub2RlLm1vbml0b3IubWV0cmljc1BlckV2ZW50TmFtZQogICAgZXZlbnRzLmV2ZW50TmFtZSA9PSBpbnB1dC5ldmVudE5hbWUKICAgIGV2ZW50cy5jb250cm9sTG9vcFNjaGVtYVR5cGUgPT0gaW5wdXQuY29udHJvbExvb3BTY2hlbWFUeXBlCiAgICBldmVudHMucG9saWN5U2NvcGUgPT0gaW5wdXQucG9saWN5U2NvcGUKICAgIGV2ZW50cy5wb2xpY3lOYW1lID09IGlucHV0LnBvbGljeU5hbWUKICAgIGV2ZW50cy5wb2xpY3lWZXJzaW9uID09IGlucHV0LnBvbGljeVZlcnNpb24KICAgIHNvbWUgdmFsdWUgaW4gZXZlbnRzLnRocmVzaG9sZHMKICAgIGlucHV0LmNvbnRyb2xuYW1lID09IHZhbHVlLmNsb3NlZExvb3BDb250cm9sTmFtZQogICAgaW5wdXQudmVyc2lvbiA9PSB2YWx1ZS52ZXJzaW9uCiAgICBpbnB1dC50aHJlc2hvbGRWYWx1ZSA9PSB2YWx1ZS50aHJlc2hvbGRWYWx1ZQogICAgb3V0cHV0IDo9IHsKICAgICAgICAic2V2ZXJpdHkiIDogIk1BSk9SIiwKICAgICAgICAiY2xvc2VkTG9vcEV2ZW50U3RhdHVzIiA6ICJBQkFURUQiCiAgICAgICAgfQp9CgojIFBvbGljeSBhbGxvd3MgaWYgYSBtYXRjaGluZyB0aHJlc2hvbGQgaXMgbWV0CnJlc3VsdCBjb250YWlucyBvdXRwdXQgaWYgewogICAgaW5wdXQuZG9tYWluID0gZGF0YS5ub2RlLm1vbml0b3IuZG9tYWluCiAgICBzb21lIGV2ZW50cyAgaW4gZGF0YS5ub2RlLm1vbml0b3IubWV0cmljc1BlckV2ZW50TmFtZQogICAgZXZlbnRzLmV2ZW50TmFtZSA9PSBpbnB1dC5ldmVudE5hbWUKICAgIGV2ZW50cy5jb250cm9sTG9vcFNjaGVtYVR5cGUgPT0gaW5wdXQuY29udHJvbExvb3BTY2hlbWFUeXBlCiAgICBldmVudHMucG9saWN5U2NvcGUgPT0gaW5wdXQucG9saWN5U2NvcGUKICAgIGV2ZW50cy5wb2xpY3lOYW1lID09IGlucHV0LnBvbGljeU5hbWUKICAgIGV2ZW50cy5wb2xpY3lWZXJzaW9uID09IGlucHV0LnBvbGljeVZlcnNpb24KICAgIHNvbWUgdmFsdWUgaW4gZXZlbnRzLnRocmVzaG9sZHMKICAgIGlucHV0LmNvbnRyb2xuYW1lID09IHZhbHVlLmNsb3NlZExvb3BDb250cm9sTmFtZQogICAgaW5wdXQudmVyc2lvbiA9PSB2YWx1ZS52ZXJzaW9uCiAgICBpbnB1dC50aHJlc2hvbGRWYWx1ZSA+IHZhbHVlLnRocmVzaG9sZFZhbHVlCiAgICBvdXRwdXQgOj0gewogICAgICAgICJzZXZlcml0eSIgOiAiQ1JJVElDQUwiLAogICAgICAgICJjbG9zZWRMb29wRXZlbnRTdGF0dXMiIDogIk9OU0VUIgogICAgICAgIH0KfQ== + name: monitor + version: 1.0.0 + metadata: + policy-id: monitor + policy-version: 1.0.0 diff --git a/test/test_resources/deploy.json b/test/toscapolicies/role/deploy_role.json similarity index 100% rename from test/test_resources/deploy.json rename to test/toscapolicies/role/deploy_role.json diff --git a/test/toscapolicies/role/policy_role.yaml b/test/toscapolicies/role/policy_role.yaml new file mode 100644 index 0000000..aeb0da5 --- /dev/null +++ b/test/toscapolicies/role/policy_role.yaml @@ -0,0 +1,16 @@ +tosca_definitions_version: tosca_simple_yaml_1_1_0 +topology_template: + policies: + - role: + type: onap.policies.native.opa + type_version: 1.0.0 + properties: + data: + node.role: ewogICAgInVzZXJfcm9sZXMiOiB7CiAgICAgICAgImFsaWNlIjogWwogICAgICAgICAgICAiYWRtaW4iCiAgICAgICAgXSwKICAgICAgICAiYm9iIjogWwogICAgICAgICAgICAiZW1wbG95ZWUiLAogICAgICAgICAgICAiYmlsbGluZyIKICAgICAgICBdLAogICAgICAgICJldmUiOiBbCiAgICAgICAgICAgICJjdXN0b21lciIKICAgICAgICBdCiAgICB9LAogICAgInJvbGVfZ3JhbnRzIjogewogICAgICAgICJjdXN0b21lciI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImNhdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJhZG9wdCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAiYWRvcHQiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiZW1wbG95ZWUiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjYXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJ1cGRhdGUiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiYmlsbGluZyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cn0KCg== + policy: + role : cGFja2FnZSByb2xlCgppbXBvcnQgcmVnby52MQoKIyBCeSBkZWZhdWx0LCBkZW55IHJlcXVlc3RzLgpkZWZhdWx0IGFsbG93IDo9IGZhbHNlCgojIEFsbG93IGFkbWlucyB0byBkbyBhbnl0aGluZy4KYWxsb3cgaWYgdXNlcl9pc19hZG1pbgoKIyBBbGxvdyB0aGUgYWN0aW9uIGlmIHRoZSB1c2VyIGlzIGdyYW50ZWQgcGVybWlzc2lvbiB0byBwZXJmb3JtIHRoZSBhY3Rpb24uCmFsbG93IGlmIHsKICAgICAgICAjIEZpbmQgZ3JhbnRzIGZvciB0aGUgdXNlci4KICAgICAgICBzb21lIGdyYW50IGluIHVzZXJfaXNfZ3JhbnRlZAoKICAgICAgICAjIENoZWNrIGlmIHRoZSBncmFudCBwZXJtaXRzIHRoZSBhY3Rpb24uCiAgICAgICAgaW5wdXQuYWN0aW9uID09IGdyYW50LmFjdGlvbgogICAgICAgIGlucHV0LnR5cGUgPT0gZ3JhbnQudHlwZQp9CgojIHVzZXJfaXNfYWRtaW4gaXMgdHJ1ZSBpZiAiYWRtaW4iIGlzIGFtb25nIHRoZSB1c2VyJ3Mgcm9sZXMgYXMgcGVyIGRhdGEudXNlcl9yb2xlcwp1c2VyX2lzX2FkbWluIGlmICJhZG1pbiIgaW4gZGF0YS5ub2RlLnJvbGUudXNlcl9yb2xlc1tpbnB1dC51c2VyXQoKIyB1c2VyX2lzX2dyYW50ZWQgaXMgYSBzZXQgb2YgZ3JhbnRzIGZvciB0aGUgdXNlciBpZGVudGlmaWVkIGluIHRoZSByZXF1ZXN0LgojIFRoZSBgZ3JhbnRgIHdpbGwgYmUgY29udGFpbmVkIGlmIHRoZSBzZXQgYHVzZXJfaXNfZ3JhbnRlZGAgZm9yIGV2ZXJ5Li4uCnVzZXJfaXNfZ3JhbnRlZCBjb250YWlucyBncmFudCBpZiB7CiAgICAgICAgIyBgcm9sZWAgYXNzaWduZWQgYW4gZWxlbWVudCBvZiB0aGUgdXNlcl9yb2xlcyBmb3IgdGhpcyB1c2VyLi4uCiAgICAgICAgc29tZSByb2xlIGluIGRhdGEubm9kZS5yb2xlLnVzZXJfcm9sZXNbaW5wdXQudXNlcl0KCiAgICAgICAgIyBgZ3JhbnRgIGFzc2lnbmVkIGEgc2luZ2xlIGdyYW50IGZyb20gdGhlIGdyYW50cyBsaXN0IGZvciAncm9sZScuLi4KICAgICAgICBzb21lIGdyYW50IGluIGRhdGEubm9kZS5yb2xlLnJvbGVfZ3JhbnRzW3JvbGVdCn0KCiMgICAgICAgKiBSZWdvIGNvbXBhcmlzb24gdG8gb3RoZXIgc3lzdGVtczogaHR0cHM6Ly93d3cub3BlbnBvbGljeWFnZW50Lm9yZy9kb2NzL2xhdGVzdC9jb21wYXJpc29uLXRvLW90aGVyLXN5c3RlbXMvCiMgICAgICAgKiBSZWdvIEl0ZXJhdGlvbjogaHR0cHM6Ly93d3cub3BlbnBvbGljeWFnZW50Lm9yZy9kb2NzL2xhdGVzdC8jaXRlcmF0aW9uCg== + name: role + version: 1.0.0 + metadata: + policy-id: role + policy-version: 1.0.0 diff --git a/test/wait_for_port.sh b/test/wait_for_port.sh deleted file mode 100644 index b29102b..0000000 --- a/test/wait_for_port.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -# ============LICENSE_START==================================================== -# Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. -# Modifications Copyright (C) 2022-2023 Nordix Foundation. -# ============================================================================= -# 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====================================================== - -usage() { - echo args: [-t timeout] [-c command] hostname1 port1 hostname2 port2 ... >&2 - exit 1 -} - -tmout=300 -cmd= -while getopts c:t: opt -do - case "$opt" in - c) - cmd="$OPTARG" - ;; - - t) - tmout="$OPTARG" - ;; - - *) - usage - ;; - esac -done - -nargs=$((OPTIND-1)) -shift "$nargs" - -even_args=$(($#%2)) -if [ $# -lt 2 ] || [ "$even_args" -ne 0 ] -then - usage -fi - -while [ $# -ge 2 ] -do - export host="$1" - export port="$2" - shift - shift - - echo "Waiting for $host port $port..." - - while [ "$tmout" -gt 0 ] - do - if command -v docker > /dev/null 2>&1 - then - docker ps --format "table {{ .Names }}\t{{ .Status }}" - fi - - nc -vz "$host" "$port" - rc=$? - - if [ $rc -eq 0 ] - then - break - else - tmout=$((tmout-1)) - sleep 1 - fi - done - - if [ $rc -ne 0 ] - then - echo "$host port $port cannot be reached" - exit $rc - fi -done -#sh scripts.sh -$cmd - -exit 0 -- 2.16.6