Fixed Data Handler and Decision Input Issue 38/140338/2
authorShalini Shivam <ss00765416@techmahindra.com>
Wed, 5 Mar 2025 10:01:34 +0000 (11:01 +0100)
committerShalini Shivam <ss00765416@techmahindra.com>
Wed, 5 Mar 2025 12:40:24 +0000 (13:40 +0100)
Issue-ID: POLICY-5232
Change-Id: I86c24925ec69f19fffd06d993a72dd4b448f3ca1
Signed-off-by: Shalini Shivam <ss00765416@techmahindra.com>
api/openapi.yaml
api/register-handlers.go
pkg/data/data-handler.go
pkg/decision/decision-provider.go
pkg/decision/decision-provider_test.go
pkg/kafkacomm/handler/pdp_update_deploy_policy.go
pkg/kafkacomm/handler/pdp_update_deploy_policy_test.go
pkg/kafkacomm/handler/pdp_update_undeploy_policy.go
pkg/model/oapicodegen/models.go
pkg/utils/utils.go
pkg/utils/utils_test.go

index 685bd4f..d8afb2f 100644 (file)
@@ -441,13 +441,15 @@ components:
           items:
             type: string
         input:
-          type: object
-          additionalProperties: true
-          example:
+          anyOf:
+           - x-go-type: "interface{}"
+           - type: object
+             additionalProperties: true
+             example:
                     user: alice
                     action: read
                     object: id123
-                    type: dog
+                    type: dog          
       required:
       - policyName
       - policyFilter
index 49b953f..ab71afe 100644 (file)
@@ -57,6 +57,8 @@ func RegisterHandlers() {
        dataHandler := http.HandlerFunc(data.DataHandler)
        http.Handle("/policy/pdpo/v1/data/", basicAuth(dataHandler))
 
+       http.Handle("/policy/pdpo/v1/data", basicAuth(dataHandler))
+
 }
 
 // handles authentication
index b571010..69c0500 100644 (file)
@@ -144,7 +144,7 @@ func patchHandler(res http.ResponseWriter, req *http.Request) {
                log.Errorf(errMsg)
                return
        }
-       path := strings.TrimPrefix(req.URL.Path, "/policy/pdpo/v1/data/")
+       path := strings.TrimPrefix(req.URL.Path, "/policy/pdpo/v1/data")
        dirParts := strings.Split(path, "/")
        dataDir := filepath.Join(dirParts...)
        log.Infof("dataDir : %s", dataDir)
@@ -173,9 +173,9 @@ func patchHandler(res http.ResponseWriter, req *http.Request) {
                        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)
-                }
+                       // Handle the error, for example, log it or return an appropriate response
+                       log.Errorf("Error encoding JSON response: %s", err)
+               }
        }
 }
 
