Merge "[RIC-587] Update E2 Setup existing nodeb behavior"
diff --git a/E2Manager/container-tag.yaml b/E2Manager/container-tag.yaml
index 45daa1d..b2f762c 100644
--- a/E2Manager/container-tag.yaml
+++ b/E2Manager/container-tag.yaml
@@ -1,4 +1,4 @@
 # The Jenkins job requires a tag to build the Docker image.
 # Global-JJB script assumes this file is in the repo root.
 ---
-tag: 5.2.21
\ No newline at end of file
+tag: 5.2.22
\ No newline at end of file
diff --git a/E2Manager/handlers/httpmsghandlers/delete_all_request_handler.go b/E2Manager/handlers/httpmsghandlers/delete_all_request_handler.go
index 80f1a04..e53c636 100644
--- a/E2Manager/handlers/httpmsghandlers/delete_all_request_handler.go
+++ b/E2Manager/handlers/httpmsghandlers/delete_all_request_handler.go
@@ -204,7 +204,7 @@
 
 func (h *DeleteAllRequestHandler) updateNodebInfo(node *entities.NodebInfo, connectionStatus entities.ConnectionStatus, resetAssociatedE2TAddress bool) error {
 
-	err := h.ranConnectStatusChangeManager.ChangeStatus(node, connectionStatus)
+	_, err := h.ranConnectStatusChangeManager.ChangeStatus(node, connectionStatus)
 	if err != nil {
 		return e2managererrors.NewRnibDbError()
 	}
diff --git a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go
index 5565513..259dcc3 100644
--- a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go
+++ b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go
@@ -42,17 +42,17 @@
 	emptyTagsToReplaceToSelfClosingTags = []string{"reject", "ignore", "transport-resource-unavailable", "om-intervention", "request-id-unknown",
 		"v60s", "v20s", "v10s", "v5s", "v2s", "v1s"}
 	gnbTypesMap = map[string]entities.GnbType{
-		"gnb":entities.GnbType_GNB,
-		"en_gnb":entities.GnbType_EN_GNB,
+		"gnb":    entities.GnbType_GNB,
+		"en_gnb": entities.GnbType_EN_GNB,
 	}
 	enbTypesMap = map[string]entities.EnbType{
-		"enB_macro":entities.EnbType_MACRO_ENB,
-		"enB_home":entities.EnbType_HOME_ENB,
-		"enB_shortmacro":entities.EnbType_SHORT_MACRO_ENB,
-		"enB_longmacro":entities.EnbType_LONG_MACRO_ENB,
-		"ng_enB_macro":entities.EnbType_MACRO_NG_ENB,
-		"ng_enB_shortmacro":entities.EnbType_SHORT_MACRO_NG_ENB,
-		"ng_enB_longmacro":entities.EnbType_LONG_MACRO_NG_ENB,
+		"enB_macro":         entities.EnbType_MACRO_ENB,
+		"enB_home":          entities.EnbType_HOME_ENB,
+		"enB_shortmacro":    entities.EnbType_SHORT_MACRO_ENB,
+		"enB_longmacro":     entities.EnbType_LONG_MACRO_ENB,
+		"ng_enB_macro":      entities.EnbType_MACRO_NG_ENB,
+		"ng_enB_shortmacro": entities.EnbType_SHORT_MACRO_NG_ENB,
+		"ng_enB_longmacro":  entities.EnbType_LONG_MACRO_NG_ENB,
 	}
 )
 
@@ -64,7 +64,7 @@
 	rNibDataService               services.RNibDataService
 	e2tAssociationManager         *managers.E2TAssociationManager
 	ranConnectStatusChangeManager managers.IRanConnectStatusChangeManager
-	ranListManager managers.RanListManager
+	ranListManager                managers.RanListManager
 }
 
 func NewE2SetupRequestNotificationHandler(logger *logger.Logger, config *configuration.Configuration, e2tInstancesManager managers.IE2TInstancesManager, rmrSender *rmrsender.RmrSender, rNibDataService services.RNibDataService, e2tAssociationManager *managers.E2TAssociationManager, ranConnectStatusChangeManager managers.IRanConnectStatusChangeManager, ranListManager managers.RanListManager) *E2SetupRequestNotificationHandler {
@@ -76,7 +76,7 @@
 		rNibDataService:               rNibDataService,
 		e2tAssociationManager:         e2tAssociationManager,
 		ranConnectStatusChangeManager: ranConnectStatusChangeManager,
-		ranListManager: ranListManager,
+		ranListManager:                ranListManager,
 	}
 }
 
