Delete Policy Instance API feature.

Implementation of Deletion of Policy Instance API

Signed-off-by: naman.gupta <naman.gupta@samsung.com>
Change-Id: Id20356cd9fa8d9138d965e96d23de4e76b8c98be
diff --git a/a1-go/pkg/restful/restful.go b/a1-go/pkg/restful/restful.go
index 17d1fad..b0663dd 100644
--- a/a1-go/pkg/restful/restful.go
+++ b/a1-go/pkg/restful/restful.go
@@ -133,6 +133,19 @@
 		return a1_mediator.NewA1ControllerGetPolicyInstanceStatusServiceUnavailable()
 	})
 
+	api.A1MediatorA1ControllerDeletePolicyInstanceHandler = a1_mediator.A1ControllerDeletePolicyInstanceHandlerFunc(func(params a1_mediator.A1ControllerDeletePolicyInstanceParams) middleware.Responder {
+		a1.Logger.Debug("handler for delete policy instance")
+		if err := r.rh.DeletePolicyInstance(models.PolicyTypeID(params.PolicyTypeID), models.PolicyInstanceID(params.PolicyInstanceID)); err != nil {
+			if r.rh.CanPolicyInstanceBeDeleted(err) {
+				return a1_mediator.NewA1ControllerDeletePolicyInstanceNotFound()
+			}
+			return a1_mediator.NewA1ControllerDeletePolicyInstanceServiceUnavailable()
+		}
+
+		return a1_mediator.NewA1ControllerDeletePolicyInstanceAccepted()
+
+	})
+	
 	return api
 
 }
diff --git a/a1-go/pkg/resthooks/resthooks.go b/a1-go/pkg/resthooks/resthooks.go
index 0c870f6..e0060f1 100644
--- a/a1-go/pkg/resthooks/resthooks.go
+++ b/a1-go/pkg/resthooks/resthooks.go
@@ -51,6 +51,11 @@
 var policyInstanceNotFoundError = errors.New("Policy Instance Not Found")
 var policyTypeNotFoundError = errors.New("Policy Type Not Found")
 var policyTypeCanNotBeDeletedError = errors.New("tried to delete a type that isn't empty")
+var policyInstanceCanNotBeDeletedError = errors.New("tried to delete a Instance that isn't empty")
+
+func (rh *Resthook) CanPolicyInstanceBeDeleted(err error) bool {
+	return err == policyInstanceCanNotBeDeletedError
+}
 
 func (rh *Resthook) CanPolicyTypeBeDeleted(err error) bool {
 	return err == policyTypeCanNotBeDeletedError
@@ -372,7 +377,7 @@
 		}
 
 		message := rmr.Message{}
-		rmrMessage, err := message.PolicyMessage(strconv.FormatInt((int64(policyTypeId)), 10), string(policyInstanceID), httpBodyString, operation)
+		rmrMessage, err = message.PolicyMessage(strconv.FormatInt((int64(policyTypeId)), 10), string(policyInstanceID), httpBodyString, operation)
 		if err != nil {
 			a1.Logger.Error("error : %v", err)
 			return err
@@ -575,3 +580,104 @@
 	}
 	return &policyInstanceStatus, nil
 }
