diff --git a/cmd/app/handler/incident_handler.go b/cmd/app/handler/incident_handler.go index 2f15c41..a5afcb6 100644 --- a/cmd/app/handler/incident_handler.go +++ b/cmd/app/handler/incident_handler.go @@ -43,28 +43,6 @@ func NewIncidentHandler( } } -func (handler *IncidentHandler) HandleCreateIncident(c *gin.Context) { - var createIncidentRequest incident.CreateIncidentRequestV2 - if err := c.ShouldBindJSON(&createIncidentRequest); err != nil { - c.JSON(http.StatusInternalServerError, err) - return - } - - if err := utils.ValidateCreateIncidentRequestV2(createIncidentRequest); err != nil { - logger.Error(fmt.Sprintf("%s Received invalid request to create new incident", logTag), zap.Error(err)) - c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - incidentResponse, err := handler.service.CreateIncident(createIncidentRequest, "API", "") - if err != nil { - logger.Error(fmt.Sprintf("%s Failed to create incident", logTag), zap.Error(err)) - metrics.PublishHoustonFlowFailureMetrics(incidentService.CREATE_INCIDENT, err.Error()) - c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusInternalServerError, nil)) - return - } - c.JSON(http.StatusOK, common.SuccessResponse(incidentResponse, http.StatusOK)) -} - func (handler *IncidentHandler) HandleCreateIncidentV3(c *gin.Context) { var createIncidentRequest incident.CreateIncidentRequestV3 if err := c.ShouldBindJSON(&createIncidentRequest); err != nil { diff --git a/cmd/app/handler/slack_handler.go b/cmd/app/handler/slack_handler.go index 0feca8e..ad0853d 100644 --- a/cmd/app/handler/slack_handler.go +++ b/cmd/app/handler/slack_handler.go @@ -29,7 +29,7 @@ import ( "github.com/spf13/viper" "go.uber.org/zap" "gorm.io/gorm" - logger "houston/logger" + "houston/logger" ) type slackHandler struct { diff --git a/cmd/app/server.go b/cmd/app/server.go index 3874da8..0ac16e5 100644 --- a/cmd/app/server.go +++ b/cmd/app/server.go @@ -161,12 +161,9 @@ func (s *Server) incidentClientHandler(houstonGroup *gin.RouterGroup) { origin := c.Request.Header.Get("Origin") c.Writer.Header().Set("Access-Control-Allow-Origin", origin) }) - //Will be deprecated because they are not using hosuton group - s.gin.POST("/create-incident", incidentHandler.CreateIncident) //TODO- Remove these api. Provide Multi Realm support in Internal Web BFF houstonGroup.GET("/incidents/unsecured/v2/:id", incidentHandler.GetIncidents) - houstonGroup.POST("/create-incident", incidentHandler.CreateIncident) } func (s *Server) productsHandler(houstonGroup *gin.RouterGroup) { @@ -216,7 +213,6 @@ func (s *Server) incidentClientHandlerV2(houstonGroup *gin.RouterGroup) { incidentServiceV2, ) incidentHandler := handler.NewIncidentHandler(s.gin, s.db, incidentServiceV2, incidentOrchestrator) - houstonGroup.POST("/create-incident-v2", incidentHandler.HandleCreateIncident) houstonGroup.POST("/create-incident-v3", incidentHandler.HandleCreateIncidentV3) s.gin.POST("/incidents", authService.IfValidHoustonUser(incidentHandler.HandleUpdateIncident)) diff --git a/common/metrics/metrics.go b/common/metrics/metrics.go index ce099fc..6d0c8e1 100644 --- a/common/metrics/metrics.go +++ b/common/metrics/metrics.go @@ -28,28 +28,6 @@ func PublishHttpServerRequestMetrics(url string, method string, responseCode int metrics.NewMetricPublisher().PublishMetrics(serverRequestMetric, ingester.HttpServerRequestMetrics) } -func PublishCronJobExecutionCounterMetrics(jobName string, duration float64) { - logger.Info("Publishing cron job execution counter metric") - cronJobMetric := ingester.MetricAttributes{ - CronJobExecutionCounterMetric: ingester.CronJobExecutionCounterMetric{ - JobName: jobName, - DurationInMs: duration, - }, - } - metrics.NewMetricPublisher().PublishMetrics(cronJobMetric, ingester.CronJobExecutionCounterMetrics) -} - -func PublishCronJobFailureMetrics(jobName string, errMessage string) { - logger.Info("Publishing cron job failure metric") - cronJobFailureMetric := ingester.MetricAttributes{ - CronJobFailureMetric: ingester.CronJobFailureMetric{ - JobName: jobName, - Error: errMessage, - }, - } - metrics.NewMetricPublisher().PublishMetrics(cronJobFailureMetric, ingester.CronJobFailureMetrics) -} - func PublishHoustonFlowFailureMetrics(flowName string, errMessage string) { logger.Info("Publishing houston flow failure metric") flowFailureMetric := ingester.MetricAttributes{ diff --git a/common/util/common_util.go b/common/util/common_util.go index b776b2d..9c2b9f0 100644 --- a/common/util/common_util.go +++ b/common/util/common_util.go @@ -149,19 +149,6 @@ func GetColorBySeverity(severityId uint) string { } } -func GetColourByOpenIncidents(openIncidents int) string { - switch { - case openIncidents <= 5: - return "#50C878" - case openIncidents <= 10: - return "#FDDA0D" - case openIncidents > 10: - return "#FF0000" - default: - return "#808080" - } -} - func PostIncidentStatusUpdateMessage(userId, updatedStatus, channelId string, client *socketmode.Client) error { msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> > set status to %s", userId, updatedStatus), false) _, _, errMessage := client.PostMessage(channelId, msgOption) @@ -180,12 +167,6 @@ func PostIncidentTypeUpdateMessage( return errMessage } -func PostIncidentSeverityUpdateMessage(userId, updatedSeverity, channelId string, client *socketmode.Client) error { - msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> > set severity to %s", userId, updatedSeverity), false) - _, _, errMessage := client.PostMessage(channelId, msgOption) - return errMessage -} - func RemoveDuplicateStr(strSlice []string) []string { allKeys := make(map[string]bool) list := []string{} diff --git a/common/util/slack/slack_helpers.go b/common/util/slack/slack_helpers.go index b628c5c..354d9f6 100644 --- a/common/util/slack/slack_helpers.go +++ b/common/util/slack/slack_helpers.go @@ -209,13 +209,3 @@ func BuildSlackTextMessageFromMetaData(metadata []byte, isCodeBlock bool) (slack return slack.MsgOptionText(textMessage, false), nil } - -func PostIncidentCustomerDataUpdateMessage(metadata *incidentRequest.CreateIncidentMetadata, userId, channelId string, client *socketmode.Client) error { - marshalledMetadata, _ := json.Marshal([]incidentRequest.CreateIncidentMetadata{*metadata}) - msgOption, err := BuildSlackTextMessageFromMetaData(marshalledMetadata, true) - if err != nil { - return err - } - _, _, errMessage := client.PostMessage(channelId, msgOption) - return errMessage -} diff --git a/internal/metrics/metric_publisher.go b/internal/metrics/metric_publisher.go index 5d8ae55..10179a1 100644 --- a/internal/metrics/metric_publisher.go +++ b/internal/metrics/metric_publisher.go @@ -42,20 +42,6 @@ func (amp *PublisherImpl) PublishMetrics(metricAttributes ingester.MetricAttribu } return } - case ingester.CronJobExecutionCounterMetrics: - { - if err := publishCronJobExecutionCounterMetric(metricAttributes.CronJobExecutionCounterMetric); err != nil { - logger.Error("error while publishing cron job execution counter metrics", zap.Error(err)) - } - return - } - case ingester.CronJobFailureMetrics: - { - if err := publishCronJobFailureMetric(metricAttributes.CronJobFailureMetric); err != nil { - logger.Error("error while publishing cron job failure metrics", zap.Error(err)) - } - return - } case ingester.HoustonFlowFailureMetrics: { if err := publishHoustonFlowFailureMetric(metricAttributes.HoustonFlowFailureMetric); err != nil { @@ -109,29 +95,6 @@ func publishHttpServerRequestMetric(serverRequestMetrics ingester.ServerRequestM return } -func publishCronJobExecutionCounterMetric(cronJobMetrics ingester.CronJobExecutionCounterMetric) (err error) { - defer func() { - if r := recover(); r != nil { - err = r.(error) - } - }() - CronJobExecutionCounter.WithLabelValues(cronJobMetrics.JobName).Inc() - CronJobExecutionDurationSum.WithLabelValues(cronJobMetrics.JobName).Add(cronJobMetrics.DurationInMs) - CronJobExecutionDurationHistogram.WithLabelValues(cronJobMetrics.JobName).Observe(cronJobMetrics.DurationInMs) - CronJobExecutionDurationSummary.WithLabelValues(cronJobMetrics.JobName).Observe(cronJobMetrics.DurationInMs) - return -} - -func publishCronJobFailureMetric(cronJobFailureMetrics ingester.CronJobFailureMetric) (err error) { - defer func() { - if r := recover(); r != nil { - err = r.(error) - } - }() - CronJobFailureCounter.WithLabelValues(cronJobFailureMetrics.JobName, cronJobFailureMetrics.Error).Inc() - return -} - func publishHoustonFlowFailureMetric(houstonFlowFailureMetrics ingester.HoustonFlowFailureMetric) (err error) { defer func() { if r := recover(); r != nil { diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 9419dda..609a58a 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -90,48 +90,6 @@ var ( []string{"url", "method", "response_code"}, ) - CronJobExecutionCounter = promauto.NewCounterVec( - prometheus.CounterOpts{ - Name: "houston_cron_job_execution_total", - Help: "Cron job execution counter", - }, - []string{"job_name"}, - ) - - CronJobExecutionDurationSum = promauto.NewCounterVec( - prometheus.CounterOpts{ - Name: "houston_cron_job_execution_duration_sum", - Help: "Cron job execution duration sum", - }, - []string{"job_name"}, - ) - - CronJobExecutionDurationHistogram = promauto.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "houston_cron_job_execution_duration_histogram", - Help: "Cron job execution duration histogram", - Buckets: cronExecutionDurationBuckets, - }, - []string{"job_name"}, - ) - - CronJobExecutionDurationSummary = promauto.NewSummaryVec( - prometheus.SummaryOpts{ - Name: "houston_cron_job_execution_duration_summary", - Help: "Cron job execution duration summary", - Objectives: quantileObjectives, - }, - []string{"job_name"}, - ) - - CronJobFailureCounter = promauto.NewCounterVec( - prometheus.CounterOpts{ - Name: "houston_cron_job_failure_total", - Help: "Cron job failure counter", - }, - []string{"job_name", "error"}, - ) - HoustonFlowFailureCounter = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "houston_flow_failure_total", diff --git a/internal/processor/action/incident_generate_rca_action.go b/internal/processor/action/incident_generate_rca_action.go index 6845b3a..e33c873 100644 --- a/internal/processor/action/incident_generate_rca_action.go +++ b/internal/processor/action/incident_generate_rca_action.go @@ -31,7 +31,7 @@ func NewIncidentGenerateRCAAction(client *socketmode.Client) *IncidentGenerateRC func (igr *IncidentGenerateRCAAction) GenerateRCAProcess(callback slack.InteractionCallback, request *socketmode.Request) { err := igr.slackService.UpdateMessageWithAttachments(callback.Channel.ID, callback.Message.Msg.Timestamp, view.GetRCAFailureAttachmentWithUpdatedMessage(callback.User.ID)) if err != nil { - logger.Error(fmt.Sprintf("Rca gneration error message update failed due to %s", err.Error())) + logger.Error(fmt.Sprintf("Rca generation error message update failed due to %s", err.Error())) } igr.client.Ack(*request) incidentEntity, err := igr.incidentServiceV2.GetIncidentByChannelID(callback.Channel.ID) diff --git a/internal/processor/action/incident_jira_links_action.go b/internal/processor/action/incident_jira_links_action.go index 634d6b1..1b3af6d 100644 --- a/internal/processor/action/incident_jira_links_action.go +++ b/internal/processor/action/incident_jira_links_action.go @@ -1,24 +1,16 @@ package action import ( - "errors" - "fmt" "github.com/slack-go/slack" - "github.com/spf13/viper" "houston/appcontext" "houston/common/util" "houston/internal/processor/action/view" - "houston/logger" - "houston/model/incident" incidentJiraModel "houston/model/incident_jira" - incidentService "houston/service/incident" "houston/service/incident_jira" slack2 "houston/service/slack" - "strings" ) type IncidentJiraLinksAction struct { - incidentService incidentService.IIncidentService incidentJiraService incident_jira.IncidentJiraService slackService slack2.ISlackService } @@ -28,11 +20,9 @@ const ( ) func NewIncidentJiraLinksAction( - incidentService incidentService.IIncidentService, slackService slack2.ISlackService, ) *IncidentJiraLinksAction { return &IncidentJiraLinksAction{ - incidentService: incidentService, incidentJiraService: incident_jira.NewIncidentJiraService(incidentJiraModel.NewIncidentJiraRepo(appcontext.GetDB())), slackService: slackService, } @@ -44,84 +34,6 @@ func (action *IncidentJiraLinksAction) getJiraLinksBlock(initialValue string) *s return view.CreatePlainTextInputBlock(jiraLinksBlockData) } -// Deprecated: updateJiraLinks is deprecated. Use updateIncidentJiraLinks instead -func (action *IncidentJiraLinksAction) updateJiraLinks(jiraLinks string, callback slack.InteractionCallback, incidentEntity *incident.IncidentEntity) error { - channelID := callback.View.PrivateMetadata - formattedJiraLinks := strings.Split( - strings.ReplaceAll(strings.ReplaceAll(jiraLinks, "\n", ""), " ", ""), - ",", - ) - compareResults := util.CompareAndGetStringArrayResults(incidentEntity.JiraLinks, formattedJiraLinks) - //Update jira links only if there is a change. Validate by checking if there are any unique elements in either array - //If there are no unique elements in either array, then there is no change and skip the update - if !(len(compareResults.UniqueElementsInArrayA) == 0 && len(compareResults.UniqueElementsInArrayB) == 0) { - jiraLinksToBeUpdated := append(compareResults.CommonElements, compareResults.UniqueElementsInArrayB...) - //Below validation make sure that blank jira links are not to be tested for valid jira link - if len(jiraLinksToBeUpdated) > 0 && jiraLinksToBeUpdated[0] != "" { - for _, link := range jiraLinksToBeUpdated { - //Validate jira link - if !strings.HasPrefix(link, viper.GetString("navi.jira.base.url")) { - err := action.slackService.PostEphemeralByChannelID(fmt.Sprintf("%s is not a valid jira link", link), callback.User.ID, false, channelID) - if err != nil { - logger.Error(fmt.Sprintf("%s failed to post jira link validation failure ephemeral to slack channel: %s", logTag, incidentEntity.IncidentName)) - return err - } - return errors.New(fmt.Sprintf("%s is a invalid jira link", link)) - } - } - } - err := action.incidentService.UpdateIncidentJiraLinksEntity(incidentEntity, callback.User.ID, jiraLinksToBeUpdated) - if err != nil { - logger.Error(fmt.Sprintf("%s unable to update jira link(s) for incident %s", logTag, incidentEntity.IncidentName)) - return err - } - } - return nil -} - -func (action *IncidentJiraLinksAction) updateIncidentJiraLinks(jiraLinks string, incidentEntity *incident.IncidentEntity) error { - err := action.incidentJiraService.RemoveAllJiraLinksByIncidentID(incidentEntity.ID) - if err != nil { - logger.Error(fmt.Sprintf("%s unable to remove jira links for incident %s", logTag, incidentEntity.IncidentName)) - return err - } - - validatedJiraLinksPtr, err := action.getValidatedJiraLinks(jiraLinks) - if err != nil { - return err - } - - if validatedJiraLinksPtr != nil && len(*validatedJiraLinksPtr) > 0 { - _, err = action.incidentJiraService.AddJiraLinksByIncidentID(incidentEntity.ID, *validatedJiraLinksPtr) - if err != nil { - logger.Error(fmt.Sprintf("%s unable to add jira link(s) for incident %s", logTag, incidentEntity.IncidentName)) - return err - } - } - - return nil -} - func (action *IncidentJiraLinksAction) GetIncidentJiraLinks(incidentID uint) (*[]incidentJiraModel.IncidentJiraEntity, error) { return action.incidentJiraService.GetJiraLinksByIncidentID(incidentID) } - -func (action *IncidentJiraLinksAction) getValidatedJiraLinks(jiraLinks string) (*[]string, error) { - var formattedJiraLinks []string - if jiraLinks != "" { - formattedJiraLinks = strings.Split( - strings.ReplaceAll(strings.ReplaceAll(jiraLinks, "\n", ""), " ", ""), - ",", - ) - } - - if len(formattedJiraLinks) > 0 && formattedJiraLinks != nil { - for _, link := range formattedJiraLinks { - //Validate jira link - if !strings.HasPrefix(link, viper.GetString("navi.jira.base.url")) { - return nil, errors.New(fmt.Sprintf("%s is not a valid Jira link", link)) - } - } - } - return &formattedJiraLinks, nil -} diff --git a/internal/processor/action/incident_jira_links_action_test.go b/internal/processor/action/incident_jira_links_action_test.go deleted file mode 100644 index 6e3518c..0000000 --- a/internal/processor/action/incident_jira_links_action_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package action - -import ( - "errors" - "github.com/gojuno/minimock/v3" - "github.com/slack-go/slack" - "github.com/spf13/viper" - "github.com/stretchr/testify/suite" - "houston/logger" - "houston/mocks" - "strings" - "testing" -) - -func getJiraLinks() []string { - return []string{"https://navihq.atlassian.net/browse/TP-44155", "https://navihq.atlassian.net/browse/TP-44157"} -} - -type IncidentJiraLinksActionSuite struct { - suite.Suite -} - -func TestIncidentJiraLinksAction(t *testing.T) { - suite.Run(t, new(IncidentJiraLinksActionSuite)) -} - -func (suite *IncidentJiraLinksActionSuite) SetupSuite() { - logger.InitLogger() - viper.Set("navi.jira.base.url", "https://navihq.atlassian.net/browse/") -} - -func (suite *IncidentJiraLinksActionSuite) TestUpdateJiraLinksFailureAtUpdatingEntity() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentService := mocks.NewIIncidentServiceMock(controller) - slackService := mocks.NewISlackServiceMock(controller) - incidentService.UpdateIncidentJiraLinksEntityMock.Return(errors.New("failure while updating jira links")) - jiraLinksActions := NewIncidentJiraLinksAction(incidentService, slackService) - err := jiraLinksActions.updateJiraLinks(strings.Join(getJiraLinks(), ", "), slack.InteractionCallback{}, getMockIncidentEntity()) - suite.EqualError(err, "failure while updating jira links") -} - -func (suite *IncidentJiraLinksActionSuite) TestUpdateJiraLinksFailureForInvalidJiraLink() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentService := mocks.NewIIncidentServiceMock(controller) - slackService := mocks.NewISlackServiceMock(controller) - slackService.PostEphemeralByChannelIDMock.Return(nil) - jiraLinksActions := NewIncidentJiraLinksAction(incidentService, slackService) - err := jiraLinksActions.updateJiraLinks("dsa", slack.InteractionCallback{}, getMockIncidentEntity()) - suite.EqualError(err, "dsa is a invalid jira link") -} - -func (suite *IncidentJiraLinksActionSuite) TestUpdateJiraLinksSuccessBlankValue() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentService := mocks.NewIIncidentServiceMock(controller) - slackService := mocks.NewISlackServiceMock(controller) - incidentService.UpdateIncidentJiraLinksEntityMock.Return(nil) - jiraLinksActions := NewIncidentJiraLinksAction(incidentService, slackService) - err := jiraLinksActions.updateJiraLinks("", slack.InteractionCallback{}, getMockIncidentEntity()) - suite.NoError(err) -} - -func (suite *IncidentJiraLinksActionSuite) TestUpdateJiraLinksSuccessDiffValue() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentService := mocks.NewIIncidentServiceMock(controller) - slackService := mocks.NewISlackServiceMock(controller) - incidentService.UpdateIncidentJiraLinksEntityMock.Return(nil) - jiraLinksActions := NewIncidentJiraLinksAction(incidentService, slackService) - err := jiraLinksActions.updateJiraLinks(strings.Join(getJiraLinks(), ", "), slack.InteractionCallback{}, getMockIncidentEntity()) - suite.NoError(err) -} - -func (suite *IncidentJiraLinksActionSuite) TestUpdateJiraLinksSuccessSameValue() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentService := mocks.NewIIncidentServiceMock(controller) - slackService := mocks.NewISlackServiceMock(controller) - jiraLinksActions := NewIncidentJiraLinksAction(incidentService, slackService) - err := jiraLinksActions.updateJiraLinks(strings.Join(getMockIncidentEntity().JiraLinks, ", "), slack.InteractionCallback{}, getMockIncidentEntity()) - suite.NoError(err) -} diff --git a/internal/processor/action/incident_rca_details_action.go b/internal/processor/action/incident_rca_details_action.go index 9dc0064..ae809fd 100644 --- a/internal/processor/action/incident_rca_details_action.go +++ b/internal/processor/action/incident_rca_details_action.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" - "github.com/spf13/viper" "go.uber.org/zap" "houston/common/jira" "houston/common/metrics" @@ -108,55 +107,22 @@ func (action *IncidentRCASectionAction) PerformSetIncidentRCADetailsAction( var payload interface{} action.client.Ack(*request, payload) - if viper.GetBool("RESOLVE_INCIDENT_SLACK_REFACTOR_ENABLED") { - request, err := service.ConvertSlackActionToResolveIncidentRequest(actions, incidentEntity.ID) - if err != nil { - logger.Error( - fmt.Sprintf("Error while creating resolve request for incident id: %d", incidentEntity.ID), - zap.Error(err), - ) - return - } - - err = action.incidentService.ExecuteIncidentResolveFlow( - *request, incidentEntity, callback.User.ID, string(requesterType), + resolveIncidentRequest, err := service.ConvertSlackActionToResolveIncidentRequest(actions, incidentEntity.ID) + if err != nil { + logger.Error( + fmt.Sprintf("Error while creating resolve request for incident id: %d", incidentEntity.ID), + zap.Error(err), ) - if err != nil { - metrics.PublishHoustonFlowFailureMetrics(incidentServiceImpl.RESOLVE_INCIDENT, err.Error()) - logger.Error(fmt.Sprintf("Error while resolving incident with id: %d", incidentEntity.ID), zap.Error(err)) - } return } - err = action.tagsAction.updateTags(actions, callback, incidentEntity) + err = action.incidentService.ExecuteIncidentResolveFlow( + *resolveIncidentRequest, incidentEntity, callback.User.ID, string(requesterType), + ) if err != nil { - logger.Error(fmt.Sprintf("failed to update the incicent tags for incident id: %v", incidentEntity.ID)) + metrics.PublishHoustonFlowFailureMetrics(incidentServiceImpl.RESOLVE_INCIDENT, err.Error()) + logger.Error(fmt.Sprintf("Error while resolving incident with id: %d", incidentEntity.ID), zap.Error(err)) } - rcaValue := actions[util.SetRCASummary].Value - err = action.rcaSummaryAction.updateRCASummary(rcaValue, incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("failed to update rca summary for incident id: %v", incidentEntity.ID)) - } - jiraLinksValue := actions[util.SetJiraLinks].Value - err = action.jiraAction.updateIncidentJiraLinks(jiraLinksValue, incidentEntity) - if err != nil { - _, _ = action.client.PostEphemeral( - callback.View.PrivateMetadata, - callback.User.ID, - slack.MsgOptionText(fmt.Sprintf("Failed to update Jira link(s). %s", err.Error()), false), - ) - logger.Error(fmt.Sprintf("failed to update Jira link(s) for incident id: %v. %+v", incidentEntity.ID, err)) - } else { - //todo: this is to be removed after jira_links column is removed from incident table - err = action.jiraAction.updateJiraLinks(jiraLinksValue, callback, incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("failed to update Jira link(s) for incident id: %v", incidentEntity.ID)) - } - } - updatedIncidentEntity, _ := action.incidentRepository.FindIncidentById(incidentEntity.ID) - tagValuesMap, _ := action.tagsAction.getIncidentTagValuesAsMap(incidentEntity.ID) - action.postRCADetailsBlock(updatedIncidentEntity, tagValuesMap) - action.performPostUpdateActions(requesterType, callback, request) } func (action *IncidentRCASectionAction) PerformShowRCADetailsAction(callback slack.InteractionCallback, request *socketmode.Request) { @@ -171,15 +137,6 @@ func (action *IncidentRCASectionAction) PerformShowRCADetailsAction(callback sla action.postRCADetailsBlock(incidentEntity, tagValuesMap) } -func (action *IncidentRCASectionAction) performPostUpdateActions(requesterType util.ViewSubmissionType, callback slack.InteractionCallback, request *socketmode.Request) { - switch requesterType { - case util.IncidentResolveSubmit: - resolveAction := NewIncidentResolveProcessor(action.client, action.incidentRepository, action.tagRepository, action.teamRepository, action.severityRepository, action.rcaService) - resolveAction.IncidentResolveProcess(callback, request) - - } -} - func (action *IncidentRCASectionAction) postRCADetailsBlock(entity *incident.IncidentEntity, tagValueMaps map[string][]string) { blocks := view.ConstructShowRCADetailsBlock(entity, tagValueMaps) color := util.GetColorBySeverity(4) diff --git a/internal/processor/action/incident_rca_summary_action.go b/internal/processor/action/incident_rca_summary_action.go index f4df42b..41b27cd 100644 --- a/internal/processor/action/incident_rca_summary_action.go +++ b/internal/processor/action/incident_rca_summary_action.go @@ -1,23 +1,16 @@ package action import ( - "fmt" "github.com/slack-go/slack" "houston/common/util" "houston/internal/processor/action/view" - "houston/logger" - "houston/model/incident" - "strings" ) type IncidentRCASummaryAction struct { - incidentRepository incident.IIncidentRepository } -func NewIncidentRCASummaryAction(incidentService incident.IIncidentRepository) *IncidentRCASummaryAction { - return &IncidentRCASummaryAction{ - incidentRepository: incidentService, - } +func NewIncidentRCASummaryAction() *IncidentRCASummaryAction { + return &IncidentRCASummaryAction{} } func (action *IncidentRCASummaryAction) getRCASummaryBlock(rcaInitialValue string) *slack.InputBlock { @@ -25,19 +18,3 @@ func (action *IncidentRCASummaryAction) getRCASummaryBlock(rcaInitialValue strin rcaBlockData := view.SimpleInputBlockElementData{BasicData: rcaBlockBasicData, InitialValue: rcaInitialValue} return view.CreatePlainTextInputBlock(rcaBlockData) } - -func (action *IncidentRCASummaryAction) updateRCASummary(rcaValue string, incidentEntity *incident.IncidentEntity) error { - trimmedRCA := strings.TrimSpace(rcaValue) - //Update RCA only if provided RCA is nt blank and different from existing - if trimmedRCA != incidentEntity.RCA { - incidentEntity.RCA = trimmedRCA - err := action.incidentRepository.UpdateIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("IncidentUpdateRca error for incident %s : %s", incidentEntity.IncidentName, err.Error())) - return err - } - } else { - logger.Info(fmt.Sprintf("RCA is not changed for incident %s", incidentEntity.IncidentName)) - } - return nil -} diff --git a/internal/processor/action/incident_rca_summary_action_test.go b/internal/processor/action/incident_rca_summary_action_test.go deleted file mode 100644 index af113e0..0000000 --- a/internal/processor/action/incident_rca_summary_action_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package action - -import ( - "errors" - "github.com/gojuno/minimock/v3" - "github.com/stretchr/testify/suite" - "houston/logger" - "houston/mocks" - "houston/model/incident" - "testing" -) - -func getMockIncidentEntity() *incident.IncidentEntity { - return &incident.IncidentEntity{IncidentName: "test", RCA: "test", JiraLinks: []string{"https://navihq.atlassian.net/browse/TP-44157", "https://navihq.atlassian.net/browse/TP-44158"}} -} - -type IncidentRCASummaryActionSuite struct { - suite.Suite -} - -func TestIncidentRCASummaryActions(t *testing.T) { - suite.Run(t, new(IncidentRCASummaryActionSuite)) -} - -func (suite *IncidentRCASummaryActionSuite) SetupSuite() { - logger.InitLogger() -} - -func (suite *IncidentRCASummaryActionSuite) TestUpdateRCASummaryFailure() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentRepo := mocks.NewIIncidentRepositoryMock(controller) - incidentRepo.UpdateIncidentMock.Return(errors.New("failure while updating incident")) - rcaSummaryActions := NewIncidentRCASummaryAction(incidentRepo) - err := rcaSummaryActions.updateRCASummary("", getMockIncidentEntity()) - suite.EqualError(err, "failure while updating incident") -} - -func (suite *IncidentRCASummaryActionSuite) TestUpdateRCASummarySuccessForSameRCAValue() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentRepo := mocks.NewIIncidentRepositoryMock(controller) - rcaSummaryActions := NewIncidentRCASummaryAction(incidentRepo) - err := rcaSummaryActions.updateRCASummary("test", getMockIncidentEntity()) - suite.NoError(err) -} - -func (suite *IncidentRCASummaryActionSuite) TestUpdateRCASummarySuccess() { - controller := minimock.NewController(suite.T()) - suite.T().Cleanup(controller.Finish) - incidentRepo := mocks.NewIIncidentRepositoryMock(controller) - incidentRepo.UpdateIncidentMock.Return(nil) - rcaSummaryActions := NewIncidentRCASummaryAction(incidentRepo) - err := rcaSummaryActions.updateRCASummary("test1", getMockIncidentEntity()) - suite.NoError(err) -} diff --git a/internal/processor/action/incident_update_severity_action.go b/internal/processor/action/incident_update_severity_action.go index 942606e..15a4b8d 100644 --- a/internal/processor/action/incident_update_severity_action.go +++ b/internal/processor/action/incident_update_severity_action.go @@ -4,10 +4,8 @@ import ( "fmt" "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" - "github.com/spf13/viper" "go.uber.org/zap" "houston/common/metrics" - incidentHelper "houston/common/util" "houston/common/util/structUtil" "houston/internal/processor/action/view" "houston/logger" @@ -18,10 +16,9 @@ import ( incidentService "houston/service/incident/impl" service "houston/service/request" "strconv" - "time" ) -type IncidentUpdateSevertityAction struct { +type IncidentUpdateSeverityAction struct { client *socketmode.Client severityRepository *severity.Repository incidentRepository *incident.Repository @@ -37,8 +34,8 @@ func NewIncidentUpdateSeverityAction( teamRepository *team.Repository, slackbotClient *slackbot.Client, incidentServiceV2 *incidentService.IncidentServiceV2, -) *IncidentUpdateSevertityAction { - return &IncidentUpdateSevertityAction{ +) *IncidentUpdateSeverityAction { + return &IncidentUpdateSeverityAction{ client: client, severityRepository: severityRepository, incidentRepository: incidentRepository, @@ -53,7 +50,7 @@ type JustificationMetadata struct { ChannelId string } -func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityRequestProcess(callback slack.InteractionCallback, request *socketmode.Request) { +func (isp *IncidentUpdateSeverityAction) IncidentUpdateSeverityRequestProcess(callback slack.InteractionCallback, request *socketmode.Request) { incidentSeverity, err := isp.severityRepository.GetAllActiveSeverity() if err != nil || incidentSeverity == nil { logger.Error("FindSeverityEntity error", @@ -65,7 +62,7 @@ func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityRequestProcess(c _, err = isp.client.OpenView(callback.TriggerID, modalRequest) if err != nil { - logger.Error("houston slackbot openview command failed.", + logger.Error("houston slackbot open view command failed.", zap.String("trigger_id", callback.TriggerID), zap.String("channel_id", callback.Channel.ID), zap.Error(err)) return } @@ -73,7 +70,7 @@ func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityRequestProcess(c isp.client.Ack(*request, payload) } -func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityJustification(callback slack.InteractionCallback, request *socketmode.Request, user slack.User) { +func (isp *IncidentUpdateSeverityAction) IncidentUpdateSeverityJustification(callback slack.InteractionCallback, request *socketmode.Request, user slack.User) { var justificationMetadata JustificationMetadata err := structUtil.StringToStruct(callback.View.PrivateMetadata, &justificationMetadata) if err != nil { @@ -115,10 +112,9 @@ func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityJustification(ca logger.Error(fmt.Sprintf("error in updating severity: %v", err)) metrics.PublishHoustonFlowFailureMetrics(incidentService.UPDATE_INCIDENT_SEVERITY, err.Error()) } - return } -func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverity(callback slack.InteractionCallback, request *socketmode.Request, channel slack.Channel, user slack.User) { +func (isp *IncidentUpdateSeverityAction) IncidentUpdateSeverity(callback slack.InteractionCallback, request *socketmode.Request, channel slack.Channel, user slack.User) { channelId := callback.View.PrivateMetadata incidentEntity, err := isp.incidentRepository.FindIncidentByChannelId(channelId) if err != nil { @@ -135,134 +131,44 @@ func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverity(callback slack. incidentSeverityId := buildUpdateIncidentSeverityRequest(callback.View.State.Values) - if viper.GetBool("UPDATE_INCIDENT_V2_ENABLED") { - var payload interface{} - isp.client.Ack(*request, payload) - teamEntity, _, incidentStatusEntity, incidentChannels, err := isp.incidentServiceV2.FetchAllEntitiesForIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err)) - return - } - if viper.GetBool("ENABLE_DE_ESCALATION_JUSTIFICATION") { - if uint(incidentSeverityId) > incidentEntity.SeverityId { - justificationMetadata := JustificationMetadata{SeverityId: uint(incidentSeverityId), ChannelId: channelId} - stringData, stringErr := structUtil.StructToString(justificationMetadata) - if stringErr != nil { - logger.Error(fmt.Sprintf("error in converting justification metadata to string for incident id: %d", incidentEntity.ID), zap.Error(stringErr)) - } - _, viewErr := isp.client.OpenView(callback.TriggerID, view.CreateSeverityJustificationBlock(stringData)) - if viewErr != nil { - logger.Error(fmt.Sprintf("error in opening justification view for incident with id: %d", incidentEntity.ID), zap.Error(viewErr)) - } - return - } - } - - if err := isp.incidentServiceV2.UpdateSeverityId( - service.UpdateIncidentRequest{ - Id: incidentEntity.ID, - SeverityId: strconv.Itoa(incidentSeverityId), - MetaData: nil, - }, - user.ID, - incidentEntity, - teamEntity, - incidentStatusEntity, - incidentChannels, - ); err != nil { - logger.Error(fmt.Sprintf("error in updating severity: %v", err)) - metrics.PublishHoustonFlowFailureMetrics(incidentService.UPDATE_INCIDENT_SEVERITY, err.Error()) - } - return - } - - incidentSeverityEntity, err := isp.severityRepository.FindIncidentSeverityEntityById(incidentSeverityId) - if err != nil { - logger.Error("FindIncidentSeverityEntityById error", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - return - } else if incidentSeverityEntity == nil { - logger.Error("SeverityEntity not found", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - return - } - incidentEntity.SeverityId = incidentSeverityEntity.ID - incidentEntity.UpdatedBy = user.ID - incidentEntity.SeverityTat = time.Now().AddDate(0, 0, incidentSeverityEntity.Sla) - err = isp.incidentRepository.UpdateIncident(incidentEntity) - if err != nil { - logger.Error("UpdateIncident error", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - } - teamEntity, err := isp.teamRepository.FindTeamById(incidentEntity.TeamId) - - for _, o := range incidentSeverityEntity.SlackUserIds { - isp.slackbotClient.InviteUsersToConversation(callback.View.PrivateMetadata, o) - } - go func() { - msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `set severity to %s (%s)`", user.ID, incidentSeverityEntity.Name, incidentSeverityEntity.Description), false) - _, _, errMessage := isp.client.PostMessage(callback.View.PrivateMetadata, msgOption) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateSeverity", zap.Error(errMessage)) - return - } - - if err != nil { - logger.Error("FindTeamEntityById error", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - return - } else if teamEntity == nil { - logger.Error("Team Not Found", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - return - } - - txt := fmt.Sprintf("set the channel topic: *%s · %s (%s) %s* | %s", teamEntity.Name, incidentSeverityEntity.Name, incidentSeverityEntity.Description, incidentEntity.IncidentName, incidentEntity.Title) - att := slack.Attachment{ - Text: txt, - Color: "#808080", // Grey color code - MarkdownIn: []string{"txt"}, // Define which fields support markdown - } - _, _, errMessage = isp.client.PostMessage(callback.View.PrivateMetadata, slack.MsgOptionAttachments(att)) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateType", zap.Error(errMessage)) - return - } - - topic := fmt.Sprintf("%s-%s(%s) Incident-%d | %s", teamEntity.Name, incidentSeverityEntity.Name, incidentSeverityEntity.Description, incidentEntity.ID, incidentEntity.Title) - isp.slackbotClient.SetChannelTopic(callback.View.PrivateMetadata, topic) - }() - - incidentHelper.TagPseOrDevOncallToIncident( - callback.View.PrivateMetadata, - incidentSeverityEntity, - teamEntity, - isp.slackbotClient, - isp.client, - ) - - err = incidentHelper.AssignResponderToIncident( - isp.incidentRepository, - incidentEntity, - teamEntity, - incidentSeverityEntity, - isp.client, - user.ID, - ) - if err != nil { - logger.Error("[Update incident severity] Error while assigning responder to the incident ", zap.Error(err)) - } - var payload interface{} isp.client.Ack(*request, payload) + teamEntity, _, incidentStatusEntity, incidentChannels, err := isp.incidentServiceV2.FetchAllEntitiesForIncident(incidentEntity) + if err != nil { + logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err)) + return + } + + if uint(incidentSeverityId) > incidentEntity.SeverityId { + justificationMetadata := JustificationMetadata{SeverityId: uint(incidentSeverityId), ChannelId: channelId} + stringData, stringErr := structUtil.StructToString(justificationMetadata) + if stringErr != nil { + logger.Error(fmt.Sprintf("error in converting justification metadata to string for incident id: %d", incidentEntity.ID), zap.Error(stringErr)) + } + _, viewErr := isp.client.OpenView(callback.TriggerID, view.CreateSeverityJustificationBlock(stringData)) + if viewErr != nil { + logger.Error(fmt.Sprintf("error in opening justification view for incident with id: %d", incidentEntity.ID), zap.Error(viewErr)) + } + return + } + + if err := isp.incidentServiceV2.UpdateSeverityId( + service.UpdateIncidentRequest{ + Id: incidentEntity.ID, + SeverityId: strconv.Itoa(incidentSeverityId), + MetaData: nil, + }, + user.ID, + incidentEntity, + teamEntity, + incidentStatusEntity, + incidentChannels, + ); err != nil { + logger.Error(fmt.Sprintf("error in updating severity: %v", err)) + metrics.PublishHoustonFlowFailureMetrics(incidentService.UPDATE_INCIDENT_SEVERITY, err.Error()) + } } -// TODO - ADD USER ACCORDING TO SEVERITY func buildUpdateIncidentSeverityRequest(blockActions map[string]map[string]slack.BlockAction) int { var requestMap = make(map[string]string, 0) for _, actions := range blockActions { @@ -276,7 +182,7 @@ func buildUpdateIncidentSeverityRequest(blockActions map[string]map[string]slack selectedValue := requestMap["incident_severity_modal_request"] selectedValueInInt, err := strconv.Atoi(selectedValue) if err != nil { - logger.Error("String conversion to int faileed in buildUpdateIncidentResponderTeamRequest for "+selectedValue, zap.Error(err)) + logger.Error("String conversion to int failed in buildUpdateIncidentResponderTeamRequest for "+selectedValue, zap.Error(err)) } return selectedValueInInt } diff --git a/internal/processor/action/incident_update_status_action.go b/internal/processor/action/incident_update_status_action.go index 274e061..ea69f37 100644 --- a/internal/processor/action/incident_update_status_action.go +++ b/internal/processor/action/incident_update_status_action.go @@ -5,17 +5,15 @@ import ( "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" "go.uber.org/zap" - "houston/common/util" - houstonSlackUtil "houston/common/util/slack" + "houston/common/metrics" "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" "houston/model/severity" "houston/model/tag" "houston/model/team" - "math" - "strconv" - "time" + incidentV2 "houston/service/incident/impl" + service "houston/service/request" ) type UpdateIncidentAction struct { @@ -24,15 +22,23 @@ type UpdateIncidentAction struct { tagService *tag.Repository teamRepository *team.Repository severityRepository *severity.Repository + incidentServiceV2 *incidentV2.IncidentServiceV2 } -func NewIncidentUpdateAction(client *socketmode.Client, incidentService *incident.Repository, tagService *tag.Repository, teamRepository *team.Repository, severityRepository *severity.Repository) *UpdateIncidentAction { +func NewIncidentUpdateAction( + client *socketmode.Client, + incidentService *incident.Repository, + tagService *tag.Repository, + teamRepository *team.Repository, + severityRepository *severity.Repository, + incidentServiceV2 *incidentV2.IncidentServiceV2) *UpdateIncidentAction { return &UpdateIncidentAction{ client: client, incidentService: incidentService, tagService: tagService, teamRepository: teamRepository, severityRepository: severityRepository, + incidentServiceV2: incidentServiceV2, } } @@ -55,7 +61,6 @@ func (isp *UpdateIncidentAction) IncidentUpdateStatusRequestProcess(callback sla isp.client.Ack(*request, payload) } -// todo: this method has to be replaced with incident-service-v2 UpdateStatus method func (isp *UpdateIncidentAction) IncidentUpdateStatus(callback slack.InteractionCallback, request *socketmode.Request, channel slack.Channel, user slack.User) { incidentEntity, err := isp.incidentService.FindIncidentByChannelId(callback.View.PrivateMetadata) if err != nil { @@ -68,77 +73,37 @@ func (isp *UpdateIncidentAction) IncidentUpdateStatus(callback slack.Interaction zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), zap.String("user_id", user.ID), zap.Error(err)) return - } incidentStatusId := buildUpdateIncidentStatusRequest(callback.View.State.Values) - result, err := isp.incidentService.FindIncidentStatusById(incidentStatusId) + + teamEntity, severityEntity, _, incidentChannels, err := isp.incidentServiceV2.FetchAllEntitiesForIncident(incidentEntity) if err != nil { - logger.Error("FindIncidentStatusById error", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - return - } else if result == nil { - logger.Error("IncidentStatusEntity Object not found", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) + logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err)) return } var payload interface{} isp.client.Ack(*request, payload) - channelId := callback.View.PrivateMetadata - if incidentEntity.Status == result.ID { - houstonSlackUtil.PostIncidentStatusErrorMessage(result.Name, channelId, callback.User.ID, isp.client) + if err := isp.incidentServiceV2.UpdateStatus( + service.UpdateIncidentRequest{ + Id: incidentEntity.ID, + Status: incidentStatusId, + }, + user.ID, + callback.View.PrivateMetadata, + incidentEntity, + teamEntity, + severityEntity, + incidentChannels, + ); err != nil { + logger.Error(fmt.Sprintf("error in updating status: %v", err)) + metrics.PublishHoustonFlowFailureMetrics(incidentV2.UPDATE_INCIDENT_STATUS, err.Error()) return } - - currentStatus, _ := isp.incidentService.FindIncidentStatusById(incidentEntity.Status) - incidentEntity.Status = result.ID - incidentEntity.UpdatedBy = user.ID - err = isp.incidentService.UpdateIncident(incidentEntity) - if err != nil { - logger.Error("UpdateIncident error", - zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), - zap.String("user_id", user.ID), zap.Error(err)) - } - - go func() { - errMessage := util.PostIncidentStatusUpdateMessage(user.ID, result.Name, callback.View.PrivateMetadata, isp.client) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateStatus", zap.Error(errMessage)) - return - } - - if currentStatus.IsTerminalStatus && incidentEntity.SeverityId != incident.Sev0Id { - toSeverity, _ := isp.severityRepository.FindSeverityById(incidentEntity.SeverityId - 1) - var message string - if (incidentEntity.SeverityTat).Before(time.Now()) { - message = fmt.Sprintf( - "Severity TAT has already breached, this incident will be auto-escalated to `%v`", - toSeverity.Name, - ) - } else if (incidentEntity.SeverityTat).Before(time.Now().AddDate(0, 0, 1)) { - message = fmt.Sprintf( - "Severity TAT is breaching in %d hours, this incident will be auto-escalated to `%s`", - int(math.Ceil(incidentEntity.SeverityTat.Sub(time.Now()).Hours())), toSeverity.Name, - ) - } - if message != "" { - _, _, err := isp.client.PostMessage(channelId, slack.MsgOptionText(message, false)) - if err != nil { - logger.Error(fmt.Sprintf("%s error in posting escalation message", logTag), zap.Error(err)) - } - } - } - - msgUpdate := NewIncidentChannelMessageUpdateAction(isp.client, isp.incidentService, isp.teamRepository, isp.severityRepository) - msgUpdate.ProcessAction(incidentEntity.SlackChannel) - }() - } -func buildUpdateIncidentStatusRequest(blockActions map[string]map[string]slack.BlockAction) uint { +func buildUpdateIncidentStatusRequest(blockActions map[string]map[string]slack.BlockAction) string { var requestMap = make(map[string]string, 0) for _, actions := range blockActions { for actionID, a := range actions { @@ -148,10 +113,5 @@ func buildUpdateIncidentStatusRequest(blockActions map[string]map[string]slack.B } } - selectedValue := requestMap["incident_status_modal_request"] - selectedValueInInt, err := strconv.Atoi(selectedValue) - if err != nil { - logger.Error("String conversion to int faileed in buildUpdateIncidentResponderTeamRequest for "+selectedValue, zap.Error(err)) - } - return uint(selectedValueInInt) + return requestMap["incident_status_modal_request"] } diff --git a/internal/processor/action/open_set_rca_view_modal_command_action.go b/internal/processor/action/open_set_rca_view_modal_command_action.go index 315a65b..2be196f 100644 --- a/internal/processor/action/open_set_rca_view_modal_command_action.go +++ b/internal/processor/action/open_set_rca_view_modal_command_action.go @@ -41,8 +41,8 @@ func (action *OpenFillRCAViewModalCommandAction) PerformAction(evt *socketmode.E } tagsAction := NewIncidentTagsAction(appcontext.GetIncidentRepo(), appcontext.GetTagRepo()) - rcaSummaryAction := NewIncidentRCASummaryAction(appcontext.GetIncidentRepo()) - jiraLinksAction := NewIncidentJiraLinksAction(appcontext.GetIncidentService(), appcontext.GetSlackService()) + rcaSummaryAction := NewIncidentRCASummaryAction() + jiraLinksAction := NewIncidentJiraLinksAction(appcontext.GetSlackService()) rcaSectionAction := NewIncidentRCASectionAction( action.socketModeClient, appcontext.GetIncidentRepo(), appcontext.GetTeamRepo(), appcontext.GetTagRepo(), appcontext.GetSeverityRepo(), tagsAction, rcaSummaryAction, diff --git a/internal/processor/action/resolve_incident_command_action.go b/internal/processor/action/resolve_incident_command_action.go index 9898283..1bf2de5 100644 --- a/internal/processor/action/resolve_incident_command_action.go +++ b/internal/processor/action/resolve_incident_command_action.go @@ -40,8 +40,8 @@ func (action *ResolveIncidentCommandAction) PerformAction(evt *socketmode.Event) return } tagsAction := NewIncidentTagsAction(appcontext.GetIncidentRepo(), appcontext.GetTagRepo()) - rcaSummaryAction := NewIncidentRCASummaryAction(appcontext.GetIncidentRepo()) - jiraLinksAction := NewIncidentJiraLinksAction(appcontext.GetIncidentService(), appcontext.GetSlackService()) + rcaSummaryAction := NewIncidentRCASummaryAction() + jiraLinksAction := NewIncidentJiraLinksAction(appcontext.GetSlackService()) rcaSectionAction := NewIncidentRCASectionAction( action.socketModeClient, appcontext.GetIncidentRepo(), appcontext.GetTeamRepo(), appcontext.GetTagRepo(), appcontext.GetSeverityRepo(), tagsAction, rcaSummaryAction, diff --git a/internal/processor/action/set_severity_command_action.go b/internal/processor/action/set_severity_command_action.go index b03bb73..b77377f 100644 --- a/internal/processor/action/set_severity_command_action.go +++ b/internal/processor/action/set_severity_command_action.go @@ -4,11 +4,9 @@ import ( "fmt" "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" - "github.com/spf13/viper" "go.uber.org/zap" "houston/appcontext" "houston/common/metrics" - incidentHelper "houston/common/util" "houston/common/util/structUtil" "houston/internal" "houston/internal/processor/action/view" @@ -18,7 +16,6 @@ import ( service "houston/service/request" "strconv" "strings" - "time" ) const setSeverityActionLogTag = "[set_severity_command_action]" @@ -80,116 +77,42 @@ func (action *SetSeverityCommandAction) setSeverity(cmd slack.SlashCommand, seve return fmt.Errorf("%s is not a valid severity", severity) } - if viper.GetBool("UPDATE_INCIDENT_V2_ENABLED") { - incidentSeverityId := severityEntity.ID - teamEntity, _, incidentStatusEntity, incidentChannels, err := appcontext.GetIncidentService().FetchAllEntitiesForIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err)) - return err - } - if viper.GetBool("ENABLE_DE_ESCALATION_JUSTIFICATION") { - if incidentSeverityId > incidentEntity.SeverityId { - justificationMetadata := JustificationMetadata{SeverityId: incidentSeverityId, ChannelId: cmd.ChannelID} - stringData, stringErr := structUtil.StructToString(justificationMetadata) - if stringErr != nil { - logger.Error(fmt.Sprintf("error in converting justification metadata to string for incident id: %d", incidentEntity.ID), zap.Error(stringErr)) - } - _, viewErr := action.socketModeClient.OpenView(cmd.TriggerID, view.CreateSeverityJustificationBlock(stringData)) - if viewErr != nil { - logger.Error(fmt.Sprintf("error in opening justification view for incident with id: %d", incidentEntity.ID), zap.Error(viewErr)) - return viewErr - } - return nil - } - } + incidentSeverityId := severityEntity.ID + teamEntity, _, incidentStatusEntity, incidentChannels, err := appcontext.GetIncidentService().FetchAllEntitiesForIncident(incidentEntity) + if err != nil { + logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err)) + return err + } - if err := appcontext.GetIncidentService().UpdateSeverityId( - service.UpdateIncidentRequest{ - Id: incidentEntity.ID, - SeverityId: strconv.Itoa(int(incidentSeverityId)), - }, - cmd.UserID, - incidentEntity, - teamEntity, - incidentStatusEntity, - incidentChannels, - ); err != nil { - logger.Error(fmt.Sprintf("error in updating severity: %v", err)) - metrics.PublishHoustonFlowFailureMetrics(incidentService.UPDATE_INCIDENT_SEVERITY, err.Error()) - return err + if incidentSeverityId > incidentEntity.SeverityId { + justificationMetadata := JustificationMetadata{SeverityId: incidentSeverityId, ChannelId: cmd.ChannelID} + stringData, stringErr := structUtil.StructToString(justificationMetadata) + if stringErr != nil { + logger.Error(fmt.Sprintf("error in converting justification metadata to string for incident id: %d", incidentEntity.ID), zap.Error(stringErr)) + } + _, viewErr := action.socketModeClient.OpenView(cmd.TriggerID, view.CreateSeverityJustificationBlock(stringData)) + if viewErr != nil { + logger.Error(fmt.Sprintf("error in opening justification view for incident with id: %d", incidentEntity.ID), zap.Error(viewErr)) + return viewErr } return nil } - incidentEntity.SeverityId = severityEntity.ID - incidentEntity.UpdatedBy = cmd.UserID - incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla) - err = appcontext.GetIncidentRepo().UpdateIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("%s failed to update severity for incident: %s. %+v", setSeverityActionLogTag, incidentEntity.IncidentName, err)) - return fmt.Errorf("failed to update severity for incident: %s", incidentEntity.IncidentName) - } - - teamEntity, err := appcontext.GetTeamRepo().FindTeamById(incidentEntity.TeamId) - if err != nil { - logger.Error(fmt.Sprintf("%s error in finding team entity by team name %d. %+v", setSeverityActionLogTag, incidentEntity.TeamId, err)) - return genericBackendError - } - if teamEntity == nil { - logger.Error(fmt.Sprintf("%s invalid team name %d. No entity found in DB", setSeverityActionLogTag, incidentEntity.TeamId)) - return genericBackendError - } - - for _, o := range severityEntity.SlackUserIds { - action.slackBot.InviteUsersToConversation(cmd.ChannelID, o) - } - go func() { - msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `set severity to %s (%s)`", cmd.UserID, severityEntity.Name, severityEntity.Description), false) - _, _, errMessage := action.socketModeClient.PostMessage(cmd.ChannelID, msgOption) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateSeverity", zap.Error(errMessage)) - return - } - - txt := fmt.Sprintf("set the channel topic: *%s · %s (%s) %s* | %s", teamEntity.Name, severityEntity.Name, severityEntity.Description, incidentEntity.IncidentName, incidentEntity.Title) - att := slack.Attachment{ - Text: txt, - Color: "#808080", // Grey color code - MarkdownIn: []string{"txt"}, // Define which fields support markdown - } - _, _, errMessage = action.socketModeClient.PostMessage(cmd.ChannelID, slack.MsgOptionAttachments(att)) - if errMessage != nil { - logger.Error(fmt.Sprintf("%s post response failed for IncidentUpdateType. %+v", setSeverityActionLogTag, zap.Error(errMessage))) - return - } - - topic := fmt.Sprintf("%s-%s(%s) Incident-%d | %s", - teamEntity.Name, severityEntity.Name, severityEntity.Description, incidentEntity.ID, incidentEntity.Title, - ) - action.slackBot.SetChannelTopic(cmd.ChannelID, topic) - }() - - incidentHelper.TagPseOrDevOncallToIncident( - cmd.ChannelID, - severityEntity, - teamEntity, - action.slackBot, - action.socketModeClient, - ) - - err = incidentHelper.AssignResponderToIncident( - appcontext.GetIncidentRepo(), + if err := appcontext.GetIncidentService().UpdateSeverityId( + service.UpdateIncidentRequest{ + Id: incidentEntity.ID, + SeverityId: strconv.Itoa(int(incidentSeverityId)), + }, + cmd.UserID, incidentEntity, teamEntity, - severityEntity, - action.socketModeClient, - cmd.UserID, - ) - if err != nil { - logger.Error(fmt.Sprintf("%s Error while assigning responder to the incident %+v", setSeverityActionLogTag, zap.Error(err))) - return fmt.Errorf("severity is set to %s. Failed to assign responder post severity update", severity) + incidentStatusEntity, + incidentChannels, + ); err != nil { + logger.Error(fmt.Sprintf("error in updating severity: %v", err)) + metrics.PublishHoustonFlowFailureMetrics(incidentService.UPDATE_INCIDENT_SEVERITY, err.Error()) + return err } - go appcontext.GetIncidentService().SendAlert(incidentEntity) return nil }) } diff --git a/internal/processor/action/start_incident_modal_submission_action.go b/internal/processor/action/start_incident_modal_submission_action.go index b7082c4..340dd68 100644 --- a/internal/processor/action/start_incident_modal_submission_action.go +++ b/internal/processor/action/start_incident_modal_submission_action.go @@ -1,34 +1,22 @@ package action import ( - "encoding/json" - "fmt" + "github.com/slack-go/slack" + "github.com/slack-go/slack/socketmode" + "go.uber.org/zap" "gorm.io/gorm" "houston/appcontext" "houston/common/metrics" - "houston/common/util" stringUtil "houston/common/util/string" "houston/internal" - "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" "houston/model/severity" "houston/model/team" - conference2 "houston/pkg/conference" "houston/pkg/slackbot" - "houston/service/conference" - incidentService "houston/service/incident" incidentServiceImpl "houston/service/incident/impl" "houston/service/orchestration" request "houston/service/request/incident" - "strings" - "time" - - "github.com/slack-go/slack" - "github.com/slack-go/slack/socketmode" - "github.com/spf13/viper" - "go.uber.org/zap" - incidentHelper "houston/common/util" ) type CreateIncidentAction struct { @@ -51,157 +39,6 @@ func NewCreateIncidentProcessor(client *socketmode.Client, incidentService *inci } } -func (isp *CreateIncidentAction) CreateIncidentModalCommandProcessing(callback slack.InteractionCallback, request *socketmode.Request) { - // Build create incident request - createIncidentRequest := buildCreateIncidentDTO(callback) - logger.Info("[CIP] incident request created", zap.Any("request", createIncidentRequest)) - - // Save the incident to the database - tx := isp.db.Begin() - defer util.RollbackTransaction(tx) - incidentEntity, err := isp.incidentRepository.CreateIncidentEntity(createIncidentRequest, tx) - if err != nil { - logger.Error("[CIP] Error while creating incident", zap.Error(err)) - tx.Rollback() - return - } - - channel, err := appcontext.GetSlackService().CreateSlackChannel(incidentEntity.ID) - if err != nil { - logger.Error("[CIP] Error while creating incident channel", zap.Error(err)) - tx.Rollback() - return - } - - tx.Commit() - - incidentEntity.SlackChannel = channel.ID - incidentEntity.IncidentName = channel.Name - err = isp.incidentRepository.UpdateIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("[CIP] failed to update the slack channel name for incident-id: %v", incidentEntity.ID)) - return - } - - teamEntity, severityEntity, incidentStatusEntity, err := isp.getTeamAndSeverityAndStatus(incidentEntity.TeamId, - incidentEntity.SeverityId, incidentEntity.Status) - if err != nil { - logger.Error("[CIP] failed while getting team, severity and status", zap.Error(err)) - return - } - - topic := fmt.Sprintf("%s-%s(%s) Incident-%d | %s", teamEntity.Name, severityEntity.Name, severityEntity.Description, incidentEntity.ID, incidentEntity.Title) - - isp.slackbotClient.SetChannelTopic(channel.ID, topic) - - go func() { - // Post incident summary to Blaze Group channel and incident channel - _, err := isp.postIncidentSummary(callback.View.PrivateMetadata, channel.ID, incidentEntity, teamEntity, - severityEntity, incidentStatusEntity) - if err != nil { - logger.Error("[CIP] error while posting incident summary", zap.Error(err)) - return - } - //Add user who created the incident - isp.slackbotClient.InviteUsersToConversation(incidentEntity.SlackChannel, incidentEntity.CreatedBy) - // add default users to the incident - err = isp.addDefaultUsersToIncident(channel.ID, teamEntity, severityEntity) - if err != nil { - logger.Error("[CIP] error while adding default users to incident", zap.Error(err)) - } - - if len(strings.TrimSpace(teamEntity.OncallHandle)) > 0 { - incidentHelper.TagPseOrDevOncallToIncident(channel.ID, severityEntity, teamEntity, isp.slackbotClient, isp.client) - } - - err = incidentHelper.AssignResponderToIncident( - isp.incidentRepository, - incidentEntity, - teamEntity, severityEntity, - isp.client, - incidentEntity.CreatedBy, - ) - if err != nil { - logger.Error("[CIP] error while assigning responder to the incident ", zap.Error(err)) - } - - err = incidentService.PostIncidentSLAMessageToChannel(incidentEntity, isp.severityRepository, isp.client) - if err != nil { - return - } - - if viper.GetBool("ENABLE_CONFERENCE") { - calendarActions := conference2.GetCalendarActions() - calendarService := conference.NewCalendarService(calendarActions) - calendarEvent, err := calendarService.CreateEvent(incidentEntity.IncidentName) - if err != nil { - logger.Error(fmt.Sprintf("Unable to create conference event due to error : %s", err.Error())) - } else { - util.UpdateIncidentWithConferenceDetails(incidentEntity, calendarEvent, isp.incidentRepository) - msgUpdate := NewIncidentChannelMessageUpdateAction(isp.client, isp.incidentRepository, isp.teamRepository, isp.severityRepository) - blazeMessageUpdate := msgUpdate - msgUpdate.ProcessAction(incidentEntity.SlackChannel) - blazeMessageUpdate.ProcessAction(callback.Channel.ID) - bookmarkParam := slack.AddBookmarkParameters{Link: calendarEvent.ConferenceLink, Title: calendarService.GetConferenceTitle()} - _, err := isp.client.AddBookmark(channel.ID, bookmarkParam) - if err != nil { - logger.Error(fmt.Sprintf("Unable to add conference link as bookmark for channel %s due to error: %s", incidentEntity.SlackChannel, err.Error())) - } - msgOption := slack.MsgOptionText(fmt.Sprintf(util.ConferenceMessage, calendarEvent.ConferenceLink), false) - _, _, err = isp.client.PostMessage(channel.ID, msgOption) - if err != nil { - logger.Error(fmt.Sprintf("Unable to post message to channel %s due to error: %s", incidentEntity.SlackChannel, err.Error())) - } - } - } - - }() - - // Acknowledge the interaction callback - var payload interface{} - isp.client.Ack(*request, payload) - - go func() { - if len(teamEntity.WebhookSlackChannel) == 0 { - return - } - - msg := fmt.Sprintf("*<@%s>* started an Incident\n `%s(%s) %s` :slack: <#%s>: %s", - incidentEntity.CreatedBy, severityEntity.Name, severityEntity.Description, teamEntity.Name, incidentEntity.SlackChannel, incidentEntity.Title) - msgOption := slack.MsgOptionText(msg, false) - _, _, errMessage := isp.client.PostMessage(teamEntity.WebhookSlackChannel, msgOption) - if errMessage != nil { - logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) - return - } - }() -} - -func (isp *CreateIncidentAction) CreateIncidentModalCommandProcessingV2( - callback slack.InteractionCallback, - request *socketmode.Request, -) { - // Build create incident request - createIncidentRequest, err := buildCreateIncidentRequestV2(callback) - if err != nil { - logger.Error("[CIP] Error in building CreateIncidentRequestV2", zap.Error(err)) - return - } - logger.Info("[CIP] incident request created", zap.Any("request", createIncidentRequest)) - - service := incidentServiceImpl.NewIncidentServiceV2(isp.db) - _, err = service.CreateIncident(*createIncidentRequest, "SLACK", callback.View.PrivateMetadata) - if err != nil { - logger.Error("[CIP] Error while creating incident", zap.Error(err)) - metrics.PublishHoustonFlowFailureMetrics(incidentServiceImpl.CREATE_INCIDENT, err.Error()) - return - } - - // Acknowledge the interaction callback - var payload interface{} - isp.client.Ack(*request, payload) -} - func (isp *CreateIncidentAction) CreateIncidentModalCommandProcessingV3( callback slack.InteractionCallback, request *socketmode.Request, @@ -241,136 +78,6 @@ func (isp *CreateIncidentAction) CreateIncidentModalCommandProcessingV3( isp.client.Ack(*request, payload) } -func (isp *CreateIncidentAction) addDefaultUsersToIncident(channelId string, teamEntity *team.TeamEntity, - severityEntity *severity.SeverityEntity) error { - var userIdList []string - userIdList = append(append(userIdList, teamEntity.SlackUserIds...), severityEntity.SlackUserIds...) - - for _, o := range userIdList { - isp.slackbotClient.InviteUsersToConversation(channelId, o) - } - return nil -} - -func (isp *CreateIncidentAction) postIncidentSummary(blazeGroupChannelID, incidentChannelID string, - incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity) (*string, error) { - // Post incident summary to Blaze Group channel and incident channel - var reportingTeamEntity *team.TeamEntity = nil - if incidentEntity.ReportingTeamId != nil { - var err error - reportingTeamEntity, err = isp.teamRepository.FindTeamById(*incidentEntity.ReportingTeamId) - if err != nil { - logger.Error(fmt.Sprintf("failed to get reporting team"), zap.Error(err)) - } - } - blocks := view.IncidentSummarySectionV3( - incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatusEntity, - ) - color := util.GetColorBySeverity(incidentEntity.SeverityId) - att := slack.Attachment{Blocks: blocks, Color: color} - _, timestamp, err := isp.client.PostMessage(blazeGroupChannelID, slack.MsgOptionAttachments(att)) - - if err == nil { - err := isp.incidentRepository.CreateIncidentChannelEntry(&incident.CreateIncidentChannelEntry{ - SlackChannel: blazeGroupChannelID, - MessageTimeStamp: timestamp, - IncidentId: incidentEntity.ID, - }) - if err != nil { - return nil, err - } - } else { - return nil, fmt.Errorf("[CIP] error in saving message %v", err) - } - - _, timestamp, err = isp.client.PostMessage(incidentChannelID, slack.MsgOptionAttachments(att)) - if err == nil { - isp.incidentRepository.CreateIncidentChannelEntry(&incident.CreateIncidentChannelEntry{ - SlackChannel: incidentChannelID, - MessageTimeStamp: timestamp, - IncidentId: incidentEntity.ID, - }) - } else { - return nil, fmt.Errorf("[CIP] error in saving message %v", err) - } - return ×tamp, nil -} - -func (isp *CreateIncidentAction) getTeamAndSeverityAndStatus(teamId, severityId, status uint) (*team.TeamEntity, - *severity.SeverityEntity, *incident.IncidentStatusEntity, error) { - teamEntity, err := isp.teamRepository.FindTeamById(teamId) - if err != nil || teamEntity == nil { - return nil, nil, nil, err - } - - severityEntity, err := isp.severityRepository.FindSeverityById(severityId) - if err != nil || severityEntity == nil { - return nil, nil, nil, err - } - - incidentStatusEntity, err := isp.incidentRepository.FindIncidentStatusById(status) - if err != nil || incidentStatusEntity == nil { - return nil, nil, nil, err - } - - return teamEntity, severityEntity, incidentStatusEntity, nil -} - -func buildCreateIncidentDTO(callback slack.InteractionCallback) *incident.CreateIncidentDTO { - blockActions := callback.View.State.Values - var createIncidentDTO incident.CreateIncidentDTO - var requestMap = make(map[string]string, 0) - - for _, actions := range blockActions { - for actionID, a := range actions { - if string(a.Type) == string(slack.METPlainTextInput) { - requestMap[actionID] = a.Value - } - if string(a.Type) == slack.OptTypeStatic { - requestMap[actionID] = a.SelectedOption.Value - } - } - } - - desRequestMap, _ := json.Marshal(requestMap) - json.Unmarshal(desRequestMap, &createIncidentDTO) - - createIncidentDTO.Status = incident.Investigating - createIncidentDTO.StartTime = time.Now() - createIncidentDTO.EnableReminder = false - createIncidentDTO.CreatedBy = callback.User.ID - createIncidentDTO.UpdatedBy = callback.User.ID - - return &createIncidentDTO -} - -func buildCreateIncidentRequestV2(callback slack.InteractionCallback) (*request.CreateIncidentRequestV2, error) { - blockActions := callback.View.State.Values - var createIncidentRequest request.CreateIncidentRequestV2 - var requestMap = make(map[string]string) - - for _, actions := range blockActions { - for actionID, a := range actions { - if string(a.Type) == string(slack.METPlainTextInput) { - requestMap[actionID] = a.Value - } - if string(a.Type) == slack.OptTypeStatic { - requestMap[actionID] = a.SelectedOption.Value - } - } - } - - desRequestMap, _ := json.Marshal(requestMap) - err := json.Unmarshal(desRequestMap, &createIncidentRequest) - if err != nil { - return nil, err - } - createIncidentRequest.CreatedBy = callback.User.ID - - return &createIncidentRequest, nil -} - func buildCreateIncidentRequestV3(callback slack.InteractionCallback) (*request.CreateIncidentRequestV3, error) { blockActions := callback.View.State.Values var createIncidentRequest request.CreateIncidentRequestV3 diff --git a/internal/processor/event_type_interactive_processor.go b/internal/processor/event_type_interactive_processor.go index 9e3dff3..527af7b 100644 --- a/internal/processor/event_type_interactive_processor.go +++ b/internal/processor/event_type_interactive_processor.go @@ -39,7 +39,7 @@ type BlockActionProcessor struct { incidentUpdateAction *action.UpdateIncidentAction incidentUpdateTypeAction *action.IncidentUpdateTypeAction incidentUpdateProductAction *action.IncidentUpdateProductAction - incidentUpdateSeverityAction *action.IncidentUpdateSevertityAction + incidentUpdateSeverityAction *action.IncidentUpdateSeverityAction incidentUpdateTitleAction *action.IncidentUpdateTitleAction incidentUpdateDescriptionAction *action.IncidentUpdateDescriptionAction incidentDuplicateAction *action.DuplicateIncidentAction @@ -76,7 +76,7 @@ func NewBlockActionProcessor( incidentResolveAction: action.NewIncidentResolveProcessor(socketModeClient, incidentRepository, tagService, teamService, severityService, rcaService), incidentUpdateAction: action.NewIncidentUpdateAction(socketModeClient, incidentRepository, - tagService, teamService, severityService), + tagService, teamService, severityService, incidentServiceV2), incidentUpdateTypeAction: action.NewIncidentUpdateTypeAction(socketModeClient, incidentRepository, teamService, severityService, slackbotClient, incidentServiceV2, orchestrator), incidentUpdateProductAction: action.NewIncidentUpdateProductAction( @@ -99,8 +99,8 @@ func NewBlockActionProcessor( incidentRCASectionAction: action.NewIncidentRCASectionAction( socketModeClient, incidentRepository, teamService, tagService, severityService, action.NewIncidentTagsAction(incidentRepository, tagService), - action.NewIncidentRCASummaryAction(incidentRepository), - action.NewIncidentJiraLinksAction(incidentServiceV2, slackService), + action.NewIncidentRCASummaryAction(), + action.NewIncidentJiraLinksAction(slackService), rcaService, appcontext.GetIncidentService(), ), incidentGenerateRCAAction: action.NewIncidentGenerateRCAAction(socketModeClient), @@ -229,7 +229,7 @@ type ViewSubmissionProcessor struct { updateIncidentAction *action.UpdateIncidentAction incidentUpdateTitleAction *action.IncidentUpdateTitleAction incidentUpdateDescriptionAction *action.IncidentUpdateDescriptionAction - incidentUpdateSeverityAction *action.IncidentUpdateSevertityAction + incidentUpdateSeverityAction *action.IncidentUpdateSeverityAction incidentUpdateProductAction *action.IncidentUpdateProductAction incidentUpdateTypeAction *action.IncidentUpdateTypeAction incidentAdditionalAction *action.IncidentRCASectionAction @@ -264,7 +264,7 @@ func NewViewSubmissionProcessor( selectProductAction: action.NewStartIncidentBlockAction(socketModeClient, teamService, severityService, orchestrator), assignIncidentAction: action.NewAssignIncidentAction(socketModeClient, incidentRepository), updateIncidentAction: action.NewIncidentUpdateAction(socketModeClient, incidentRepository, - tagService, teamService, severityService), + tagService, teamService, severityService, incidentServiceV2), incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, incidentRepository, teamService, severityService, slackbotClient), incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, incidentRepository), @@ -289,8 +289,8 @@ func NewViewSubmissionProcessor( incidentRCAAction: action.NewIncidentRCASectionAction( socketModeClient, incidentRepository, teamService, tagService, severityService, action.NewIncidentTagsAction(incidentRepository, tagService), - action.NewIncidentRCASummaryAction(incidentRepository), - action.NewIncidentJiraLinksAction(incidentServiceV2, slackService), + action.NewIncidentRCASummaryAction(), + action.NewIncidentJiraLinksAction(slackService), rcaService, appcontext.GetIncidentService(), ), } diff --git a/service/filter_service.go b/service/filter_service.go index 122f78e..3efdb3e 100644 --- a/service/filter_service.go +++ b/service/filter_service.go @@ -1,7 +1,7 @@ package service import ( - logger "houston/logger" + "houston/logger" "houston/model/incident" "houston/model/log" "houston/model/severity" diff --git a/service/incident/impl/incident_service_v2.go b/service/incident/impl/incident_service_v2.go index 0f3429e..8954107 100644 --- a/service/incident/impl/incident_service_v2.go +++ b/service/incident/impl/incident_service_v2.go @@ -152,7 +152,7 @@ func NewIncidentServiceV2(db *gorm.DB) *IncidentServiceV2 { return incidentService } -const logTag = "[create-incident-v2]" +const logTag = "[create-incident]" const updateLogTag = "[update-incident-v2]" const resolveLogTag = "[resolve-incident]" const updateSeveritySlackActionCount = 6 @@ -173,102 +173,6 @@ func (i *IncidentServiceV2) UpdateIncidentEntity(entity *incident.IncidentEntity return i.incidentRepository.UpdateIncident(entity) } -func (i *IncidentServiceV2) CreateIncident( - request incidentRequest.CreateIncidentRequestV2, - source string, - blazeGroupChannelID string, -) (service.IncidentResponse, error) { - emptyResponse := service.IncidentResponse{} - // Create incident dto - logger.Info(fmt.Sprintf("%s received request to create incident: %+v", logTag, request)) - responderTeam, severityEntity, err := getTeamAndSeverityEntity(i, request.TeamID, request.SeverityID) - if err != nil { - return emptyResponse, err - } - incidentDTO, err := buildCreateIncidentDTO(request, i.teamRepository, i.severityRepository, i.slackService) - if err != nil { - return emptyResponse, err - } - logger.Info(fmt.Sprintf("%s CreateIncidentDTO created", logTag)) - - // Save the incident to the database - tx := i.db.Begin() - defer util.RollbackTransaction(tx) - incidentEntity, err := i.incidentRepository.CreateIncidentEntity(incidentDTO, tx) - if err != nil { - logger.Error(fmt.Sprintf("%s Error while creating incident", logTag), zap.Error(err)) - tx.Rollback() - return emptyResponse, err - } - incidentName := incidentEntity.IncidentName - logger.Info(fmt.Sprintf("%s Incident entity created. Incident is: %s", logTag, incidentName)) - - // Create slack channel - // Call slack service to create a slack channel for incident - channel, err := i.slackService.CreateSlackChannel(incidentEntity.ID) - if err != nil { - logger.Error( - fmt.Sprintf("%s [%s] Error while crating slack channel", logTag, incidentName), - zap.Error(err), - ) - tx.Rollback() - return emptyResponse, err - } - logger.Info(fmt.Sprintf( - "%s [%s] Slack channel created. Channel name is %s", logTag, incidentName, channel.Name), - ) - tx.Commit() - // Update channel details to incident entity - incidentEntity.SlackChannel = channel.ID - incidentEntity.IncidentName = channel.Name - incidentEntity.UpdatedBy = incidentEntity.CreatedBy - err = i.incidentRepository.UpdateIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("%s [%s] Failed to update the slack channel details in DB", logTag, incidentName)) - return emptyResponse, err - } - logger.Info(fmt.Sprintf("%s [%s] Slack channel details updated to incident entity", logTag, incidentName)) - - // Post incident summary - // Call slack service, provide required message to be posted - incidentStatusEntity, err := getIncidentStatusEntity(i, incidentEntity.ID, incidentEntity.Status, incidentName) - if err != nil { - return emptyResponse, err - } - logger.Info(fmt.Sprintf("%s [%s] Team, Severity and IncidentStatus entity fetched successfully", logTag, incidentName)) - - err = i.slackService.SetChannelTopic(channel, responderTeam, severityEntity, incidentEntity) - if err != nil { - logger.Error( - fmt.Sprintf("%s [%s] Failed to set channel topic", logTag, incidentName), - zap.Error(err), - ) - } - logger.Info(fmt.Sprintf("%s [%s] Channel topic is set", logTag, incidentName)) - - go func() { - err := createIncidentWorkflow( - i, - channel, - incidentEntity, - responderTeam, - severityEntity, - incidentStatusEntity, - blazeGroupChannelID, - ) - if err != nil { - metrics.PublishHoustonFlowFailureMetrics(CREATE_INCIDENT, err.Error()) - return - } - i.HandleKrakatoaWorkflow(incidentEntity) - }() - - go postInWebhookSlackChannel(i, responderTeam, incidentEntity, severityEntity) - go i.SendAlert(incidentEntity) - - return service.ConvertToIncidentResponse(*incidentEntity), nil -} - func (i *IncidentServiceV2) PostIncidentCreationWorkflow( channel *slackClient.Channel, incidentID uint, @@ -1028,52 +932,6 @@ func assignResponderToIncident( return nil } -/* -takes create incident request, team, severity repo and slack service as input -builds data transfer object with required properties which will be used -by the repository function to create and commit incident entity -*/ -func buildCreateIncidentDTO( - createIncRequest incidentRequest.CreateIncidentRequestV2, - teamRepository team.ITeamRepository, - severityRepository severity.ISeverityRepository, - slackService slack.ISlackService, -) (*incident.CreateIncidentDTO, error) { - var createIncidentRequest incident.CreateIncidentDTO - teamID, err := strconv.ParseUint(createIncRequest.TeamID, 10, 64) - if err != nil { - //todo handle error - } - teamEntity, err := teamRepository.FindTeamById(uint(teamID)) - if err != nil { - return nil, err - } - - severityID, err := strconv.ParseUint(createIncRequest.SeverityID, 10, 64) - if err != nil { - //todo handle error - } - severityEntity, err := severityRepository.FindSeverityById(uint(severityID)) - if err != nil { - return nil, err - } - - var rawJson, _ = json.Marshal([]incidentRequest.CreateIncidentMetadata{createIncRequest.Metadata}) - createdBy := slackService.GetSlackUserIdOrEmail(createIncRequest.CreatedBy) - - createIncidentRequest.Title = createIncRequest.Title - createIncidentRequest.Description = createIncRequest.Description - createIncidentRequest.Severity = fmt.Sprintf("%d", severityEntity.ID) - createIncidentRequest.TeamId = fmt.Sprintf("%d", teamEntity.ID) - createIncidentRequest.Status = incident.Investigating - createIncidentRequest.CreatedBy = createdBy - createIncidentRequest.UpdatedBy = createdBy - createIncidentRequest.StartTime = time.Now() - createIncidentRequest.EnableReminder = false - createIncidentRequest.MetaData = rawJson - return &createIncidentRequest, nil -} - /* returns incident status entity for a given status ID */ @@ -1507,28 +1365,17 @@ func (i *IncidentServiceV2) UpdateSeverityId( } if incidentEntity.SeverityId != uint(num) { - if viper.GetBool("ENABLE_DE_ESCALATION_JUSTIFICATION") { - if uint(num) > incidentEntity.SeverityId && request.Justification == "" { - return fmt.Errorf("justification is required for de-escalating the incident") - } - incidentEntity.SeverityId = uint(num) - incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla) - incidentEntity.UpdatedAt = time.Now() - incidentEntity.UpdatedBy = userId - err := i.incidentRepository.UpdateIncidentWithJustification(incidentEntity, request.Justification) - if err != nil { - logger.Error(fmt.Sprintf("%s error in committing update to DB", updateLogTag), zap.Error(err)) - return err - } - } else { - incidentEntity.SeverityId = uint(num) - incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla) - - err := i.commitIncidentEntity(incidentEntity, userId) - if err != nil { - logger.Error(fmt.Sprintf("%s error in committing update to DB", updateLogTag), zap.Error(err)) - return err - } + if uint(num) > incidentEntity.SeverityId && request.Justification == "" { + return fmt.Errorf("justification is required for de-escalating the incident") + } + incidentEntity.SeverityId = uint(num) + incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla) + incidentEntity.UpdatedAt = time.Now() + incidentEntity.UpdatedBy = userId + err := i.incidentRepository.UpdateIncidentWithJustification(incidentEntity, request.Justification) + if err != nil { + logger.Error(fmt.Sprintf("%s error in committing update to DB", updateLogTag), zap.Error(err)) + return err } err = i.UpdateSeverityWorkflow( diff --git a/service/incident/incident_service_v2_interface.go b/service/incident/incident_service_v2_interface.go index ae81816..76c8d27 100644 --- a/service/incident/incident_service_v2_interface.go +++ b/service/incident/incident_service_v2_interface.go @@ -5,14 +5,11 @@ import ( "gorm.io/gorm" "houston/model/incident" request "houston/service/request" - incidentRequest "houston/service/request/incident" - service "houston/service/response" ) type IIncidentService interface { CreateIncidentEntity(incidentDTO *incident.CreateIncidentDTO, tx *gorm.DB) (*incident.IncidentEntity, error) UpdateIncidentEntity(entity *incident.IncidentEntity) error - CreateIncident(request incidentRequest.CreateIncidentRequestV2, source string, blazeGroupChannelID string) (service.IncidentResponse, error) PostIncidentCreationWorkflow( channel *slackClient.Channel, incidentID uint, diff --git a/service/incident_service.go b/service/incident_service.go index ed23ec7..06a8e8e 100644 --- a/service/incident_service.go +++ b/service/incident_service.go @@ -1,15 +1,10 @@ package service import ( - "encoding/json" - "errors" "fmt" "houston/appcontext" - "houston/common/util" - slackUtil "houston/common/util/slack" "houston/internal/processor/action" - "houston/internal/processor/action/view" - logger "houston/logger" + "houston/logger" "houston/model/incident" "houston/model/log" "houston/model/product" @@ -17,11 +12,9 @@ import ( "houston/model/team" "houston/model/user" "houston/pkg/slackbot" - incidentV2 "houston/service/incident" "houston/service/incident/impl" rcaService "houston/service/rca/impl" request "houston/service/request" - incidentRequest "houston/service/request/incident" service "houston/service/response" common "houston/service/response/common" slack2 "houston/service/slack" @@ -29,7 +22,6 @@ import ( utils "houston/service/utils" "math" "net/http" - "reflect" "strconv" "strings" "time" @@ -374,109 +366,6 @@ func (i *incidentService) GetTeamIncidents(c *gin.Context) { c.JSON(http.StatusOK, common.SuccessResponse(incidents, http.StatusOK)) } -func (i *incidentService) CreateIncident(c *gin.Context) { - - var createIncRequest incidentRequest.CreateIncidentRequest - if err := c.ShouldBindJSON(&createIncRequest); err != nil { - c.JSON(http.StatusInternalServerError, err) - return - } - - if err := utils.ValidateCreateIncidentRequest(createIncRequest); err != nil { - logger.Error("[Create incident Api] Error while creating incident", zap.Error(err)) - c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - - incidentDTO, err := i.buildCreateIncidentDTO(createIncRequest) - if err != nil { - c.JSON(http.StatusBadRequest, err) - } - - // Save the incident to the database - tx := i.db.Begin() - defer util.RollbackTransaction(tx) - incidentEntity, err := i.incidentRepository.CreateIncidentEntity(incidentDTO, tx) - if err != nil { - logger.Error("[Create incident Api] Error while creating incident", zap.Error(err)) - tx.Rollback() - return - } - - teamEntity, severityEntity, incidentStatusEntity, err := i.getTeamAndSeverityAndStatus( - incidentEntity.TeamId, - incidentEntity.SeverityId, - incidentEntity.Status, - ) - if err != nil { - logger.Error("[CIP] failed while getting team, severity and status", zap.Error(err)) - tx.Rollback() - return - } - - channel, err := appcontext.GetSlackService().CreateSlackChannel(incidentEntity.ID) - if err != nil { - logger.Error("[Create incident] Error while creating incident channel", zap.Error(err)) - tx.Rollback() - return - } - - tx.Commit() - - incidentEntity.SlackChannel = channel.ID - incidentEntity.IncidentName = channel.Name - err = i.incidentRepository.UpdateIncident(incidentEntity) - if err != nil { - logger.Error(fmt.Sprintf("[CIP] failed to update the slack channel name for incident-id: %v", incidentEntity.ID)) - return - } - - // Post incident summary to Blaze Group channel and incident channel - _, err = i.postIncidentSummary(channel.ID, incidentEntity, teamEntity, - severityEntity, incidentStatusEntity) - if err != nil { - logger.Error("[Create incident] error while posting incident summary", zap.Error(err)) - return - } - - // Check if the user is a slack user and get the slack user id - isSlackUser, slackUser := i.userRepository.IsAHoustonUser(incidentEntity.CreatedBy) - - if isSlackUser { - //Add user who created the incident - i.slackbotClient.InviteUsersToConversation(incidentEntity.SlackChannel, slackUser.SlackUserId) - } - // add default users to the incident - err = i.addDefaultUsersToIncident(channel.ID, teamEntity, severityEntity) - if err != nil { - logger.Error("[Create Incident] error while adding default users to incident", zap.Error(err)) - return - } - - util.TagPseOrDevOncallToIncident(channel.ID, severityEntity, teamEntity, i.slackbotClient, i.socketModeClient) - - err = util.AssignResponderToIncident( - i.incidentRepository, - incidentEntity, - teamEntity, severityEntity, - i.socketModeClient, - incidentEntity.CreatedBy, - ) - if err != nil { - logger.Error("[Create incident] Error while assigning responder to the incident ", zap.Error(err)) - } - - err = incidentV2.PostIncidentSLAMessageToChannel(incidentEntity, i.severityRepository, i.socketModeClient) - if err != nil { - return - } - - go i.incidentServiceV2.HandleKrakatoaWorkflow(incidentEntity) - - incidentResponse := service.ConvertToIncidentResponse(*incidentEntity) - c.JSON(http.StatusOK, common.SuccessResponse(incidentResponse, http.StatusOK)) -} - func (i *incidentService) InvitePseOnCallPersonToIncident(channelId, ts string) { go func() { time.Sleep(3 * time.Second) @@ -493,354 +382,6 @@ func (i *incidentService) InvitePseOnCallPersonToIncident(channelId, ts string) }() } -func (i *incidentService) addDefaultUsersToIncident(channelId string, teamEntity *team.TeamEntity, - severityEntity *severity.SeverityEntity) error { - var userIdList []string - userIdList = append(append(userIdList, teamEntity.SlackUserIds...), severityEntity.SlackUserIds...) - - for _, o := range userIdList { - i.slackbotClient.InviteUsersToConversation(channelId, o) - } - return nil -} - -func (i *incidentService) postIncidentSummary(incidentChannelID string, - incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity) (*string, error) { - // Post incident summary to Blaze Group channel and incident channel - var reportingTeamEntity *team.TeamEntity = nil - if incidentEntity.ReportingTeamId != nil { - var err error - reportingTeamEntity, err = i.teamRepository.FindTeamById(*incidentEntity.ReportingTeamId) - if err != nil { - logger.Error(fmt.Sprintf("failed to get reporting team"), zap.Error(err)) - } - } - blocks := view.IncidentSummarySectionV3( - incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatusEntity, - ) - color := util.GetColorBySeverity(incidentEntity.SeverityId) - att := slack.Attachment{Blocks: blocks, Color: color} - _, timestamp, err := i.socketModeClient.PostMessage(incidentChannelID, slack.MsgOptionAttachments(att)) - if incidentEntity.MetaData != nil { - msgOption, noMetaDataError := slackUtil.BuildSlackTextMessageFromMetaData(incidentEntity.MetaData, true) - if noMetaDataError == nil { - _, _, err = i.socketModeClient.PostMessage(incidentChannelID, msgOption) - if err != nil { - return nil, err - } - } - } - - if err == nil { - i.incidentRepository.CreateIncidentChannelEntry(&incident.CreateIncidentChannelEntry{ - SlackChannel: incidentChannelID, - MessageTimeStamp: timestamp, - IncidentId: incidentEntity.ID, - }) - } else { - return nil, fmt.Errorf("[CIP] error in saving message %v", err) - } - return ×tamp, nil -} - -func (i *incidentService) getTeamAndSeverityAndStatus(teamId, severityId, status uint) (*team.TeamEntity, - *severity.SeverityEntity, *incident.IncidentStatusEntity, error) { - teamEntity, err := i.teamRepository.FindTeamById(teamId) - if err != nil || teamEntity == nil { - return nil, nil, nil, err - } - - severityEntity, err := i.severityRepository.FindSeverityById(severityId) - if err != nil || severityEntity == nil { - return nil, nil, nil, err - } - - incidentStatusEntity, err := i.incidentRepository.FindIncidentStatusById(status) - if err != nil || incidentStatusEntity == nil { - return nil, nil, nil, err - } - - return teamEntity, severityEntity, incidentStatusEntity, nil -} - -func (i *incidentService) buildCreateIncidentDTO(createIncRequest incidentRequest.CreateIncidentRequest) (*incident.CreateIncidentDTO, error) { - var createIncidentRequest incident.CreateIncidentDTO - teamEntity, err := i.teamRepository.FindTeamByTeamName(createIncRequest.TeamName) - if err != nil { - return nil, err - } - - severityEntity, err := i.severityRepository.FindSeverityByName(createIncRequest.SeverityName) - if err != nil { - return nil, err - } - - var rawJson, _ = json.Marshal([]incidentRequest.CreateIncidentMetadata{createIncRequest.MetaData}) - createdBy := slackUtil.GetSlackUserIdFromEmail(createIncRequest.CreatedBy, i.slackbotClient) - - createIncidentRequest.Title = createIncRequest.Title - createIncidentRequest.Description = createIncRequest.Description - createIncidentRequest.Severity = fmt.Sprintf("%d", severityEntity.ID) - createIncidentRequest.TeamId = fmt.Sprintf("%d", teamEntity.ID) - createIncidentRequest.Status = incident.Investigating - createIncidentRequest.CreatedBy = createdBy - createIncidentRequest.UpdatedBy = createdBy - createIncidentRequest.StartTime = time.Now() - createIncidentRequest.EnableReminder = false - createIncidentRequest.MetaData = rawJson - return &createIncidentRequest, nil -} - -func (i *incidentService) UpdateIncident(c *gin.Context) { - userEmail := c.GetHeader("X-User-Email") - - var updateIncidentRequest request.UpdateIncidentRequest - if err := c.ShouldBindJSON(&updateIncidentRequest); err != nil { - c.JSON(http.StatusInternalServerError, err) - return - } - - err := utils.ValidateUpdateIncidentRequest(updateIncidentRequest, userEmail) - if err != nil { - c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - - incidentEntity, err := i.incidentRepository.FindIncidentById(updateIncidentRequest.Id) - if err != nil { - logger.Error("error in fetching incident", zap.Any("incidentId", updateIncidentRequest.Id), zap.Error(err)) - c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - if incidentEntity == nil { - logger.Info("incident not found", zap.Any("incidentId", updateIncidentRequest.Id)) - c.JSON(http.StatusBadRequest, common.ErrorResponse(errors.New(fmt.Sprintf("incident with id: %v not found", updateIncidentRequest.Id)), http.StatusBadRequest, nil)) - return - } - - userInfo, err := i.slackbotClient.GetUserByEmail(userEmail) - if err != nil { - logger.Error(fmt.Sprintf("error in fetching user by email: %v, hence using user email as user Id", userEmail), zap.String("userEmail", userEmail), zap.Error(err)) - userInfo = &slack.User{ - ID: userEmail, - } - } - - err = i.UpdateSeverityId(updateIncidentRequest, userInfo.ID, incidentEntity) - if err != nil { - logger.Error("error in updating severity", zap.Error(err)) - c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - - err = i.UpdateStatus(updateIncidentRequest, userInfo.ID, incidentEntity.SlackChannel, incidentEntity) - if err != nil { - logger.Error("error in updating status", zap.Error(err)) - c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - - err = i.UpdateTeamId(updateIncidentRequest, userInfo.ID, incidentEntity) - if err != nil { - logger.Error("error in updating teamId", zap.Error(err)) - c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - - err = i.UpdateMetaData(updateIncidentRequest, incidentEntity, userInfo.ID) - if err != nil { - logger.Error("error in updating metadata", zap.Error(err)) - c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil)) - return - } - - incidentEntity.UpdatedAt = time.Now() - incidentEntity.UpdatedBy = userInfo.ID - i.incidentRepository.UpdateIncident(incidentEntity) - - i.messageUpdateAction.ProcessAction(incidentEntity.SlackChannel) - - if updateIncidentRequest.SeverityId != "" || updateIncidentRequest.TeamId != "" { - teamEntity, err := i.teamRepository.FindTeamById(incidentEntity.TeamId) - if err != nil { - logger.Error(fmt.Sprintf("error in fetching team by id: %v", incidentEntity.TeamId), zap.Error(err)) - } - - incidentSeverityEntity, err := i.severityRepository.FindIncidentSeverityEntityById(int(incidentEntity.SeverityId)) - if err != nil { - logger.Error(fmt.Sprintf("error in fetching severity by id: %v", incidentEntity.SeverityId), zap.Error(err)) - } - - topic := fmt.Sprintf("%s-%s(%s) Incident-%d | %s", teamEntity.Name, incidentSeverityEntity.Name, incidentSeverityEntity.Description, incidentEntity.ID, incidentEntity.Title) - i.socketModeClient.SetTopicOfConversation(incidentEntity.SlackChannel, topic) - if !util.IsBlank(updateIncidentRequest.TeamId) { - go i.incidentServiceV2.HandleKrakatoaWorkflow(incidentEntity) - } - } - - c.JSON(http.StatusOK, common.SuccessResponse(incidentEntity.SlackChannel, http.StatusOK)) -} - -func (i *incidentService) UpdateSeverityId( - updateIncidentRequest request.UpdateIncidentRequest, userId string, incidentEntity *incident.IncidentEntity) error { - if updateIncidentRequest.SeverityId != "" { - num, err := strconv.ParseUint(updateIncidentRequest.SeverityId, 10, 64) - if err != nil { - logger.Error("error in string to int conversion", - zap.String("SeverityId", updateIncidentRequest.SeverityId), zap.Error(err)) - return err - } - - severityEntity, err := i.severityRepository.FindSeverityById(uint(num)) - if err != nil { - logger.Error("error in fetching severity", zap.Any("severity", incidentEntity.SeverityId), zap.Error(err)) - return err - } - - if updateIncidentRequest.SeverityId != "" { - num, err := strconv.ParseUint(updateIncidentRequest.SeverityId, 10, 64) - if err != nil { - logger.Error("error in string to int conversion", - zap.String("SeverityId", updateIncidentRequest.SeverityId), zap.Error(err)) - return err - } - if incidentEntity.SeverityId != uint(num) { - incidentEntity.SeverityId = uint(num) - incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla) - errMessage := util.PostIncidentSeverityUpdateMessage(userId, severityEntity.Name, incidentEntity.SlackChannel, i.socketModeClient) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateSeverity", zap.Error(errMessage)) - return err - } - } - } - } - return nil -} - -func (i *incidentService) UpdateStatus( - updateIncidentRequest request.UpdateIncidentRequest, userId, slackChannel string, - incidentEntity *incident.IncidentEntity) error { - if updateIncidentRequest.Status != "" { - num, err := strconv.ParseUint(updateIncidentRequest.Status, 10, 64) - if err != nil { - logger.Error("error in string to int conversion", - zap.String("Status", updateIncidentRequest.Status), zap.Error(err)) - return err - } - if incidentEntity.Status != uint(num) { - incidentEntity.Status = uint(num) - incidentStatus, _ := i.incidentRepository.FindIncidentStatusById(incidentEntity.Status) - errMessage := util.PostIncidentStatusUpdateMessage(userId, incidentStatus.Name, slackChannel, i.socketModeClient) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateStatus", zap.Error(errMessage)) - return err - } - if incidentStatus.IsTerminalStatus { - now := time.Now() - incidentEntity.EndTime = &now - } - } - } - return nil -} - -func (i *incidentService) UpdateTeamId( - updateIncidentRequest request.UpdateIncidentRequest, userId string, incidentEntity *incident.IncidentEntity) error { - if updateIncidentRequest.TeamId != "" { - severityEntity, err := i.severityRepository.FindSeverityById(incidentEntity.SeverityId) - if err != nil { - logger.Error("error in fetching severity", zap.Any("severity", incidentEntity.SeverityId), zap.Error(err)) - return err - } - if updateIncidentRequest.TeamId != "" { - num, err := strconv.ParseUint(updateIncidentRequest.TeamId, 10, 64) - if err != nil { - logger.Error("error in string to int conversion", - zap.String("TeamId", updateIncidentRequest.TeamId), zap.Error(err)) - return err - } - if incidentEntity.TeamId != uint(num) { - incidentEntity.TeamId = uint(num) - teamEntity, err := i.teamRepository.FindTeamById(incidentEntity.TeamId) - if err != nil { - logger.Error("error in fetching team by id", - zap.String("TeamId", updateIncidentRequest.TeamId), zap.Error(err)) - return err - } - errMessage := util.PostIncidentTypeUpdateMessage( - userId, teamEntity.Name, severityEntity.Name, severityEntity.Description, - incidentEntity.IncidentName, incidentEntity.Title, incidentEntity.SlackChannel, i.socketModeClient) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateType", zap.Error(errMessage)) - return err - } - err = i.addDefaultUsersToIncident(incidentEntity.SlackChannel, teamEntity, severityEntity) - if err != nil { - logger.Error("[Update Incident] error while adding default users to incident", zap.Error(err)) - return err - } - - util.TagPseOrDevOncallToIncident( - incidentEntity.SlackChannel, - severityEntity, - teamEntity, - i.slackbotClient, - i.socketModeClient, - ) - - err = util.AssignResponderToIncident( - i.incidentRepository, - incidentEntity, - teamEntity, - severityEntity, - i.socketModeClient, - incidentEntity.UpdatedBy, - ) - if err != nil { - logger.Error("[Update Incident][update team id] error while assigning responder to the incident ", zap.Error(err)) - } - } - } - } - return nil -} - -func (i *incidentService) UpdateMetaData(updateIncidentRequest request.UpdateIncidentRequest, incidentEntity *incident.IncidentEntity, userId string) error { - metadata := incidentRequest.CreateIncidentMetadata{} - if !reflect.DeepEqual(updateIncidentRequest.MetaData, metadata) { - metadata.CrmTicketCreationTime = updateIncidentRequest.MetaData.CrmTicketCreationTime - metadata.CustomerId = updateIncidentRequest.MetaData.CustomerId - metadata.PhoneNumber = updateIncidentRequest.MetaData.PhoneNumber - metadata.TicketId = updateIncidentRequest.MetaData.TicketId - metadata.AgentName = updateIncidentRequest.MetaData.AgentName - metadata.TicketGroup = updateIncidentRequest.MetaData.TicketGroup - var incidentMetadata []incidentRequest.CreateIncidentMetadata - - if incidentEntity.MetaData != nil { - err := json.Unmarshal(incidentEntity.MetaData, &incidentMetadata) - if err != nil { - logger.Error("error occurred while converting incident metadata to json", zap.Error(err)) - return err - } - } - incidentMetadata = append(incidentMetadata, metadata) - var err error - incidentEntity.MetaData, err = json.Marshal(incidentMetadata) - if err != nil { - logger.Error("error occurred while converting incident metadata to json", zap.Error(err)) - return err - } - errMessage := slackUtil.PostIncidentCustomerDataUpdateMessage(updateIncidentRequest.MetaData, userId, incidentEntity.SlackChannel, i.socketModeClient) - if errMessage != nil { - logger.Error("post response failed for IncidentUpdateCustomerData", zap.Error(errMessage)) - return errMessage - } - } - return nil -} - func teamDTOToIncidentHeaderOption(t *team.TeamDTO) *service.IncidentHeaderOption { return &service.IncidentHeaderOption{ Value: t.ID, diff --git a/service/krakatoa/krakatoa_service.go b/service/krakatoa/krakatoa_service.go index de6ffeb..cb49376 100644 --- a/service/krakatoa/krakatoa_service.go +++ b/service/krakatoa/krakatoa_service.go @@ -6,7 +6,7 @@ import ( "github.com/google/uuid" "github.com/spf13/viper" "go.uber.org/zap" - metrics "houston/common/metrics" + "houston/common/metrics" "houston/common/util" "houston/common/util/channel" "houston/common/util/file" diff --git a/service/log_service.go b/service/log_service.go index c52baec..4c408ff 100644 --- a/service/log_service.go +++ b/service/log_service.go @@ -6,7 +6,7 @@ import ( "github.com/gin-gonic/gin" "go.uber.org/zap" "gorm.io/gorm" - logger "houston/logger" + "houston/logger" "houston/model/log" service "houston/service/response" common "houston/service/response/common" diff --git a/service/rca/impl/rca_service.go b/service/rca/impl/rca_service.go index 44686a5..7a1f6a7 100644 --- a/service/rca/impl/rca_service.go +++ b/service/rca/impl/rca_service.go @@ -289,7 +289,7 @@ func (r *RcaService) uploadSlackConversationHistory(channelId string, incidentId r.extractUserIDs(&conversations, userIDtoNameMap) if len(userIDtoNameMap) > 0 { var slackUserIds []string - for slackUserId, _ := range userIDtoNameMap { + for slackUserId := range userIDtoNameMap { slackUserIds = append(slackUserIds, slackUserId) } diff --git a/service/rca/impl/rca_service_test.go b/service/rca/impl/rca_service_test.go index 48b1667..d387507 100644 --- a/service/rca/impl/rca_service_test.go +++ b/service/rca/impl/rca_service_test.go @@ -12,7 +12,7 @@ import ( "houston/logger" "houston/mocks" "houston/model" - incident "houston/model/incident" + "houston/model/incident" "houston/model/rca" "houston/model/rcaInput" "houston/model/user" @@ -248,7 +248,7 @@ func TestExtractUserIds(t *testing.T) { rcaService.extractUserIDs(testConversation, testUserIdMap) assert.Equal(t, len(expectedUserIdMap), len(testUserIdMap)) - for key, _ := range expectedUserIdMap { + for key := range expectedUserIdMap { assert.Contains(t, testUserIdMap, key) } // if there is no user id in the conversation text diff --git a/service/request/incident/create_incident.go b/service/request/incident/create_incident.go index 87343c5..a865c44 100644 --- a/service/request/incident/create_incident.go +++ b/service/request/incident/create_incident.go @@ -5,24 +5,6 @@ import ( "time" ) -type CreateIncidentRequest struct { - Title string `gorm:"column:title"` - Description string `gorm:"column:description"` - SeverityName string `gorm:"column:severityName"` - TeamName string `gorm:"column:teamName"` - CreatedBy string `gorm:"column:createdBy"` - MetaData CreateIncidentMetadata `gorm:"json:metaData"` -} - -type CreateIncidentRequestV2 struct { - Title string `json:"title"` - Description string `json:"description"` - SeverityID string `json:"severity"` - TeamID string `json:"type"` - CreatedBy string `json:"createdBy"` - Metadata CreateIncidentMetadata `json:"metaData"` -} - type CreateIncidentRequestV3 struct { Title string `json:"title"` Description string `json:"description"` diff --git a/service/slack/slack_service.go b/service/slack/slack_service.go index 3637c0b..d55b955 100644 --- a/service/slack/slack_service.go +++ b/service/slack/slack_service.go @@ -7,7 +7,7 @@ import ( "github.com/slack-go/slack/socketmode" "github.com/spf13/viper" "go.uber.org/zap" - metrics "houston/common/metrics" + "houston/common/metrics" "houston/common/util" "houston/logger" "houston/model/incident" diff --git a/service/tag/tag_service_test.go b/service/tag/tag_service_test.go index 43e2ce1..15fa1f2 100644 --- a/service/tag/tag_service_test.go +++ b/service/tag/tag_service_test.go @@ -147,17 +147,17 @@ func (suite *TagServiceSuite) Test_GetMandatoryActiveTags_SuccessCase() { func getMockTagDTO() *[]tag.TagDTO { return &[]tag.TagDTO{ - tag.TagDTO{ + { Id: 1, Label: "Business affected", PlaceHolder: "select business affected", }, - tag.TagDTO{ + { Id: 2, Label: "Contributing factors", PlaceHolder: "select contributing factors", }, - tag.TagDTO{ + { Id: 3, Label: "Additional tags", PlaceHolder: "select additional tags", @@ -167,11 +167,11 @@ func getMockTagDTO() *[]tag.TagDTO { func getMockTagValues() *[]tag.TagValueEntity { return &[]tag.TagValueEntity{ - tag.TagValueEntity{ + { TagId: 1, Value: "Mock Value 1", }, - tag.TagValueEntity{ + { TagId: 2, Value: "Mock Value 2", }, diff --git a/service/teamService/team_service_v2.go b/service/teamService/team_service_v2.go index 1ae8541..5abfe2b 100644 --- a/service/teamService/team_service_v2.go +++ b/service/teamService/team_service_v2.go @@ -9,7 +9,7 @@ import ( "houston/common/util" "houston/logger" "houston/model/customErrors" - externalTeam "houston/model/externalTeam" + "houston/model/externalTeam" "houston/model/incident" "houston/model/team" teamSeverityModel "houston/model/teamSeverity" diff --git a/service/users_service.go b/service/users_service.go index 76c296c..60d377e 100644 --- a/service/users_service.go +++ b/service/users_service.go @@ -7,8 +7,8 @@ import ( "github.com/slack-go/slack/socketmode" "go.uber.org/zap" "gorm.io/gorm" - util "houston/common/util" - logger "houston/logger" + "houston/common/util" + "houston/logger" "houston/model/incident" "houston/model/log" "houston/model/severity" diff --git a/service/utils/validations.go b/service/utils/validations.go index 07bf2db..58e0c50 100644 --- a/service/utils/validations.go +++ b/service/utils/validations.go @@ -75,42 +75,6 @@ func ValidateResolveIncidentRequest(request service.ResolveIncidentRequest) erro return nil } -func ValidateCreateIncidentRequest(request incident.CreateIncidentRequest) error { - if request.Title == "" || request.Description == "" { - return errors.New("title and description should be present in create request") - } - descriptionMaxLength := viper.GetInt("create-incident.description.max-length") - titleMaxLength := viper.GetInt("create-incident.title.max-length") - if len(request.Description) > descriptionMaxLength { - return errors.New(fmt.Sprintf("description should not be more than %v characters long", descriptionMaxLength)) - } - if len(request.Title) > titleMaxLength { - return errors.New(fmt.Sprintf("title should not be more than %v characters long", titleMaxLength)) - } - if request.CreatedBy == "" { - return errors.New("created By should be present") - } - return nil -} - -func ValidateCreateIncidentRequestV2(request incident.CreateIncidentRequestV2) error { - if request.Title == "" || request.Description == "" { - return errors.New("title and description should be present in create request") - } - descriptionMaxLength := viper.GetInt("create-incident.description.max-length") - titleMaxLength := viper.GetInt("create-incident.title.max-length") - if len(request.Description) > descriptionMaxLength { - return errors.New(fmt.Sprintf("description should not be more than %v characters long", descriptionMaxLength)) - } - if len(request.Title) > titleMaxLength { - return errors.New(fmt.Sprintf("title should not be more than %v characters long", titleMaxLength)) - } - if request.CreatedBy == "" { - return errors.New("created By should be present") - } - return nil -} - func ValidateCreateIncidentRequestV3(request incident.CreateIncidentRequestV3) error { if request.Title == "" || request.Description == "" { return errors.New("title and description should be present in create request")