@@ -117,12 +117,13 @@
 
 	nodebInfo, err := h.rNibDataService.GetNodeb(ranName)
 
+	var functionsModified bool
+
 	if err != nil {
 
 		if _, ok := err.(*common.ResourceNotFoundError); !ok {
 			h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - failed to retrieve nodebInfo entity. Error: %s", ranName, err)
 			return
-
 		}
 
 		if nodebInfo, err = h.handleNewRan(ranName, e2tIpAddress, setupRequest); err != nil {
@@ -134,26 +135,56 @@
 		}
 
 	} else {
-		if err = h.handleExistingRan(ranName, nodebInfo, setupRequest); err != nil {
+
+		functionsModified, err = h.handleExistingRan(ranName, nodebInfo, setupRequest)
+
+		if err != nil {
 			return
 		}
 	}
 
-	err = h.e2tAssociationManager.AssociateRan(e2tIpAddress, nodebInfo)
+	ranStatusChangePublished, err := h.e2tAssociationManager.AssociateRan(e2tIpAddress, nodebInfo)
 
 	if err != nil {
 
 		h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - failed to associate E2T to nodeB entity. Error: %s", ranName, err)
 		if _, ok := err.(*e2managererrors.RoutingManagerError); ok {
+
+			if err = h.handleUpdateAndPublishNodebInfo(functionsModified, ranStatusChangePublished, nodebInfo); err != nil {
+				return
+			}
+
 			cause := models.Cause{Transport: &models.CauseTransport{TransportResourceUnavailable: &struct{}{}}}
 			h.handleUnsuccessfulResponse(nodebInfo.RanName, request, cause)
 		}
 		return
 	}
 
+	if err = h.handleUpdateAndPublishNodebInfo(functionsModified, ranStatusChangePublished, nodebInfo); err != nil {
+		return
+	}
+
 	h.handleSuccessfulResponse(ranName, request, setupRequest)
 }
 
+func (h *E2SetupRequestNotificationHandler) handleUpdateAndPublishNodebInfo(functionsModified bool, ranStatusChangePublished bool, nodebInfo *entities.NodebInfo) error {
+
+	if ranStatusChangePublished || !functionsModified {
+		return nil
+	}
+
+	err := h.rNibDataService.UpdateNodebInfoAndPublish(nodebInfo)
+
+	if err != nil {
+		h.logger.Errorf("#E2SetupRequestNotificationHandler.handleUpdateAndPublishNodebInfo - RAN name: %s - Failed at UpdateNodebInfoAndPublish. error: %s", nodebInfo.RanName, err)
+		return err
+	}
+
+	h.logger.Infof("#E2SetupRequestNotificationHandler.handleUpdateAndPublishNodebInfo - RAN name: %s - Successfully executed UpdateNodebInfoAndPublish", nodebInfo.RanName)
+	return nil
+
+}
+
 func (h *E2SetupRequestNotificationHandler) handleNewRan(ranName string, e2tIpAddress string, setupRequest *models.E2SetupRequestMessage) (*entities.NodebInfo, error) {
 
 	nodebInfo, err := h.buildNodebInfo(ranName, e2tIpAddress, setupRequest)
@@ -179,26 +210,24 @@
 	return nodebInfo, nil
 }
 