@@ -386,7 +386,13 @@ func getDataInfo(res http.ResponseWriter, req *http.Request) {
        constructResponseHeader(res, req)
 
        urlPath := req.URL.Path
-       dataPath := strings.ReplaceAll(urlPath, "/policy/pdpo/v1/data", "")
+
+       dataPath := strings.TrimPrefix(urlPath, "/policy/pdpo/v1/data")
+
+       if len(strings.TrimSpace(dataPath)) == 0 {
+               // dataPath "/" is used to get entire data
+               dataPath = "/"
+       }
        log.Debugf("datapath to get Data : %s\n", dataPath)
 
        getData(res, dataPath)
@@ -420,7 +426,7 @@ func getData(res http.ResponseWriter, dataPath string) {
        res.WriteHeader(http.StatusOK)
 
        if err := json.NewEncoder(res).Encode(dataResponse); err != nil {
-                // Handle the error, for example, log it or return an appropriate response
-                log.Errorf("Error encoding JSON response: %s", err)
+               // Handle the error, for example, log it or return an appropriate response
+               log.Errorf("Error encoding JSON response: %s", err)
        }
 }
index 12896c3..463f731 100644 (file)
@@ -267,7 +267,12 @@ func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapi
        log.Debugf("SDK making a decision")
        var  decisionRes  *oapicodegen.OPADecisionResponse
        //OPA is seding success with a warning message if "input" parameter is missing, so we need to send success response
-       if (decisionReq.Input == nil) {
+       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)
        } else {
index ad95522..aac543b 100644 (file)
@@ -470,7 +470,6 @@ func Test_Error_Marshalling(t *testing.T) {
 
        OpaDecision(res, req)
        assert.Equal(t, http.StatusOK, res.Code)
-       assert.NotEmpty(t, res.Body.String())
 }
 
 
index bf56951..b7b9901 100644 (file)
@@ -365,11 +365,7 @@ func checkIfPolicyAlreadyDeployed(pdpUpdate model.PdpUpdate) []model.ToscaPolicy
 // verfies policy by creating bundle.
 func verifyPolicyByBundleCreation(policy model.ToscaPolicy) error {
        // get directory name
-       dirNames := getDirName(policy)
-       if len(dirNames) == 0 {
-               log.Warnf("Unable to extract folder name from policy %s", policy.Name)
-               return fmt.Errorf("failed to extract folder name")
-       }
+       dirNames := []string{strings.ReplaceAll(consts.Data+"/"+policy.Name, ".", "/"), strings.ReplaceAll(consts.Policies+"/"+policy.Name, ".", "/")}
        // create bundle
        output, err := createBundleFuncVar(exec.Command, policy)
        if err != nil {
index 3e4a24a..e95bbeb 100644 (file)
@@ -78,128 +78,6 @@ func TestValidatePackageName(t *testing.T) {
        }
 }
 
-func TestGetDirName(t *testing.T) {
-       var testData = []struct {
-               name     string
-               policy   model.ToscaPolicy // Use the actual package name
-               expected []string
-       }{
-               {
-                       name: "Basic valid case",
-                       policy: model.ToscaPolicy{
-                               Type:        "onap.policies.native.opa",
-                               TypeVersion: "1.0.0",
-                               Properties: model.PolicyProperties{
-                                       Data: map[string]string{
-                                               "key1": "value1",
-                                               "key2": "value2",
-                                       },
-                                       Policy: map[string]string{
-                                               "policy1": "value1",
-                                               "policy2": "value2",
-                                       },
-                               },
-                               Name:    "zone",
-                               Version: "1.0.0",
-                               Metadata: model.Metadata{
-                                       PolicyID:      "zone",
-                                       PolicyVersion: "1.0.0",
-                               },
-                       },
-                       expected: []string{
-                               "/opt/data/key2",
-                               "/opt/data/key1",
-                               "/opt/policies/policy1",
-                               "/opt/policies/policy2",
-                       },
-               },
-               {
-                       name: "Empty policy",
-                       policy: model.ToscaPolicy{
-                               Type:        "onap.policies.native.opa",
-                               TypeVersion: "1.0.0",
-                               Properties: model.PolicyProperties{
-                                       Data:   map[string]string{},
-                                       Policy: map[string]string{},
-                               },
-                               Name:    "zone",
-                               Version: "1.0.0",
-                               Metadata: model.Metadata{
-                                       PolicyID:      "zone",
-                                       PolicyVersion: "1.0.0",
-                               },
-                       },
-                       expected: []string{}, // No directories expected
-               },
-               {
-                       name: "Multiple keys",
-                       policy: model.ToscaPolicy{
-                               Type:        "onap.policies.native.opa",
-                               TypeVersion: "1.0.0",
-                               Properties: model.PolicyProperties{
-                                       Data: map[string]string{
-                                               "key1": "value1",
-                                               "key2": "value2",
-                                       },
-                                       Policy: map[string]string{
-                                               "policy1": "value1",
-                                               "policy2": "value2",
-                                       },
-                               },
-                               Name:    "zone",
-                               Version: "1.0.0",
-                               Metadata: model.Metadata{
-                                       PolicyID:      "zone",
-                                       PolicyVersion: "1.0.0",
-                               },
-                       },
-                       expected: []string{
-                               "/opt/data/key1",
-                               "/opt/data/key2",
-                               "/opt/policies/policy1",
-                               "/opt/policies/policy2",
-                       },
-               },
-               {
-                       name: "Special characters",
-                       policy: model.ToscaPolicy{
-                               Type:        "onap.policies.native.opa",
-                               TypeVersion: "1.0.0",
-                               Properties: model.PolicyProperties{
-                                       Data: map[string]string{
-                                               "key.with.dot": "value1",
-                                       },
-                                       Policy: map[string]string{
-                                               "policy.with.dot": "value2",
-                                       },
-                               },
-                               Name:    "zone",
-                               Version: "1.0.0",
-                               Metadata: model.Metadata{
-                                       PolicyID:      "zone",
-                                       PolicyVersion: "1.0.0",
-                               },
-                       },
-                       expected: []string{
-                               "/opt/data/key/with/dot",
-                               "/opt/policies/policy/with/dot",
-                       },
-               },
-       }
-       for _, tt := range testData {
-               t.Run(tt.name, func(t *testing.T) {
-                       result := getDirName(tt.policy)
-                       // Check that the actual result is either nil or empty
-                       if len(tt.expected) == 0 {
-                               // They should both be empty
-                               assert.Empty(t, result) // Assert that result is empty
-                       } else {
-                               assert.ElementsMatch(t, tt.expected, result) // Standard equality check for non-empty scenarios
-                       }
-               })
-       }
-}
-
 func TestExtractAndDecodeData(t *testing.T) {
        tests := []struct {
                name         string
@@ -508,7 +386,7 @@ func TestVerifyPolicyByBundleCreation_getDirEmpty(t *testing.T) {
 
        //Mocking the CreateBundle
        err := verifyPolicyByBundleCreation(policy)
-       assert.Error(t, err)
+       assert.NoError(t, err)
 
 }
 
@@ -675,7 +553,7 @@ func TestHandlePolicyDeployment_Success(t *testing.T) {
                        {
                                Properties: model.PolicyProperties{
                                        Data: map[string]string{
-                                               "node.role": "ewogICAgInVzZXJfcm9sZXMiOiB7CiAgICAgICAgImFsaWNlIjogWwogICAgICAgICAgICAiYWRtaW4iCiAgICAgICAgXSwKICAgICAgICAiYm9iIjogWwogICAgICAgICAgICAiZW1wbG95ZWUiLAogICAgICAgICAgICAiYmlsbGluZyIKICAgICAgICBdLAogICAgICAgICJldmUiOiBbCiAgICAgICAgICAgICJjdXN0b21lciIKICAgICAgICBdCiAgICB9LAogICAgInJvbGVfZ3JhbnRzIjogewogICAgICAgICJjdXN0b21lciI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImNhdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJhZG9wdCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAiYWRvcHQiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiZW1wbG95ZWUiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjYXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJ1cGRhdGUiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiYmlsbGluZyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cn0K",
+                                               "node.role": "ewogICAgInVzZXJfcm9sZXMiOiB7CiAgICAgICAgImFsaWNlIjogWwogICAgICAgICAgICAiYWRtaW4iCiAgICAgICAgXSwKICAgICAgICAiYm9iIjogWwogICAgICAgICAgICAiZW1wbG95ZWUiLAogICAgICAgICAgICAiYmlsbGluZyIKICAgICAgICBdLAogICAgICAgICJldmUiOiBbCiAgICAgICAgICAgICJjdXN0b21lciIKICAgICAgICBdCiAgICB9LAogICAgInJvbGVfZ3JhbnRzIjogewogICAgICAgICJjdXN0b21lciI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImNhdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJhZG9wdCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAiYWRvcHQiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiZW1wbG95ZWUiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjYXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJ1cGRhdGUiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiYmlsbGluZyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cn0K",
                                        },
                                        Policy: map[string]string{
                                                "role": "ewogICAgInVzZXJfcm9sZXMiOiB7CiAgICAgICAgImFsaWNlIjogWwogICAgICAgICAgICAiYWRtaW4iCiAgICAgICAgXSwKICAgICAgICAiYm9iIjogWwogICAgICAgICAgICAiZW1wbG95ZWUiLAogICAgICAgICAgICAiYmlsbGluZyIKICAgICAgICBdLAogICAgICAgICJldmUiOiBbCiAgICAgICAgICAgICJjdXN0b21lciIKICAgICAgICBdCiAgICB9LAogICAgInJvbGVfZ3JhbnRzIjogewogICAgICAgICJjdXN0b21lciI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImNhdCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJhZG9wdCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAiYWRvcHQiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiZW1wbG95ZWUiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJkb2ciCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAicmVhZCIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICJjYXQiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImRvZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJ1cGRhdGUiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiY2F0IgogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiYmlsbGluZyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImFjdGlvbiI6ICJyZWFkIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJhY3Rpb24iOiAidXBkYXRlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogImZpbmFuY2UiCiAgICAgICAgICAgIH0KICAgICAgICBdCiAgICB9Cn0K",
index 31d4554..b714ec6 100644 (file)
@@ -39,27 +39,25 @@ type (
 )
 
 var (
-        handlePolicyUndeploymentVar HandlePolicyUndeploymentFunc = handlePolicyUndeployment
+       handlePolicyUndeploymentVar HandlePolicyUndeploymentFunc = handlePolicyUndeployment
 
-        removeDirectoryFunc          = utils.RemoveDirectory
+       removeDirectoryFunc = utils.RemoveDirectory
 
-        deleteDataSdkFunc            = opasdk.DeleteData
+       deleteDataSdkFunc = opasdk.DeleteData
 
-        deletePolicySdkFunc          = opasdk.DeletePolicy
+       deletePolicySdkFunc = opasdk.DeletePolicy
 
-        removeDataDirectoryFunc      = removeDataDirectory
+       removeDataDirectoryFunc = removeDataDirectory
 
-        removePolicyDirectoryFunc    = removePolicyDirectory
+       removePolicyDirectoryFunc = removePolicyDirectory
 
        policyUndeploymentActionFunc = policyUndeploymentAction
 
-       removePolicyFromSdkandDirFunc= removePolicyFromSdkandDir
-
-       removeDataFromSdkandDirFunc  = removeDataFromSdkandDir
+       removePolicyFromSdkandDirFunc = removePolicyFromSdkandDir
 
+       removeDataFromSdkandDirFunc = removeDataFromSdkandDir
 )
 
-
 // processPoliciesTobeUndeployed handles the undeployment of policies
 func processPoliciesTobeUndeployed(undeployedPolicies map[string]string) ([]string, map[string]string) {
        var failureMessages []string
@@ -147,8 +145,9 @@ func removeDataFromSdkandDir(policy map[string]interface{}) []string {
 
        if dataKeys, ok := policy["data"].([]interface{}); ok {
                for _, dataKey := range dataKeys {
-                       keyPath := "/" + strings.Replace(dataKey.(string), ".", "/", -1)
-                       log.Debugf("Deleting data from OPA at keypath: %s", keyPath)
+                       keyPath := dataKey.(string)
+                       keyPath = "/" + strings.Replace(keyPath, ".", "/", -1)
+                       log.Debugf("Deleting data from OPA : %s", keyPath)
                        if err := deleteDataSdkFunc(context.Background(), keyPath); err != nil {
                                failureMessages = append(failureMessages, err.Error())
                                continue
@@ -171,6 +170,7 @@ func removePolicyFromSdkandDir(policy map[string]interface{}) []string {
        if policyKeys, ok := policy["policy"].([]interface{}); ok {
                for _, policyKey := range policyKeys {
                        keyPath := "/" + strings.Replace(policyKey.(string), ".", "/", -1)
+                       log.Debugf("Deleting Policy from OPA : %s", keyPath)
                        if err := deletePolicySdkFunc(context.Background(), policyKey.(string)); err != nil {
                                failureMessages = append(failureMessages, err.Error())
                                continue
index dc51713..34d88cd 100644 (file)
@@ -84,15 +84,15 @@ type OPADataUpdateRequest struct {
 
 // OPADecisionRequest defines model for OPADecisionRequest.
 type OPADecisionRequest struct {
-       CurrentDate     *openapi_types.Date    `json:"currentDate,omitempty"`
-       CurrentDateTime *time.Time             `json:"currentDateTime,omitempty"`
-       CurrentTime     *string                `json:"currentTime,omitempty"`
-       Input           map[string]interface{} `json:"input"`
-       OnapComponent   *string                `json:"onapComponent,omitempty"`
-       OnapInstance    *string                `json:"onapInstance,omitempty"`
-       OnapName        *string                `json:"onapName,omitempty"`
-       PolicyFilter    []string               `json:"policyFilter"`
-       PolicyName      string                 `json:"policyName"`
+       CurrentDate     *openapi_types.Date      `json:"currentDate,omitempty"`
+       CurrentDateTime *time.Time               `json:"currentDateTime,omitempty"`
+       CurrentTime     *string                  `json:"currentTime,omitempty"`
+       Input           OPADecisionRequest_Input `json:"input"`
+       OnapComponent   *string                  `json:"onapComponent,omitempty"`
+       OnapInstance    *string                  `json:"onapInstance,omitempty"`
+       OnapName        *string                  `json:"onapName,omitempty"`
+       PolicyFilter    []string                 `json:"policyFilter"`
+       PolicyName      string                   `json:"policyName"`
 
        // TimeOffset Time offset in hours and minutes, e.g., '+02:00' or '-05:00'
        TimeOffset *string `json:"timeOffset,omitempty"`
@@ -101,6 +101,17 @@ type OPADecisionRequest struct {
        TimeZone *string `json:"timeZone,omitempty"`
 }
 
+// OPADecisionRequestInput0 defines model for .
+type OPADecisionRequestInput0 = interface{}
+
+// OPADecisionRequestInput1 defines model for .
+type OPADecisionRequestInput1 map[string]interface{}
+
+// OPADecisionRequest_Input defines model for OPADecisionRequest.Input.
+type OPADecisionRequest_Input struct {
+       union json.RawMessage
+}
+
 // OPADecisionResponse defines model for OPADecisionResponse.
 type OPADecisionResponse struct {
        Output        map[string]interface{} `json:"output"`
@@ -219,3 +230,65 @@ func (t *OPADataResponse_Data) UnmarshalJSON(b []byte) error {
        err := t.union.UnmarshalJSON(b)
        return err
 }
+
+// AsOPADecisionRequestInput0 returns the union data inside the OPADecisionRequest_Input as a OPADecisionRequestInput0
+func (t OPADecisionRequest_Input) AsOPADecisionRequestInput0() (OPADecisionRequestInput0, error) {
+       var body OPADecisionRequestInput0
+       err := json.Unmarshal(t.union, &body)
+       return body, err
+}
+
+// FromOPADecisionRequestInput0 overwrites any union data inside the OPADecisionRequest_Input as the provided OPADecisionRequestInput0
+func (t *OPADecisionRequest_Input) FromOPADecisionRequestInput0(v OPADecisionRequestInput0) error {
+       b, err := json.Marshal(v)
+       t.union = b
+       return err
+}
+
+// MergeOPADecisionRequestInput0 performs a merge with any union data inside the OPADecisionRequest_Input, using the provided OPADecisionRequestInput0
+func (t *OPADecisionRequest_Input) MergeOPADecisionRequestInput0(v OPADecisionRequestInput0) error {
+       b, err := json.Marshal(v)
+       if err != nil {
+               return err
+       }
+
+       merged, err := runtime.JsonMerge(t.union, b)
+       t.union = merged
+       return err
+}
+
+// AsOPADecisionRequestInput1 returns the union data inside the OPADecisionRequest_Input as a OPADecisionRequestInput1
+func (t OPADecisionRequest_Input) AsOPADecisionRequestInput1() (OPADecisionRequestInput1, error) {
+       var body OPADecisionRequestInput1
+       err := json.Unmarshal(t.union, &body)
+       return body, err
+}
+
+// FromOPADecisionRequestInput1 overwrites any union data inside the OPADecisionRequest_Input as the provided OPADecisionRequestInput1
+func (t *OPADecisionRequest_Input) FromOPADecisionRequestInput1(v OPADecisionRequestInput1) error {
+       b, err := json.Marshal(v)
+       t.union = b
+       return err
+}
+
+// MergeOPADecisionRequestInput1 performs a merge with any union data inside the OPADecisionRequest_Input, using the provided OPADecisionRequestInput1
+func (t *OPADecisionRequest_Input) MergeOPADecisionRequestInput1(v OPADecisionRequestInput1) error {
+       b, err := json.Marshal(v)
+       if err != nil {
+               return err
+       }
+
+       merged, err := runtime.JsonMerge(t.union, b)
+       t.union = merged
+       return err
+}
+
+func (t OPADecisionRequest_Input) MarshalJSON() ([]byte, error) {
+       b, err := t.union.MarshalJSON()
+       return b, err
+}
+
+func (t *OPADecisionRequest_Input) UnmarshalJSON(b []byte) error {
+       err := t.union.UnmarshalJSON(b)
+       return err
+}
index 23f9cfe..903a0ce 100644 (file)
@@ -75,30 +75,55 @@ func RemoveDirectory(dirPath string) error {
 
        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)
+               }
+       }
 
-               if entry.IsDir() {
-                       // Check if the subdirectory is empty and delete it
-                       isEmpty, err := isDirEmpty(entryPath)
-                       if err != nil {
-                               return err
-                       }
-                       if isEmpty {
-                               log.Debugf("Removing empty subdirectory: %s", entryPath)
-                               if err := os.RemoveAll(entryPath); err != nil {
-                                       return fmt.Errorf("failed to remove directory: %s, error: %w", entryPath, err)
-                               }
-                       }
-               } else {
-                       // Delete specific files in the parent directory
-                       if entry.Name() == "data.json" || entry.Name() == "policy.rego" {
-                               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
+       for {
+               log.Infof("Processig Parent dir : %s", currentPath)
+               // Check if we have reached the match path
+               if currentPath == consts.Data+"/node" || currentPath == consts.Policies {
+                       return nil // Stop if we reach the match path
+               }
+
+               if currentPath == "/" || currentPath == "." {
+                       log.Infof("Reached root orelative path: %s", currentPath)
+                       return nil // Stop if we reach the match path
+               }
+
+               // 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)
+                       return nil // Stop if we can't find the parent path
                }
+               // Clean the parent directory
+               err = isSubDirEmpty(currentPath)
+               if err != nil {
+                       return err
+               }
+               // Trim the path to its parent directory.
+               currentPath = filepath.Dir(currentPath)
        }
 
+}
+
+func isSubDirEmpty(entryPath string) error {
+
+       isEmpty, err := isDirEmpty(entryPath)
+       if err != nil {
+               return err
+       }
+       if isEmpty {
+               log.Debugf("Removing empty subdirectory: %s", entryPath)
+               if err := os.RemoveAll(entryPath); err != nil {
+                       return fmt.Errorf("failed to remove directory: %s, error: %w", entryPath, err)
+               }
+       }
        return nil
 }
 
@@ -144,7 +169,7 @@ func ValidateToscaPolicyJsonFields(policy model.ToscaPolicy) error {
                                return fmt.Errorf("duplicate data key '%s' found, '%s'", key, emphasize)
                        }
                        keySeen[key] = true
-                       if !strings.HasPrefix(key, "node." + policy.Name) {
+                       if !strings.HasPrefix(key, "node."+policy.Name) {
                                return fmt.Errorf("data key '%s' does not have name node.'%s' as a prefix, '%s'", key, policy.Name, emphasize)
                        }
                }
@@ -298,15 +323,15 @@ func IsValidString(name *string) bool {
 }
 
 func BuildBundle(cmdFunc func(string, ...string) *exec.Cmd) (string, error) {
-     cmd := cmdFunc(
-         consts.Opa,
-         consts.BuildBundle,
-         consts.V1_COMPATIBLE,
-         consts.Policies,
-         consts.Data,
-         consts.Output,
-         consts.BundleTarGzFile,
-     )
+       cmd := cmdFunc(
+               consts.Opa,
+               consts.BuildBundle,
+               consts.V1_COMPATIBLE,
+               consts.Policies,
+               consts.Data,
+               consts.Output,
+               consts.BundleTarGzFile,
+       )
        log.Debugf("Before calling combinedoutput")
        output, err := cmd.CombinedOutput()
 
index 3a4948d..591d1ea 100644 (file)
@@ -117,16 +117,12 @@ func TestRemoveDirectory_Positive(t *testing.T) {
        _, err = os.Stat(filePath)
        assert.True(t, os.IsNotExist(err), "Fle should be removed")
 
-       _, err = os.Stat(tempDir)
-       assert.NoError(t, err, "Directory should exist if file is removed")
-
 }
 
 func TestRemoveDirectory_Negative(t *testing.T) {
        nonExistentDirectory := filepath.Join(os.TempDir(), "non_existent_directory")
 
        _, err := os.Stat(nonExistentDirectory)
-       assert.True(t, os.IsNotExist(err), "DIrectory should not exist before deletion")
        err = RemoveDirectory(nonExistentDirectory)
        assert.NoError(t, err)
 }
@@ -145,8 +141,6 @@ func TestRemoveDirectory_ValidEmptyDir(t *testing.T) {
        _, err = os.Stat(subDir)
        assert.True(t, os.IsNotExist(err), "Expected directory to be deleted")
 
-       _, err = os.Stat(tempDir)
-       assert.NoError(t, err, "Directory should exist if file is removed")
 }
 
 // Test removing a directory that does not exist