+
+func (rh *Resthook) storeDeletedPolicyInstanceMetadata(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID, creation_timestamp string) error {
+	deleted_timestamp := time.Now()
+
+	instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
+
+	a1.Logger.Debug("instanceMetadata Key : %+v", instanceMetadataKey)
+
+	var metadatajson interface{}
+	metadatajson = map[string]string{"created_at": creation_timestamp, "has_been_deleted": "True", "deleted_at": deleted_timestamp.Format("2006-01-02 15:04:05")}
+	a1.Logger.Debug("metadatajson to create : %+v", metadatajson)
+	deletedmetadata, err := json.Marshal(metadatajson)
+
+	a1.Logger.Debug("policyinstanceMetaData to create : %+v", string(deletedmetadata))
+
+	err = rh.db.Set(a1MediatorNs, instanceMetadataKey, string(deletedmetadata))
+	a1.Logger.Debug("deletemetadatacreated")
+	if err != nil {
+		a1.Logger.Error("error :%+v", err)
+		return err
+	}
+
+	a1.Logger.Error("Policy Instance Meta Data deleted at :%+v", creation_timestamp)
+
+	return nil
+}
+
+func (rh *Resthook) deleteInstancedata(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) error {
+	var keys [1]string
+	instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
+	keys[0] = instancekey
+	err := rh.db.Remove(a1MediatorNs, keys[:])
+	if err != nil {
+		a1.Logger.Error("error in deleting policy type err: %v", err)
+		return err
+	}
+	return nil
+}
+
+func (rh *Resthook) deleteMetadata(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) error {
+	var keys [1]string
+	instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
+
+	a1.Logger.Debug("instanceMetadata Key : %+v", instanceMetadataKey)
+	keys[0] = instanceMetadataKey
+	err := rh.db.Remove(a1MediatorNs, keys[:])
+	if err != nil {
+		a1.Logger.Error("error in deleting policy metadata err: %v", err)
+		return err
+	}
+	return nil
+}
+
+func (rh *Resthook) DeletePolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) error {
+	err := rh.instanceValidity(policyTypeId, policyInstanceID)
+	if err != nil {
+		a1.Logger.Error("policy instance error : %v", err)
+		if err == policyInstanceNotFoundError || err == policyTypeNotFoundError {
+			return err
+		}
+	}
+
+	createdmetadata, err := rh.getMetaData(policyTypeId, policyInstanceID)
+	if err != nil {
+		a1.Logger.Error("error : %v", err)
+		return err
+	}
+	a1.Logger.Debug(" created metadata %v", createdmetadata)
+	instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
+	creation_metadata := createdmetadata[instanceMetadataKey]
+	var metadata map[string]interface{}
+	if err = json.Unmarshal([]byte(creation_metadata.(string)), &metadata); err != nil {
+		a1.Logger.Error("unmarshal error : %v", err)
+		return err
+	}
+
+	a1.Logger.Debug(" created metadata created_at %v", metadata["created_at"])
+	creation_timestamp := metadata["created_at"]
+
+	rh.deleteMetadata(policyTypeId, policyInstanceID)
+
+	rh.deleteInstancedata(policyTypeId, policyInstanceID)
+
+	rh.storeDeletedPolicyInstanceMetadata(policyTypeId, policyInstanceID, creation_timestamp.(string))
+
+	message := rmr.Message{}
+	rmrMessage, err = message.PolicyMessage(strconv.FormatInt((int64(policyTypeId)), 10), string(policyInstanceID), "", "DELETE")
+	if err != nil {
+		a1.Logger.Error("error : %v", err)
+		return err
+	}
+	isSent := rh.iRmrSenderInst.RmrSendToXapp(rmrMessage)
+	if isSent {
+		a1.Logger.Debug("rmrSendToXapp : message sent")
+	} else {
+		//TODO:if message not sent need to return error or just log it or retry sending
+		a1.Logger.Error("rmrSendToXapp : message not sent")
+	}
+
+	return nil
+}
diff --git a/a1-go/pkg/resthooks/resthooks_test.go b/a1-go/pkg/resthooks/resthooks_test.go
index 34bf97a..deffc4b 100644
--- a/a1-go/pkg/resthooks/resthooks_test.go
+++ b/a1-go/pkg/resthooks/resthooks_test.go
@@ -225,6 +225,76 @@
 	sdlInst.AssertExpectations(t)
 }
 