-func (h *E2SetupRequestNotificationHandler) setGnbFunctions(nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) {
-	if nodebInfo.GetNodeType() == entities.Node_ENB {
-		return
-	}
-
-	ranFunctions := setupRequest.ExtractRanFunctionsList()
-	if ranFunctions != nil {
-		nodebInfo.GetGnb().RanFunctions = ranFunctions
-	}
-}
-
-func (h *E2SetupRequestNotificationHandler) handleExistingRan(ranName string, nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) error {
+func (h *E2SetupRequestNotificationHandler) handleExistingRan(ranName string, nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) (bool, error) {
 	if nodebInfo.GetConnectionStatus() == entities.ConnectionStatus_SHUTTING_DOWN {
 		h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s, connection status: %s - nodeB entity in incorrect state", ranName, nodebInfo.ConnectionStatus)
-		return errors.New("nodeB entity in incorrect state")
+		return false, errors.New("nodeB entity in incorrect state")
 	}
 
-	h.setGnbFunctions(nodebInfo, setupRequest)
+	if nodebInfo.NodeType == entities.Node_ENB {
+		return false, nil
+	}
 
-	return h.rNibDataService.UpdateNodebInfo(nodebInfo)
+	setupMessageRanFuncs := setupRequest.ExtractRanFunctionsList()
+
+	if setupMessageRanFuncs == nil || (len(setupMessageRanFuncs) == 0 && len(nodebInfo.GetGnb().RanFunctions) == 0) {
+		return false, nil
+	}
+
+	nodebInfo.GetGnb().RanFunctions = setupMessageRanFuncs
+	return true, nil
 }
 
 func (h *E2SetupRequestNotificationHandler) handleUnsuccessfulResponse(ranName string, req *models.NotificationRequest, cause models.Cause) {
@@ -318,13 +347,23 @@
 		AssociatedE2TInstanceAddress: e2tAddress,
 		RanName:                      ranName,
 		GlobalNbId:                   h.buildGlobalNbId(request),
-		SetupFromNetwork: 			  true,
+		SetupFromNetwork:             true,
 	}
 	err := h.setNodeTypeAndConfiguration(nodebInfo)
 	if err != nil {
 		return nil, err
 	}
-	h.setGnbFunctions(nodebInfo, request)
+
+	if nodebInfo.NodeType == entities.Node_ENB {
+		return nodebInfo, nil
+	}
+
+	ranFuncs := request.ExtractRanFunctionsList()
+
+	if ranFuncs != nil {
+		nodebInfo.GetGnb().RanFunctions = ranFuncs
+	}
+
 	return nodebInfo, nil
 }
 
diff --git a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go
index f0af881..77ffe7a 100644
--- a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go
+++ b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go
@@ -51,7 +51,7 @@
 	GnbWithoutFunctionsSetupRequestXmlPath   = "../../tests/resources/setupRequest_gnb_without_functions.xml"
 	E2SetupFailureResponseWithMiscCause      = "<E2AP-PDU><unsuccessfulOutcome><procedureCode>1</procedureCode><criticality><reject/></criticality><value><E2setupFailure><protocolIEs><E2setupFailureIEs><id>1</id><criticality><ignore/></criticality><value><Cause><misc><om-intervention/></misc></Cause></value></E2setupFailureIEs><E2setupFailureIEs><id>31</id><criticality><ignore/></criticality><value><TimeToWait><v60s/></TimeToWait></value></E2setupFailureIEs></protocolIEs></E2setupFailure></value></unsuccessfulOutcome></E2AP-PDU>"
 	E2SetupFailureResponseWithTransportCause = "<E2AP-PDU><unsuccessfulOutcome><procedureCode>1</procedureCode><criticality><reject/></criticality><value><E2setupFailure><protocolIEs><E2setupFailureIEs><id>1</id><criticality><ignore/></criticality><value><Cause><transport><transport-resource-unavailable/></transport></Cause></value></E2setupFailureIEs><E2setupFailureIEs><id>31</id><criticality><ignore/></criticality><value><TimeToWait><v60s/></TimeToWait></value></E2setupFailureIEs></protocolIEs></E2setupFailure></value></unsuccessfulOutcome></E2AP-PDU>"
-	E2SetupFailureResponseWithRicCause      = "<E2AP-PDU><unsuccessfulOutcome><procedureCode>1</procedureCode><criticality><reject/></criticality><value><E2setupFailure><protocolIEs><E2setupFailureIEs><id>1</id><criticality><ignore/></criticality><value><Cause><ricRequest><request-id-unknown/></ricRequest></Cause></value></E2setupFailureIEs><E2setupFailureIEs><id>31</id><criticality><ignore/></criticality><value><TimeToWait><v60s/></TimeToWait></value></E2setupFailureIEs></protocolIEs></E2setupFailure></value></unsuccessfulOutcome></E2AP-PDU>"
+	E2SetupFailureResponseWithRicCause       = "<E2AP-PDU><unsuccessfulOutcome><procedureCode>1</procedureCode><criticality><reject/></criticality><value><E2setupFailure><protocolIEs><E2setupFailureIEs><id>1</id><criticality><ignore/></criticality><value><Cause><ricRequest><request-id-unknown/></ricRequest></Cause></value></E2setupFailureIEs><E2setupFailureIEs><id>31</id><criticality><ignore/></criticality><value><TimeToWait><v60s/></TimeToWait></value></E2setupFailureIEs></protocolIEs></E2setupFailure></value></unsuccessfulOutcome></E2AP-PDU>"
 	StateChangeMessageChannel                = "RAN_CONNECTION_STATUS_CHANGE"
 )
 
