NTP-4943 | making ee monitoring service webhook call upon severity update (#461)
* NTP-4943 | making ee monitoring service webhook call upon severity update * NTP-4943 | review comments resolved
This commit is contained in:
27
common/util/go_util.go
Normal file
27
common/util/go_util.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrTimeout = errors.New("task timed out")
|
||||
|
||||
func RunWithTimeout(timeout time.Duration, task func(ctx context.Context) error) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
done := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
done <- task(ctx)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-done:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ErrTimeout
|
||||
}
|
||||
}
|
||||
@@ -30,5 +30,4 @@ TEAM_NAME_MAX_LENGTH=100
|
||||
#incidents
|
||||
INCIDENTS_SHOW_LIMIT=10
|
||||
GOOGLE_AUTH_KEY_CONTENT={"type":"service_account","project_id":"houston-402208","private_key_id":"private-key","private_key":"key","client_email":"houston@houston-402208.iam.gserviceaccount.com","client_id":"104926879839085398481","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/houston%40houston-402208.iam.gserviceaccount.com","universe_domain":"googleapis.com"}
|
||||
GOOGLE_AUTH_EMAIL='houston@navi.com'
|
||||
|
||||
GOOGLE_AUTH_EMAIL='houston@navi.com'
|
||||
24
contracts/ee_monitoring_service_contracts.go
Normal file
24
contracts/ee_monitoring_service_contracts.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package contracts
|
||||
|
||||
type SeverityUpdateWebhookRequest struct {
|
||||
Requester string `json:"requester"`
|
||||
RequestType string `json:"requestType"`
|
||||
IncidentDetails IncidentDetails `json:"incidentDetails"`
|
||||
RequestMetaData SeverityUpdateRequestMetaData `json:"requestMetaData"`
|
||||
}
|
||||
|
||||
type IncidentDetails struct {
|
||||
IncidentType string `json:"incidentType"`
|
||||
IncidentID uint `json:"incidentId"`
|
||||
}
|
||||
|
||||
type SeverityUpdateRequestMetaData struct {
|
||||
OldSeverity SeverityInfo `json:"oldSeverity"`
|
||||
NewSeverity SeverityInfo `json:"newSeverity"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
}
|
||||
|
||||
type SeverityInfo struct {
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
75
pkg/monitoringService/ee_monitoring_service_client.go
Normal file
75
pkg/monitoringService/ee_monitoring_service_client.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package monitoringService
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"houston/contracts"
|
||||
"houston/logger"
|
||||
"houston/pkg/rest"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EEMonitoringServiceClientImpl struct {
|
||||
BaseURL string
|
||||
Client rest.HttpRestClient
|
||||
DefaultTimeout time.Duration
|
||||
WebhookAPIPath string
|
||||
}
|
||||
|
||||
func NewEEMonitoringServiceActionsImpl(client rest.HttpRestClient) *EEMonitoringServiceClientImpl {
|
||||
return &EEMonitoringServiceClientImpl{
|
||||
Client: client,
|
||||
BaseURL: viper.GetString("EE_MONITORING_SERVICE_BASEURL"),
|
||||
DefaultTimeout: viper.GetDuration("DEFAULT_EE_MONITORING_SERVICE_TIMEOUT"),
|
||||
WebhookAPIPath: viper.GetString("EE_MONITORING_SERVICE_WEBHOOK_API_PATH"),
|
||||
}
|
||||
}
|
||||
|
||||
func (client *EEMonitoringServiceClientImpl) TriggerSeverityUpdateWebhook(
|
||||
incidentId uint,
|
||||
triggerredBy string,
|
||||
requestId string,
|
||||
oldSeverity, newSeverity contracts.SeverityInfo,
|
||||
) error {
|
||||
logger.Info(fmt.Sprintf("Triggering severity update webhook for requestId: %s", requestId))
|
||||
fullURL := client.BaseURL + client.WebhookAPIPath
|
||||
requestHeaders := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"CORRELATION_ID": requestId,
|
||||
}
|
||||
|
||||
incidentDetails := contracts.IncidentDetails{
|
||||
IncidentType: "HOUSTON",
|
||||
IncidentID: incidentId,
|
||||
}
|
||||
|
||||
metaData := contracts.SeverityUpdateRequestMetaData{
|
||||
OldSeverity: oldSeverity,
|
||||
NewSeverity: newSeverity,
|
||||
UpdatedBy: triggerredBy,
|
||||
}
|
||||
requestBody := contracts.SeverityUpdateWebhookRequest{
|
||||
Requester: "HOUSTON",
|
||||
RequestType: "HOUSTON_SEVERITY_UPDATE",
|
||||
IncidentDetails: incidentDetails,
|
||||
RequestMetaData: metaData,
|
||||
}
|
||||
payload, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
logger.Error("Error while marshalling request body", zap.Error(err))
|
||||
return errors.New("error while marshalling request body")
|
||||
}
|
||||
|
||||
response, err := client.Client.PostWithTimeout(fullURL, *bytes.NewBuffer(payload), requestHeaders,
|
||||
client.DefaultTimeout, nil)
|
||||
if err != nil || response.StatusCode != http.StatusOK {
|
||||
logger.Error("Error while triggering webhook", zap.Error(err))
|
||||
return errors.New("error while triggering webhook")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package monitoringService
|
||||
|
||||
import "houston/contracts"
|
||||
|
||||
type EEMonitoringServiceClient interface {
|
||||
TriggerSeverityUpdateWebhook(
|
||||
incidentId uint, triggerredBy string, requestId string, oldSeverity, newSeverity contracts.SeverityInfo,
|
||||
) error
|
||||
}
|
||||
121
pkg/monitoringService/ee_monitoring_service_client_test.go
Normal file
121
pkg/monitoringService/ee_monitoring_service_client_test.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package monitoringService
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/gojuno/minimock/v3"
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"houston/common/util"
|
||||
"houston/contracts"
|
||||
"houston/logger"
|
||||
"houston/mocks"
|
||||
service "houston/service/response"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type EEMonitoringServiceSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (suite *EEMonitoringServiceSuite) SetupSuite() {
|
||||
logger.InitLogger()
|
||||
viper.Set("EE_MONITORING_SERVICE_BASEURL", "http://localhost:8082")
|
||||
viper.Set("DEFAULT_EE_MONITORING_SERVICE_TIMEOUT", "5s")
|
||||
viper.Set("EE_MONITORING_SERVICE_WEBHOOK_API_PATH", "/monitoring-webhook/trigger")
|
||||
viper.Set("DEFAULT_HTTP_REQUEST_TIMEOUT", "5s")
|
||||
}
|
||||
|
||||
func (suite *EEMonitoringServiceSuite) Test_TriggerWebhook_ErrorResponseCase() {
|
||||
controller := minimock.NewController(suite.T())
|
||||
suite.T().Cleanup(controller.Finish)
|
||||
requestId := uuid.NewString()
|
||||
|
||||
restClient := mocks.NewHttpRestClientMock(controller)
|
||||
|
||||
// Mocking HTTP calls
|
||||
defaultTimeOut := viper.GetDuration("DEFAULT_EE_MONITORING_SERVICE_TIMEOUT")
|
||||
fullURL := viper.GetString("EE_MONITORING_SERVICE_BASEURL") + viper.GetString("EE_MONITORING_SERVICE_WEBHOOK_API_PATH")
|
||||
|
||||
payload, _ := json.Marshal(getRequestBody())
|
||||
requestHeaders := map[string]string{
|
||||
"Content-Type": util.ContentTypeJSON,
|
||||
"CORRELATION_ID": requestId,
|
||||
}
|
||||
|
||||
restClient.PostWithTimeoutMock.When(fullURL, *bytes.NewBuffer(payload), requestHeaders, defaultTimeOut,
|
||||
nil).Then(nil, errors.New("error while getting grafana images"))
|
||||
|
||||
responseChannel := make(chan service.MonitoringServiceClientResponse)
|
||||
defer close(responseChannel)
|
||||
|
||||
err := NewEEMonitoringServiceActionsImpl(restClient).TriggerSeverityUpdateWebhook(
|
||||
1, "test", requestId, getOldSeverity(), getNewSeverity(),
|
||||
)
|
||||
suite.Error(err)
|
||||
}
|
||||
|
||||
func (suite *EEMonitoringServiceSuite) Test_TriggerWebhook_SuccessCase() {
|
||||
controller := minimock.NewController(suite.T())
|
||||
suite.T().Cleanup(controller.Finish)
|
||||
requestId := uuid.NewString()
|
||||
|
||||
restClient := mocks.NewHttpRestClientMock(controller)
|
||||
|
||||
// Mocking HTTP calls
|
||||
defaultTimeOut := viper.GetDuration("DEFAULT_EE_MONITORING_SERVICE_TIMEOUT")
|
||||
fullURL := viper.GetString("EE_MONITORING_SERVICE_BASEURL") + viper.GetString("EE_MONITORING_SERVICE_WEBHOOK_API_PATH")
|
||||
|
||||
payload, _ := json.Marshal(getRequestBody())
|
||||
requestHeaders := map[string]string{
|
||||
"Content-Type": util.ContentTypeJSON,
|
||||
"CORRELATION_ID": requestId,
|
||||
}
|
||||
response := &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: nil,
|
||||
}
|
||||
|
||||
restClient.PostWithTimeoutMock.When(fullURL, *bytes.NewBuffer(payload), requestHeaders, defaultTimeOut,
|
||||
nil).Then(response, nil)
|
||||
|
||||
responseChannel := make(chan service.MonitoringServiceClientResponse)
|
||||
defer close(responseChannel)
|
||||
err := NewEEMonitoringServiceActionsImpl(restClient).TriggerSeverityUpdateWebhook(
|
||||
1, "test", requestId, getOldSeverity(), getNewSeverity(),
|
||||
)
|
||||
|
||||
suite.Nil(err)
|
||||
}
|
||||
|
||||
func getRequestBody() *contracts.SeverityUpdateWebhookRequest {
|
||||
incidentDetails := contracts.IncidentDetails{
|
||||
IncidentType: "HOUSTON",
|
||||
IncidentID: 1,
|
||||
}
|
||||
metaData := contracts.SeverityUpdateRequestMetaData{
|
||||
OldSeverity: getOldSeverity(),
|
||||
NewSeverity: getNewSeverity(),
|
||||
UpdatedBy: "test",
|
||||
}
|
||||
return &contracts.SeverityUpdateWebhookRequest{
|
||||
Requester: "HOUSTON",
|
||||
RequestType: "HOUSTON_SEVERITY_UPDATE",
|
||||
IncidentDetails: incidentDetails,
|
||||
RequestMetaData: metaData,
|
||||
}
|
||||
}
|
||||
|
||||
func getOldSeverity() contracts.SeverityInfo {
|
||||
return contracts.SeverityInfo{Name: "Sev-1", ID: 2}
|
||||
}
|
||||
func getNewSeverity() contracts.SeverityInfo {
|
||||
return contracts.SeverityInfo{Name: "Sev-0", ID: 1}
|
||||
}
|
||||
|
||||
func TestEEMonitoringServiceClient(t *testing.T) {
|
||||
suite.Run(t, new(EEMonitoringServiceSuite))
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
slackClient "github.com/slack-go/slack"
|
||||
slackUtil "github.com/slack-go/slack"
|
||||
"github.com/spf13/viper"
|
||||
@@ -16,6 +18,7 @@ import (
|
||||
"houston/common/util/env"
|
||||
houstonSlackUtil "houston/common/util/slack"
|
||||
stringUtil "houston/common/util/string"
|
||||
"houston/contracts"
|
||||
"houston/internal/processor/action/view"
|
||||
"houston/logger"
|
||||
"houston/model/incident"
|
||||
@@ -32,6 +35,7 @@ import (
|
||||
"houston/pkg/atlassian/dto/response"
|
||||
"houston/pkg/conference"
|
||||
"houston/pkg/google/googleDrive"
|
||||
"houston/pkg/monitoringService"
|
||||
"houston/pkg/rest"
|
||||
"houston/repository/externalTeamRepo"
|
||||
"houston/repository/incidentStatus"
|
||||
@@ -104,6 +108,7 @@ type IncidentServiceV2 struct {
|
||||
incidentTeamService incidentTeam.IncidentTeamService
|
||||
incidentTeamTagValueService incidentTeamTagValue.IncidentTeamTagValueService
|
||||
logService *logService.LogService
|
||||
eeMonitoringServiceClient *monitoringService.EEMonitoringServiceClientImpl
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -166,7 +171,8 @@ func NewIncidentServiceV2(db *gorm.DB) *IncidentServiceV2 {
|
||||
incidentTeamTagValueService: incidentTeamTagValue.NewIncidentTeamTagValueService(
|
||||
incidentTeamTagValueRepo.NewIncidentTeamTagValueRepository(db),
|
||||
),
|
||||
logService: logService.NewLogService(nil, db),
|
||||
logService: logService.NewLogService(nil, db),
|
||||
eeMonitoringServiceClient: monitoringService.NewEEMonitoringServiceActionsImpl(rest.NewHttpRestClient()),
|
||||
}
|
||||
driveActions, _ := googleDrive.NewGoogleDriveActions()
|
||||
incidentService.rcaService = rcaServiceImpl.NewRcaService(
|
||||
@@ -1422,6 +1428,8 @@ func (i *IncidentServiceV2) UpdateSeverityId(
|
||||
return nil
|
||||
}
|
||||
|
||||
oldSeverity := contracts.SeverityInfo{Name: incidentEntity.Severity.Name, ID: incidentEntity.SeverityId}
|
||||
|
||||
severityId, err := strconv.Atoi(request.SeverityId)
|
||||
if err != nil {
|
||||
logger.Error("String conversion to int failed in UpdateSeverityId for "+request.SeverityId, zap.Error(err))
|
||||
@@ -1514,11 +1522,39 @@ func (i *IncidentServiceV2) UpdateSeverityId(
|
||||
}()
|
||||
}
|
||||
go i.SendAlert(incidentEntity)
|
||||
i.eeMonitoringServiceWebhookCall(incidentEntity, oldSeverity)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IncidentServiceV2) eeMonitoringServiceWebhookCall(
|
||||
incidentEntity *incident.IncidentEntity, oldSeverity contracts.SeverityInfo,
|
||||
) {
|
||||
task := func(ctx context.Context) error {
|
||||
entities, err := i.incidentRepository.GetIncidentsByIds([]uint{incidentEntity.ID})
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("error in fetching incident by id: %+v", err))
|
||||
}
|
||||
updatedIncident := entities[0]
|
||||
newSeverity := contracts.SeverityInfo{Name: updatedIncident.Severity.Name, ID: updatedIncident.SeverityId}
|
||||
err = i.eeMonitoringServiceClient.TriggerSeverityUpdateWebhook(
|
||||
incidentEntity.ID, incidentEntity.UpdatedBy, uuid.NewString(), oldSeverity, newSeverity,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("error in triggering severity update webhook: %+v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
err := util.RunWithTimeout(30*time.Second, task)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s Failed to trigger webhook: %v", updateLogTag, err))
|
||||
} else {
|
||||
logger.Info(fmt.Sprintf("%s Severity update webhook triggered successfully", updateLogTag))
|
||||
}
|
||||
}
|
||||
|
||||
func isValidRequestForUpdateSeverity(teamSeverityUpdateRule team.TeamSeverityUpdateRule, reportingTeam team.TeamEntity, userDTO *user.UserDTO) bool {
|
||||
strategy := teamSeverityUpdateRule.Strategy
|
||||
allowedUserIds := teamSeverityUpdateRule.AllowedUserIdsForSeverityChange
|
||||
|
||||
Reference in New Issue
Block a user