+func TestDeletePolicyInstance(t *testing.T) {
+	var policyTypeId models.PolicyTypeID
+	policyTypeId = 20001
+	var policyInstanceID models.PolicyInstanceID
+	policyInstanceID = "123456"
+	var policyTypeSchema models.PolicyTypeSchema
+	name := "admission_control_policy_mine"
+	policyTypeSchema.Name = &name
+	policytypeid := int64(20001)
+	policyTypeSchema.PolicyTypeID = &policytypeid
+	description := "various parameters to control admission of dual connection"
+	policyTypeSchema.Description = &description
+	schema := `{"$schema": "http://json-schema.org/draft-07/schema#","type":"object","properties": {"enforce": {"type":"boolean","default":"true",},"window_length": {"type":        "integer","default":1,"minimum":1,"maximum":60,"description": "Sliding window length (in minutes)",},
+"blocking_rate": {"type":"number","default":10,"minimum":1,"maximum":100,"description": "% Connections to block",},"additionalProperties": false,},}`
+	policyTypeSchema.CreateSchema = schema
+
+	key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
+	var policytypekeys [1]string
+	policytypekeys[0] = key
+
+	sdlInst.On("Get", a1MediatorNs, policytypekeys[:]).Return(map[string]interface{}{key: policyTypeSchema}, nil)
+
+	httpBody := `{
+		"enforce":true,
+		"window_length":20,
+	   "blocking_rate":20,
+		"trigger_threshold":10
+		}`
+	instancekey := a1InstancePrefix + strconv.FormatInt(20001, 10) + "." + string(policyInstanceID)
+	var instancekeys [1]string
+	instancekeys[0] = instancekey
+
+	sdlInst.On("Get", a1MediatorNs, instancekeys[:]).Return(httpBody, nil)
+
+	var instanceMetadataKeys [1]string
+	instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
+	instanceMetadataKeys[0] = instanceMetadataKey
+	httpBody = `{
+		"created_at":"2022-11-02 10:30:20",
+			"instance_status":"NOT IN EFFECT"
+		}`
+
+	sdlInst.On("Get", a1MediatorNs, instanceMetadataKeys[:]).Return(httpBody, nil)
+
+	sdlInst.On("Remove", a1MediatorNs, instanceMetadataKeys[:]).Return(nil)
+
+	var metadatainstancekeys [1]string
+	metadatainstancekeys[0] = instancekey
+
+	sdlInst.On("Remove", a1MediatorNs, metadatainstancekeys[:]).Return(nil)
+
+	metadatainstancekey := a1InstanceMetadataPrefix + strconv.FormatInt(20001, 10) + "." + string(policyInstanceID)
+	deleted_timestamp := time.Now()
+	var metadatajson interface{}
+	metadatajson = map[string]string{"created_at": "2022-11-02 10:30:20", "deleted_at": deleted_timestamp.Format("2006-01-02 15:04:05"), "has_been_deleted": "True"}
+	metadata, _ := json.Marshal(metadatajson)
+	metadatainstancearr := []interface{}{metadatainstancekey, string(metadata)}
+
+	sdlInst.On("Set", "A1m_ns", metadatainstancearr).Return(nil)
+
+	httpBodyString := `{"operation":"DELETE","payload":"","policy_instance_id":"123456","policy_type_id":"20001"}`
+
+	rmrSenderInst.On("RmrSendToXapp", httpBodyString).Return(true)
+
+	errresp := rh.DeletePolicyInstance(policyTypeId, policyInstanceID)
+
+	assert.Nil(t, errresp)
+	sdlInst.AssertExpectations(t)
+}
+
 type SdlMock struct {
 	mock.Mock
 }
@@ -255,7 +325,7 @@
 		key = a1PolicyPrefix + strconv.FormatInt((policytypeid), 10)
 	} else if keys[0] == "a1.policy_inst_metadata.20001.123456" {
 		policySchemaString = `{
-			"created_at":"0001-01-01T00:00:00.000Z",
+			"created_at":"2022-11-02 10:30:20",
 			"instance_status":"NOT IN EFFECT"
 			}`
 		key = a1InstanceMetadataPrefix + strconv.FormatInt(policytypeid, 10) + "." + string(policyInstanceID)
diff --git a/a1-go/pkg/resthooks/types.go b/a1-go/pkg/resthooks/types.go
index 4765e29..2eb2f6d 100644
--- a/a1-go/pkg/resthooks/types.go
+++ b/a1-go/pkg/resthooks/types.go
@@ -22,6 +22,7 @@
 
 import (
 	"gerrit.o-ran-sc.org/r/ric-plt/a1/pkg/rmr"
+	"gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
 )
 
 type Resthook struct {