@@ -274,14 +274,14 @@
 
 func TestExtractionOfNodeTypeFromRanName(t *testing.T) {
 	handler, _, _, _, _, _ := initMocks(t)
-	validRanNames := []string {"gnb_P310_410_b5c67788","en_gnb_P310_410_b5c67788","ng_enB_macro_P310_410_b5c67788","ng_enB_shortmacro_P310_410_b5c67788","ng_enB_longmacro_P310_410_b5c67788","enB_macro_P310_410_b5c67788","enB_home_P310_410_b5c67788","enB_shortmacro_P310_410_b5c67788","enB_longmacro_P310_410_b5c67788"}
-	for _,v := range validRanNames {
+	validRanNames := []string{"gnb_P310_410_b5c67788", "en_gnb_P310_410_b5c67788", "ng_enB_macro_P310_410_b5c67788", "ng_enB_shortmacro_P310_410_b5c67788", "ng_enB_longmacro_P310_410_b5c67788", "enB_macro_P310_410_b5c67788", "enB_home_P310_410_b5c67788", "enB_shortmacro_P310_410_b5c67788", "enB_longmacro_P310_410_b5c67788"}
+	for _, v := range validRanNames {
 		nodeb := &entities.NodebInfo{RanName: v}
 		err := handler.setNodeTypeAndConfiguration(nodeb)
 		assert.Nil(t, err)
 	}
-	inValidRanNames := []string {"P310_410_b5c67788","blabla_P310_410_b5c67788","ng_enB-macro_P310_410_b5c67788","ng_enb_shortmacro_P310_410_b5c67788","ng_enB-longmacro_P310_410_b5c67788","enB_new_macro_P310_410_b5c67788"}
-	for _,v := range inValidRanNames {
+	inValidRanNames := []string{"P310_410_b5c67788", "blabla_P310_410_b5c67788", "ng_enB-macro_P310_410_b5c67788", "ng_enb_shortmacro_P310_410_b5c67788", "ng_enB-longmacro_P310_410_b5c67788", "enB_new_macro_P310_410_b5c67788"}
+	for _, v := range inValidRanNames {
 		nodeb := &entities.NodebInfo{RanName: v}
 		err := handler.setNodeTypeAndConfiguration(nodeb)
 		assert.NotNil(t, err, v)
@@ -289,7 +289,14 @@
 }
 
 func testE2SetupRequestNotificationHandler_HandleExistingConnectedGnbSuccess(t *testing.T, withFunctions bool) {
-	xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath)
+	var xmlGnb []byte
+
+	if withFunctions {
+		xmlGnb = readXmlFile(t, GnbSetupRequestXmlPath)
+
+	} else {
+		xmlGnb = readXmlFile(t, GnbWithoutFunctionsSetupRequestXmlPath)
+	}
 	handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t)
 	readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil)
 	e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil)
@@ -311,14 +318,17 @@
 
 	notificationRequest := &models.NotificationRequest{RanName: gnbNodebRanName, Payload: append([]byte(e2SetupMsgPrefix), xmlGnb...)}
 	gnbToUpdate := getExpectedNodebForExistingRan(*nodebInfo, notificationRequest.Payload)
+
 	writerMock.On("UpdateNodebInfo", gnbToUpdate).Return(nil)
+	if withFunctions {
+		writerMock.On("UpdateNodebInfoAndPublish", gnbToUpdate).Return(nil)
+	}
 	e2tInstancesManagerMock.On("AddRansToInstance", e2tInstanceFullAddress, []string{gnbNodebRanName}).Return(nil)
 	var errEmpty error
 	rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(&rmrCgo.MBuf{}, errEmpty)
 	handler.Handle(notificationRequest)
 	readerMock.AssertExpectations(t)
 	writerMock.AssertExpectations(t)
-	writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 3)
 	e2tInstancesManagerMock.AssertExpectations(t)
 	rmrMessengerMock.AssertCalled(t, "SendMsg", mock.Anything, true)
 }
@@ -349,7 +359,6 @@
 
 	notificationRequest := &models.NotificationRequest{RanName: gnbNodebRanName, Payload: append([]byte(e2SetupMsgPrefix), xmlGnb...)}
 	gnbToUpdate := getExpectedNodebForExistingRan(*nodebInfo, notificationRequest.Payload)
-	writerMock.On("UpdateNodebInfo", gnbToUpdate).Return(nil)
 	gnbToUpdate2 := *gnbToUpdate
 	gnbToUpdate2.ConnectionStatus = entities.ConnectionStatus_CONNECTED
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &gnbToUpdate2, gnbNodebRanName+"_CONNECTED").Return(nil)
@@ -363,7 +372,6 @@
 	handler.Handle(notificationRequest)
 	readerMock.AssertExpectations(t)
 	writerMock.AssertExpectations(t)
-	writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2)
 	e2tInstancesManagerMock.AssertExpectations(t)
 }
 
@@ -371,7 +379,9 @@
 	pipInd := bytes.IndexByte(payload, '|')
 	setupRequest := &models.E2SetupRequestMessage{}
 	_ = xml.Unmarshal(normalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU)
-	nodeb.GetGnb().RanFunctions = setupRequest.ExtractRanFunctionsList()
+	if ranFuncs := setupRequest.ExtractRanFunctionsList(); ranFuncs != nil {
+		nodeb.GetGnb().RanFunctions = ranFuncs
+	}
 	return &nodeb
 }
 
@@ -412,7 +422,7 @@
 		NodeType:                     entities.Node_ENB,
 		Configuration: &entities.NodebInfo_Enb{
 			Enb: &entities.Enb{
-				EnbType:      entities.EnbType_MACRO_ENB,
+				EnbType: entities.EnbType_MACRO_ENB,
 			},
 		},
 		GlobalNbId: &entities.GlobalNbId{
diff --git a/E2Manager/managers/e2t_association_manager.go b/E2Manager/managers/e2t_association_manager.go
index dfcaa3d..9ebdd60 100644
--- a/E2Manager/managers/e2t_association_manager.go
+++ b/E2Manager/managers/e2t_association_manager.go
@@ -45,37 +45,37 @@
 	}
 }
 
-func (m *E2TAssociationManager) AssociateRan(e2tAddress string, nodebInfo *entities.NodebInfo) error {
+func (m *E2TAssociationManager) AssociateRan(e2tAddress string, nodebInfo *entities.NodebInfo) (bool, error) {
 	ranName := nodebInfo.RanName
 	m.logger.Infof("#E2TAssociationManager.AssociateRan - Associating RAN %s to E2T Instance address: %s", ranName, e2tAddress)
 
-	err := m.associateRanAndUpdateNodeb(e2tAddress, nodebInfo)
+	ranStatusChangePublished, err := m.associateRanAndUpdateNodeb(e2tAddress, nodebInfo)
 	if err != nil {
 		m.logger.Errorf("#E2TAssociationManager.AssociateRan - RoutingManager failure: Failed to associate RAN %s to E2T %s. Error: %s", nodebInfo, e2tAddress, err)
-		return err
+		return ranStatusChangePublished, err
 	}
 	err = m.e2tInstanceManager.AddRansToInstance(e2tAddress, []string{ranName})
 	if err != nil {
 		m.logger.Errorf("#E2TAssociationManager.AssociateRan - RAN name: %s - Failed to add RAN to E2T instance %s. Error: %s", ranName, e2tAddress, err)
-		return e2managererrors.NewRnibDbError()
+		return ranStatusChangePublished, e2managererrors.NewRnibDbError()
 	}
 	m.logger.Infof("#E2TAssociationManager.AssociateRan - successfully associated RAN %s with E2T %s", ranName, e2tAddress)
-	return nil
+	return ranStatusChangePublished, nil
 }
 
-func (m *E2TAssociationManager) associateRanAndUpdateNodeb(e2tAddress string, nodebInfo *entities.NodebInfo) error {
+func (m *E2TAssociationManager) associateRanAndUpdateNodeb(e2tAddress string, nodebInfo *entities.NodebInfo) (bool, error) {
 
 	rmErr := m.rmClient.AssociateRanToE2TInstance(e2tAddress, nodebInfo.RanName)
 
 	if rmErr != nil {
-		_ =  m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_DISCONNECTED)
-		return e2managererrors.NewRoutingManagerError()
+		ranStatusChangePublished, _ := m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_DISCONNECTED)
+		return ranStatusChangePublished, e2managererrors.NewRoutingManagerError()
 	}
 
-	rnibErr := m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_CONNECTED)
+	ranStatusChangePublished, rnibErr := m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_CONNECTED)
 
 	if rnibErr != nil {
-		return e2managererrors.NewRnibDbError()
+		return ranStatusChangePublished, e2managererrors.NewRnibDbError()
 	}
 
 	nodebInfo.AssociatedE2TInstanceAddress = e2tAddress
@@ -83,10 +83,10 @@
 
 	if rnibErr != nil {
 		m.logger.Errorf("#E2TAssociationManager.associateRanAndUpdateNodeb - RAN name: %s - Failed updating nodeb. Error: %s", nodebInfo.RanName, rnibErr)
-		return e2managererrors.NewRnibDbError()
+		return ranStatusChangePublished, e2managererrors.NewRnibDbError()
 	}
 
-	return nil
+	return ranStatusChangePublished, nil
 }
 
 func (m *E2TAssociationManager) DissociateRan(e2tAddress string, ranName string) error {
diff --git a/E2Manager/managers/e2t_association_manager_test.go b/E2Manager/managers/e2t_association_manager_test.go
index bc17295..5a3a114 100644
--- a/E2Manager/managers/e2t_association_manager_test.go
+++ b/E2Manager/managers/e2t_association_manager_test.go
@@ -92,7 +92,7 @@
 	updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
 	writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
 
-	err := manager.AssociateRan(E2TAddress, nb)
+	_, err := manager.AssociateRan(E2TAddress, nb)
 
 	assert.Nil(t, err)
 	readerMock.AssertExpectations(t)
@@ -108,7 +108,7 @@
 	updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNb, RanName+"_CONNECTED").Return(common.NewInternalError(fmt.Errorf("for tests")))
 
-	err := manager.AssociateRan(E2TAddress, nb)
+	_, err := manager.AssociateRan(E2TAddress, nb)
 
 	assert.NotNil(t, err)
 	assert.IsType(t, &e2managererrors.RnibDbError{}, err)
@@ -123,7 +123,7 @@
 	nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
 	writerMock.On("UpdateNodebInfo", nb).Return(nil)
 
-	err := manager.AssociateRan(E2TAddress, nb)
+	_, err := manager.AssociateRan(E2TAddress, nb)
 
 	assert.NotNil(t, err)
 	assert.IsType(t, &e2managererrors.RoutingManagerError{}, err)
@@ -144,7 +144,7 @@
 	updatedNb2.AssociatedE2TInstanceAddress = E2TAddress
 	writerMock.On("UpdateNodebInfo", &updatedNb2).Return(e2managererrors.NewRnibDbError())
 
-	err := manager.AssociateRan(E2TAddress, nb)
+	_, err := manager.AssociateRan(E2TAddress, nb)
 
 	assert.NotNil(t, err)
 	assert.IsType(t, &e2managererrors.RnibDbError{}, err)
@@ -169,7 +169,7 @@
 	var e2tInstance *entities.E2TInstance
 	readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
 
-	err := manager.AssociateRan(E2TAddress, nb)
+	_, err := manager.AssociateRan(E2TAddress, nb)
 
 	assert.NotNil(t, err)
 	assert.IsType(t, &e2managererrors.RnibDbError{}, err)
@@ -197,7 +197,7 @@
 	updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
 	writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
 
-	err := manager.AssociateRan(E2TAddress, nb)
+	_, err := manager.AssociateRan(E2TAddress, nb)
 
 	assert.NotNil(t, err)
 	assert.IsType(t, &e2managererrors.RnibDbError{}, err)
diff --git a/E2Manager/managers/e2t_shutdown_manager.go b/E2Manager/managers/e2t_shutdown_manager.go
index 61761f2..3c88dbd 100644
--- a/E2Manager/managers/e2t_shutdown_manager.go
+++ b/E2Manager/managers/e2t_shutdown_manager.go
@@ -96,7 +96,7 @@
 			return err
 		}
 
-		err = m.ranConnectStatusChangeManager.ChangeStatus(nodeb, entities.ConnectionStatus_DISCONNECTED)
+		_, err = m.ranConnectStatusChangeManager.ChangeStatus(nodeb, entities.ConnectionStatus_DISCONNECTED)
 		if err != nil {
 			return err
 		}
diff --git a/E2Manager/managers/ran_connect_status_change_manager.go b/E2Manager/managers/ran_connect_status_change_manager.go
index ecb645c..138f089 100644
--- a/E2Manager/managers/ran_connect_status_change_manager.go
+++ b/E2Manager/managers/ran_connect_status_change_manager.go
@@ -32,7 +32,7 @@
 )
 
 type IRanConnectStatusChangeManager interface {
-	ChangeStatus(nodebInfo *entities.NodebInfo, nextStatus entities.ConnectionStatus) error
+	ChangeStatus(nodebInfo *entities.NodebInfo, nextStatus entities.ConnectionStatus) (bool, error)
 }
 
 type RanConnectStatusChangeManager struct {
@@ -51,9 +51,11 @@
 	}
 }
 
-func (m *RanConnectStatusChangeManager) ChangeStatus(nodebInfo *entities.NodebInfo, nextStatus entities.ConnectionStatus) error {
+func (m *RanConnectStatusChangeManager) ChangeStatus(nodebInfo *entities.NodebInfo, nextStatus entities.ConnectionStatus) (bool, error) {
 	m.logger.Infof("#RanConnectStatusChangeManager.ChangeStatus - RAN name: %s, currentStatus: %s, nextStatus: %s", nodebInfo.RanName, nodebInfo.GetConnectionStatus(), nextStatus)
 
+	var ranStatusChangePublished bool
+
 	// set the proper event
 	event := m.setEvent(nodebInfo, nextStatus)
 	isConnectivityEvent := event != NONE_RAW_EVENT
@@ -63,13 +65,14 @@
 	if !isConnectivityEvent {
 		err := m.updateNodebInfo(nodebInfo)
 		if err != nil {
-			return err
+			return ranStatusChangePublished, err
 		}
 	} else {
 		err := m.updateNodebInfoOnConnectionStatusInversion(nodebInfo, event)
 		if err != nil {
-			return err
+			return ranStatusChangePublished, err
 		}
+		ranStatusChangePublished = true
 	}
 
 	// in any case, update RanListManager
@@ -89,7 +92,7 @@
 		}
 	}
 
-	return nil
+	return ranStatusChangePublished, nil
 }
 
 func (m *RanConnectStatusChangeManager) updateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, event string) error {
diff --git a/E2Manager/managers/ran_connect_status_change_manager_test.go b/E2Manager/managers/ran_connect_status_change_manager_test.go
index 53921a1..a35e71e 100644
--- a/E2Manager/managers/ran_connect_status_change_manager_test.go
+++ b/E2Manager/managers/ran_connect_status_change_manager_test.go
@@ -62,7 +62,7 @@
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, RanName+"_"+CONNECTED_RAW_EVENT).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil)
 	ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(nil)
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -77,7 +77,7 @@
 	updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN
 	writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil)
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -92,7 +92,7 @@
 	updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN
 	writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil)
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -108,7 +108,7 @@
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, RanName+"_"+CONNECTED_RAW_EVENT).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil)
 	ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(nil)
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -124,7 +124,7 @@
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, RanName+"_"+DISCONNECTED_RAW_EVENT).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil)
 	ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(nil)
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_DISCONNECTED)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_DISCONNECTED)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -138,7 +138,7 @@
 	updatedNodebInfo := *origNodebInfo
 	updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN
 	writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error")))
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
 	assert.NotNil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -152,7 +152,7 @@
 	updatedNodebInfo := *origNodebInfo
 	updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, RanName+"_"+CONNECTED_RAW_EVENT).Return(common.NewInternalError(errors.New("Error")))
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
 	assert.NotNil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -167,7 +167,7 @@
 	updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN
 	writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error")))
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
@@ -183,7 +183,7 @@
 	writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, RanName+"_"+CONNECTED_RAW_EVENT).Return(nil)
 	ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil)
 	ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error")))
-	err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
+	_, err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED)
 	assert.Nil(t, err)
 	writerMock.AssertExpectations(t)
 	ranListManagerMock.AssertExpectations(t)
diff --git a/E2Manager/managers/ran_disconnection_manager.go b/E2Manager/managers/ran_disconnection_manager.go
index f07e8fd..8d30eec 100644
--- a/E2Manager/managers/ran_disconnection_manager.go
+++ b/E2Manager/managers/ran_disconnection_manager.go
@@ -65,10 +65,11 @@
 	}
 
 	if connectionStatus == entities.ConnectionStatus_SHUTTING_DOWN {
-		return m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_SHUT_DOWN)
+		_, err = m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_SHUT_DOWN)
+		return err
 	}
 
-	err = m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_DISCONNECTED)
+	_, err = m.ranConnectStatusChangeManager.ChangeStatus(nodebInfo, entities.ConnectionStatus_DISCONNECTED)
 
 	if err != nil {
 		return err
diff --git a/E2Manager/mocks/rnibWriterMock.go b/E2Manager/mocks/rnibWriterMock.go
index 35a255a..02237a4 100644
--- a/E2Manager/mocks/rnibWriterMock.go
+++ b/E2Manager/mocks/rnibWriterMock.go
@@ -52,6 +52,18 @@
 	return nil
 }
 
+func (rnibWriterMock *RnibWriterMock) UpdateNodebInfoAndPublish(nodebInfo *entities.NodebInfo) error {
+	args := rnibWriterMock.Called(nodebInfo)
+
+	errArg := args.Get(0)
+
+	if errArg != nil {
+		return errArg.(error)
+	}
+
+	return nil
+}
+
 func (rnibWriterMock *RnibWriterMock) SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error {
 	args := rnibWriterMock.Called(inventoryName, ranLoadInformation)
 
@@ -134,4 +146,4 @@
 func (rnibWriterMock *RnibWriterMock) AddEnb(nodebInfo *entities.NodebInfo) error {
 	args := rnibWriterMock.Called(nodebInfo)
 	return args.Error(0)
-}
\ No newline at end of file
+}
diff --git a/E2Manager/rNibWriter/rNibWriter.go b/E2Manager/rNibWriter/rNibWriter.go
index 7678fb3..670ee6b 100644
--- a/E2Manager/rNibWriter/rNibWriter.go
+++ b/E2Manager/rNibWriter/rNibWriter.go
@@ -46,6 +46,7 @@
 type RNibWriter interface {
 	SaveNodeb(nodebInfo *entities.NodebInfo) error
 	UpdateNodebInfo(nodebInfo *entities.NodebInfo) error
+	UpdateNodebInfoAndPublish(nodebInfo *entities.NodebInfo) error
 	SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error
 	SaveE2TInstance(e2tInstance *entities.E2TInstance) error
 	SaveE2TAddresses(addresses []string) error
@@ -340,10 +341,7 @@
 	return nil
 }
 
-/*
-UpdateNodebInfo...
-*/
-func (w *rNibWriterInstance) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error {
+func (w *rNibWriterInstance) updateNodebInfo(nodebInfo *entities.NodebInfo, publish bool) error {
 
 	pairs, err := buildUpdateNodebInfoPairs(nodebInfo)
 
@@ -351,7 +349,12 @@
 		return err
 	}
 
-	err = w.sdl.Set(pairs)
+	if publish {
+		channelsAndEvents := getChannelsAndEventsPair(w.rnibWriterConfig.RanManipulationMessageChannel, nodebInfo.RanName, RanUpdatedEvent)
+		err = w.sdl.SetAndPublish(channelsAndEvents, pairs)
+	} else {
+		err = w.sdl.Set(pairs)
+	}
 
 	if err != nil {
 		return common.NewInternalError(err)
@@ -361,6 +364,21 @@
 }
 
 /*
+UpdateNodebInfo...
+*/
+func (w *rNibWriterInstance) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error {
+	return w.updateNodebInfo(nodebInfo, false)
+}
+
+/*
+UpdateNodebInfoAndPublish...
+*/
+func (w *rNibWriterInstance) UpdateNodebInfoAndPublish(nodebInfo *entities.NodebInfo) error {
+	return w.updateNodebInfo(nodebInfo, true)
+}
+
+
+/*
 SaveRanLoadInformation stores ran load information for the provided ran
 */
 func (w *rNibWriterInstance) SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error {
diff --git a/E2Manager/services/rnib_data_service.go b/E2Manager/services/rnib_data_service.go
index 7d3d6c5..e2b5dc4 100644
--- a/E2Manager/services/rnib_data_service.go
+++ b/E2Manager/services/rnib_data_service.go
@@ -33,6 +33,7 @@
 type RNibDataService interface {
 	SaveNodeb(nodebInfo *entities.NodebInfo) error
 	UpdateNodebInfo(nodebInfo *entities.NodebInfo) error
+	UpdateNodebInfoAndPublish(nodebInfo *entities.NodebInfo) error
 	SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error
 	GetNodeb(ranName string) (*entities.NodebInfo, error)
 	GetListNodebIds() ([]*entities.NbIdentity, error)
@@ -142,6 +143,17 @@
 	return err
 }
 
+func (w *rNibDataService) UpdateNodebInfoAndPublish(nodebInfo *entities.NodebInfo) error {
+	w.logger.Infof("#RnibDataService.UpdateNodebInfoAndPublish - nodebInfo: %s", nodebInfo)
+
+	err := w.retry("UpdateNodebInfoAndPublish", func() (err error) {
+		err = w.rnibWriter.UpdateNodebInfoAndPublish(nodebInfo)
+		return
+	})
+
+	return err
+}
+
 func (w *rNibDataService) SaveNodeb(nodebInfo *entities.NodebInfo) error {
 	w.logger.Infof("#RnibDataService.SaveNodeb - nodebInfo: %s", nodebInfo)