INFRA-2828 : Drop unused tables, update migrations and removed unused code modules (#367)

This commit is contained in:
Vijay Joshi
2024-02-13 15:43:24 +05:30
committed by GitHub
parent f8b286adb1
commit 358799442e
21 changed files with 17 additions and 1069 deletions

View File

@@ -5,7 +5,6 @@ import (
"houston/appcontext"
"houston/common/util"
"houston/internal/cron"
"houston/internal/diagnostic"
"houston/internal/processor"
"houston/internal/resolver"
"houston/model/incident"
@@ -40,7 +39,6 @@ type slackHandler struct {
memberJoinCallbackProcessor *processor.MemberJoinedCallbackEventProcessor
blockActionProcessor *processor.BlockActionProcessor
viewSubmissionProcessor *processor.ViewSubmissionProcessor
diagnosticCommandProcessor *processor.DiagnosticCommandProcessor
userChangeEventProcessor *processor.UserChangeEventProcessor
houstonCommandResolver *resolver.HoustonCommandResolver
}
@@ -54,8 +52,6 @@ func NewSlackHandler(gormClient *gorm.DB, socketModeClient *socketmode.Client) *
userService := user.NewUserRepository(gormClient)
shedlockService := shedlock.NewShedlockRepository(gormClient)
slackbotClient := slackbot.NewSlackClient(socketModeClient)
grafanaRepository := diagnostic.NewDiagnoseRepository(gormClient)
diagnosticCommandProcessor := processor.NewDiagnosticCommandProcessor(socketModeClient, grafanaRepository)
incidentServiceV2 := incidentServiceV2.NewIncidentServiceV2(gormClient)
slackService := slack2.NewSlackService()
// new services
@@ -84,9 +80,8 @@ func NewSlackHandler(gormClient *gorm.DB, socketModeClient *socketmode.Client) *
}
return &slackHandler{
socketModeClient: socketModeClient,
slashCommandProcessor: slashCommandProcessor,
diagnosticCommandProcessor: diagnosticCommandProcessor,
socketModeClient: socketModeClient,
slashCommandProcessor: slashCommandProcessor,
memberJoinCallbackProcessor: processor.NewMemberJoinedCallbackEventProcessor(
socketModeClient, incidentService, teamService, severityService,
),
@@ -99,7 +94,7 @@ func NewSlackHandler(gormClient *gorm.DB, socketModeClient *socketmode.Client) *
userChangeEventProcessor: processor.NewUserChangeEventProcessor(
socketModeClient, userService,
),
houstonCommandResolver: resolver.NewHoustonCommandResolver(diagnosticCommandProcessor, socketModeClient, slackbotClient, rcaService),
houstonCommandResolver: resolver.NewHoustonCommandResolver(socketModeClient, slackbotClient, rcaService),
}
}

View File

@@ -0,0 +1,8 @@
DROP TABLE IF EXISTS role;
DROP TABLE IF EXISTS team_tag;
DROP TABLE IF EXISTS dbz_heartbeat;
DROP TABLE IF EXISTS deployment_config_mapping;
DROP TABLE IF EXISTS deployment_mapping;
DROP TABLE IF EXISTS diagnose_runbook;
DROP TABLE IF EXISTS grafana_mapping;
DROP TABLE IF EXISTS kibana_mapping;

View File

@@ -1,57 +0,0 @@
package diagnostic
import (
"gorm.io/gorm"
"houston/internal/diagnostic/models/entity"
"houston/model/severity"
)
type Repository struct {
gormClient *gorm.DB
severityService *severity.Repository
}
func NewDiagnoseRepository(gormClient *gorm.DB) *Repository {
return &Repository{
gormClient: gormClient,
}
}
func (r *Repository) GetGrafanaLinksForAlert(alertId string) ([]entity.GrafanaDiagnosticEntity, error) {
var grafanaLink []entity.GrafanaDiagnosticEntity
result := r.gormClient.Table("grafana_mapping").Find(&grafanaLink, "alert_id = ?", alertId)
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected == 0 {
return nil, nil
}
return grafanaLink, nil
}
func (r *Repository) GetDeploymentPortalDetails(alertId string) ([]entity.DeploymentDiagnosticEntity, error) {
var portalDetails []entity.DeploymentDiagnosticEntity
result := r.gormClient.Table("deployment_mapping").Find(&portalDetails, "alert_id = ?", alertId)
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected == 0 {
return nil, nil
}
return portalDetails, nil
}
func (r *Repository) GetDeploymentConfigDetails(alertId string) ([]entity.DeploymentConfigEntity, error) {
var portalDetails []entity.DeploymentConfigEntity
result := r.gormClient.Table("deployment_config_mapping").Find(&portalDetails, "alert_id = ?", alertId)
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected == 0 {
return nil, nil
}
return portalDetails, nil
}

View File

@@ -1,91 +0,0 @@
package diagnostic
import (
"bytes"
"github.com/google/uuid"
"github.com/slack-go/slack"
"houston/internal/diagnostic/models"
)
type DataAssembler interface {
HandleData(runbooks []models.Runbook) string
}
type AssemblerData struct {
}
type DataAssemblerImpl struct {
assemblerData AssemblerData
}
type DataAssembler2Impl struct {
assemblerData AssemblerData
}
func NewDiagnosticDataAssembler() *DataAssemblerImpl {
return &DataAssemblerImpl{
assemblerData: AssemblerData{},
}
}
func NewDiagnosticDataAssembler2() *DataAssembler2Impl {
return &DataAssembler2Impl{
assemblerData: AssemblerData{},
}
}
func (gah *DataAssemblerImpl) HandleData(runbooks []models.Runbook) (slack.MsgOption, []slack.Attachment) {
var messageBlock slack.MsgOption
attachments := make([]slack.Attachment, 0)
for _, runbook := range runbooks {
if runbook.ImagePaths != nil {
imageMessages := make([]slack.Block, 0)
for it, images := range runbook.ImagePaths {
imageBlock := slack.NewImageBlock(images, "", "id"+string(rune(it)), &slack.TextBlockObject{Type: "plain_text", Text: "abc"})
imageMessages = append(imageMessages, imageBlock)
}
messageBlock = slack.MsgOptionBlocks(imageMessages...)
}
if runbook.TextSnippets != nil {
attachment := slack.Attachment{
Text: runbook.TextSnippets[0],
}
attachments = append(attachments, attachment)
}
}
return messageBlock, attachments
}
func (gah *DataAssembler2Impl) HandleData(runbooks []models.Runbook) (slack.MsgOption, []slack.Attachment) {
var messageBlock slack.MsgOption
messages := make([]slack.Block, 0)
attachments := make([]slack.Attachment, 0)
for _, runbook := range runbooks {
if runbook.ImagePaths != nil {
for _, images := range runbook.ImagePaths {
id, _ := uuid.NewUUID()
textBlock := &slack.TextBlockObject{
Type: "plain_text",
Text: "image",
}
imageSectionBlock := slack.NewImageBlock(images, "", id.String(), textBlock)
messages = append(messages, imageSectionBlock)
}
}
if runbook.TextSnippets != nil {
var message bytes.Buffer
for it, text := range runbook.TextSnippets {
if it == 0 {
message.WriteString(text)
continue
}
message.WriteString("\n>" + text)
}
textBlock := slack.NewTextBlockObject("mrkdwn", message.String(), false, false)
block := slack.NewSectionBlock(textBlock, nil, nil)
messages = append(messages, block)
}
}
messageBlock = slack.MsgOptionBlocks(messages...)
return messageBlock, attachments
}

View File

@@ -1,160 +0,0 @@
package diagnostic
import (
"encoding/json"
"fmt"
"github.com/joho/godotenv"
"github.com/spf13/viper"
"go.uber.org/zap"
"houston/config"
"houston/internal/clients"
"houston/logger"
"io"
"net/http"
"strconv"
)
func DeploymentConfigHandler(repo *Repository, alertId string) []string {
deploymentConfigDetails, _ := repo.GetDeploymentConfigDetails(alertId)
config.LoadHoustonConfig()
godotenv.Load()
logger.Info("DeploymentConfigHandler")
client := clients.NewHttpClient()
result := make([]string, 0)
configClient := NewConfigClient(client.HttpClient)
result = append(result, ":ghost: *New and Updated configs* :ghost:")
for _, deploymentConfig := range deploymentConfigDetails {
baseUrl := deploymentConfig.DeploymentPortalUrl
bearerToken := getBearerTokenForConfigBaseUrl(baseUrl)
config := DeploymentConfig{
BaseUrl: baseUrl,
BearerToken: bearerToken,
}
configListResponse, _ := configClient.getConfigResponse(config, deploymentConfig.ManifestId)
if configListResponse != nil && len(configListResponse) > 2 {
deploymentConfig1, _ := configClient.getConfigResponseForVersion(config, deploymentConfig.ManifestId, strconv.Itoa(configListResponse[0]))
deploymentConfig2, _ := configClient.getConfigResponseForVersion(config, deploymentConfig.ManifestId, strconv.Itoa(configListResponse[1]))
diff := calculateDiff(deploymentConfig1, deploymentConfig2)
result = append(result, diff...)
}
}
return result
}
func (m *ConfigClient) getConfigResponseForVersion(config DeploymentConfig, manifestId string, version string) (*ConfigResponse, error) {
client := m.HttpClient
req, _ := http.NewRequest("GET", fmt.Sprintf("%sapi/manifest/%s/version/%s", config.BaseUrl, manifestId, version), nil)
req.Header.Add("X_AUTH_TOKEN", fmt.Sprintf("%s", config.BearerToken))
resp, err := client.Do(req)
if err != nil {
m.Logger.Error(err.Error())
return nil, err
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
m.Logger.Error(err.Error())
return nil, err
}
var response ConfigResponse
err = json.Unmarshal(responseBody, &response)
if err != nil {
m.Logger.Error(err.Error())
return nil, err
}
return &response, nil
}
func (m *ConfigClient) getConfigResponse(config DeploymentConfig, manifestId string) (ConfigList, error) {
client := m.HttpClient
req, _ := http.NewRequest("GET", fmt.Sprintf("%sapi/manifest/%s/version/list", config.BaseUrl, manifestId), nil)
req.Header.Add("X_AUTH_TOKEN", fmt.Sprintf("%s", config.BearerToken))
resp, err := client.Do(req)
if err != nil {
m.Logger.Error(err.Error())
return nil, err
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
m.Logger.Error(err.Error())
return nil, err
}
var response ConfigList
err = json.Unmarshal(responseBody, &response)
if err != nil {
m.Logger.Error(err.Error())
return nil, err
}
return response, nil
}
func calculateDiff(response1 *ConfigResponse, response2 *ConfigResponse) []string {
if response1 == nil || response2 == nil {
logger.Info("either response1 is null or response1 is")
}
diff := make([]string, 0)
var result = make(map[string]string)
for _, v := range response1.EnvironmentVariables {
result[v.Name] = v.Value
}
for _, variable := range response2.EnvironmentVariables {
value, ok := result[variable.Name]
if ok {
if value != variable.Value {
diff = append(diff, variable.Name+", New: "+value+" old: "+variable.Value)
}
} else {
diff = append(diff, variable.Name+", New: "+value+" old: "+variable.Value)
}
delete(result, variable.Name)
}
for key, variable := range result {
diff = append(diff, key+", New: "+variable)
}
return diff
}
func getBearerTokenForConfigBaseUrl(baseUrl string) string {
switch url := baseUrl; url {
case "https://sa-deployment-portal-backend.cmd.navi-tech.in/":
return viper.GetString("config.sa.keys")
default:
return ""
}
}
func NewConfigClient(httpClient *http.Client) *ConfigClient {
return &ConfigClient{
HttpClient: httpClient,
}
}
type ConfigList []int
type ConfigClient struct {
HttpClient *http.Client
Logger *zap.Logger
baseUrl string
config GoCDConnectionConfig
}
type ConfigResponse struct {
Name string `json:"name"`
EnvironmentVariables []EnvironmentVariable `json:"environmentVariables"`
}
type EnvironmentVariable struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
}
type DeploymentConfig struct {
BaseUrl string
BearerToken string
}

View File

@@ -1,123 +0,0 @@
package diagnostic
import (
"bytes"
"encoding/json"
"fmt"
"github.com/joho/godotenv"
"github.com/spf13/viper"
"houston/config"
"houston/internal/clients"
"houston/logger"
"io"
"net/http"
"time"
)
func DeploymentPortalHandler(repo *Repository, alertId string) []string {
deplymentPortalDetails, _ := repo.GetDeploymentPortalDetails(alertId)
config.LoadHoustonConfig()
godotenv.Load()
client := clients.NewHttpClient()
result := make([]string, 0)
goCDClient := NewGoCDClient(client.HttpClient)
for _, deploymentPortal := range deplymentPortalDetails {
baseUrl := deploymentPortal.DeploymentPortalUrl
bearerToken := getBearerTokenForBaseUrl(baseUrl)
config := GoCDConnectionConfig{
BaseUrl: baseUrl,
BearerToken: bearerToken,
}
response, _ := goCDClient.getPipelineHistoryResponse(config, deploymentPortal.ServiceName)
if len(response.Pipelines) > 0 {
result = append(result, " :ghost: *"+response.Pipelines[0].Name+"* :ghost:")
for _, pipeLine := range response.Pipelines {
var singleDeployment bytes.Buffer
singleDeployment.WriteString("Approver ")
singleDeployment.WriteString(pipeLine.BuildCause.Approver)
singleDeployment.WriteString(" Message: ")
singleDeployment.WriteString(pipeLine.BuildCause.TriggerMessage)
singleDeployment.WriteString(" on ")
singleDeployment.WriteString(getDate(pipeLine.ScheduledDate))
result = append(result, singleDeployment.String())
}
}
}
return result
}
func getDate(date int64) string {
loc, _ := time.LoadLocation("Asia/Kolkata")
tm := time.Unix(0, date*int64(time.Millisecond)).In(loc)
tm.Format("2006-02-01 15:01:05")
return tm.String()
}
func getBearerTokenForBaseUrl(baseUrl string) string {
switch url := baseUrl; url {
case "https://sa-pipelines.cmd.navi-tech.in":
return viper.GetString("gocd.sa.bearer.token")
default:
return ""
}
}
type GoCDClient struct {
HttpClient *http.Client
baseUrl string
config GoCDConnectionConfig
}
type GoCDConnectionConfig struct {
BaseUrl string
BearerToken string
}
func NewGoCDClient(httpClient *http.Client) *GoCDClient {
return &GoCDClient{
HttpClient: httpClient,
}
}
type GoCdResponse struct {
Pipelines []GoCdStageRun `json:"pipelines,omitempty"`
}
type GoCdStageRun struct {
Name string `json:"name,omitempty"`
StageCounter int32 `json:"counter,omitempty"`
ScheduledDate int64 `json:"scheduled_date,omitempty"`
BuildCause GoCdBuildCause `json:"build_cause,omitempty"`
}
type GoCdBuildCause struct {
TriggerMessage string `json:"trigger_message,omitempty"`
Approver string `json:"approver,omitempty"`
}
func (m *GoCDClient) getPipelineHistoryResponse(config GoCDConnectionConfig, pipelineName string) (*GoCdResponse, error) {
client := m.HttpClient
req, _ := http.NewRequest("GET", fmt.Sprintf("%s/go/api/pipelines/%s/history", config.BaseUrl, pipelineName), nil)
req.Header.Add("Authorization", fmt.Sprintf("bearer %s", config.BearerToken))
req.Header.Add("Accept", "application/vnd.go.cd.v1+json")
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var response GoCdResponse
err = json.Unmarshal(responseBody, &response)
if err != nil {
logger.Error(err.Error())
return nil, err
}
return &response, nil
}

File diff suppressed because one or more lines are too long

View File

@@ -1,15 +0,0 @@
package entity
import "gorm.io/gorm"
type DeploymentConfigEntity struct {
gorm.Model
AlertId string `gorm:"column:alert_id"`
ManifestId string `gorm:"column:manifest_id"`
DeploymentPortalUrl string `gorm:"column:deployment_portal_url"`
Priority int `gorm:"column:priority"`
}
func (DeploymentConfigEntity) TableName() string {
return "deployment_config_mapping"
}

View File

@@ -1,15 +0,0 @@
package entity
import "gorm.io/gorm"
type DeploymentDiagnosticEntity struct {
gorm.Model
AlertId string `gorm:"column:alert_id"`
ServiceName string `gorm:"column:service_name"`
DeploymentPortalUrl string `gorm:"column:deployment_portal_url"`
Priority int `gorm:"column:priority"`
}
func (DeploymentDiagnosticEntity) TableName() string {
return "deployment_mapping"
}

View File

@@ -1,15 +0,0 @@
package entity
import "gorm.io/gorm"
type DiagnoseEntity struct {
gorm.Model
AlertId string `gorm:"column:alert_id"`
AlertName string `gorm:"column:alert_name`
Description string `gorm:"column:description`
IsActive bool `gorm:"column:is_active"`
}
func (DiagnoseEntity) TableName() string {
return "diagnose_runbook"
}

View File

@@ -1 +0,0 @@
package entity

View File

@@ -1,14 +0,0 @@
package entity
import "gorm.io/gorm"
type GrafanaDiagnosticEntity struct {
gorm.Model
AlertId string `gorm:"column:alert_id"`
EndpointUrl string `gorm:"column:endpoint_url"`
Priority int `gorm:"column:priority"`
}
func (GrafanaDiagnosticEntity) TableName() string {
return "grafana_mapping"
}

View File

@@ -1,15 +0,0 @@
package entity
import "gorm.io/gorm"
type KibanaDiagnosticEntity struct {
gorm.Model
AlertId string `gorm:"column:alert_id"`
KibanaLink string `gorm:"column:kibana_link"`
Priority int `gorm:"column:priority"`
CustomQuery string `gorm:"column:custom_query"`
}
func (KibanaDiagnosticEntity) TableName() string {
return "kibana_mapping"
}

View File

@@ -1,23 +0,0 @@
package models
type GoCdResponse struct {
PipelineName string `json:"pipelineName,omitempty"`
Groups []GoCdGroups `json:"groups,omitempty"`
}
type GoCdGroups struct {
History []GoCdPipelineRun `json:"history,omitempty"`
}
type GoCdPipelineRun struct {
BuildCause string `json:"buildCauseBy,omitempty"`
ScheduledDate string `json:"scheduled_date,omitempty"`
Stages []GoCdStageRun `json:"stages,omitempty"`
}
type GoCdStageRun struct {
Name string `json:"stageName,omitempty"`
StageCounter string `json:"stageCounter,omitempty"`
StageStatus string `json:"stageStatus,omitempty"`
ScheduledDate string `json:"scheduled_date,omitempty"`
}

View File

@@ -1,8 +0,0 @@
package models
type Runbook struct {
links []string // links to be shown in the printed runbook on slack
TextSnippets []string // snippets to be shown in printed runbook on slack
ImagePaths []string // images that needs to be shown in the runbook
filePaths []string // if any files needs to be uploaded along with the runbook
}

View File

@@ -1,138 +0,0 @@
package diagnostic
import (
"context"
"fmt"
"github.com/google/uuid"
"github.com/joho/godotenv"
"github.com/spf13/viper"
"go.uber.org/zap"
"houston/config"
"houston/logger"
"houston/pkg/s3"
"image"
"io"
"net/http"
"os"
"path/filepath"
"time"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)
func getImageFromFilePath(filePath string) (image.Image, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()
image, _, err := image.Decode(f)
return image, err
}
func TakeScreenshotAndUpload(repo *Repository, alertId string) []string {
grafanaLinks, _ := repo.GetGrafanaLinksForAlert(alertId)
logger.Info("taking screenshot")
fileLinkList := make([]string, 0)
for _, links := range grafanaLinks {
takeScreenShotUrl(&fileLinkList, links.EndpointUrl)
}
return fileLinkList
}
func takeScreenShotUrl(fileList *[]string, url string) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
logger.Error(err.Error())
}
token := fmt.Sprintf("Bearer %s", viper.GetString("grafana.token"))
req.Header.Set("Authorization", token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
logger.Error(err.Error())
}
id := uuid.New()
if err := os.MkdirAll("images", os.ModePerm); err != nil {
logger.Error(err.Error())
}
fileName := "images/" + id.String() + ".jpg"
file, err := os.Create(fileName)
if err != nil {
logger.Error(err.Error())
}
defer file.Close()
_, err = io.Copy(file, resp.Body)
link, err := upload(fileName)
if err != nil {
return
}
os.Remove(fileName)
*fileList = append(*fileList, link)
}
func takeScreenShot(fileList *[]string, url string) {
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
var buf []byte
if err := chromedp.Run(ctx, setHeaders(url, &buf)); err != nil {
logger.Fatal(err.Error())
}
id := uuid.New()
if err := os.MkdirAll("images", os.ModePerm); err != nil {
logger.Fatal(err.Error())
}
fileName := "images/" + id.String() + ".jpg"
if err := os.WriteFile(fileName, buf, 0644); err != nil {
logger.Fatal(err.Error())
}
link, err := upload(fileName)
if err != nil {
logger.Error("failed", zap.Error(err))
return
}
os.Remove(fileName)
*fileList = append(*fileList, link)
}
func upload(fileName string) (string, error) {
s3Operations := s3.NewS3Operations()
s3BucketName := viper.GetString("S3_BUCKET_NAME")
output, uploadErr := s3Operations.UploadFile(s3BucketName, filepath.Join(), fileName, fileName)
if uploadErr != nil {
logger.Info("upload failed for grafana screenshot")
logger.Error(uploadErr.Error())
logger.Error("upload failed", zap.Error(uploadErr), zap.Any("output", output))
return "", uploadErr
}
link, err := s3Operations.GetFileLink(s3BucketName, fileName)
if err != nil {
logger.Error("upload failed", zap.Error(err), zap.Any("output", output))
return "", err
}
logger.Info("upload success", zap.String("link", link), zap.Any("s3_output", output), zap.Error(err))
return link, nil
}
func setHeaders(host string, imageBuf *[]byte) chromedp.Tasks {
config.LoadHoustonConfig()
godotenv.Load()
token := fmt.Sprintf("Bearer %s", viper.GetString("grafana.token"))
headers := map[string]interface{}{
"Authorization": token,
}
return chromedp.Tasks{
network.Enable(),
network.SetExtraHTTPHeaders(headers),
chromedp.Navigate(host), //chromedp.WaitVisible(`#reactRoot > div > main > div:nth-child(3) > div > div > div > div > div > div > div > div > div:nth-child(33) > div > section > div:nth-child(2)`),
chromedp.Sleep(5 * time.Second), // chromedp.WaitVisible(`body`, chromedp.BySearch),
chromedp.ActionFunc(func(context.Context) error {
return nil
}),
chromedp.FullScreenshot(imageBuf, 95),
}
}

View File

@@ -1,102 +0,0 @@
package action
import (
"github.com/slack-go/slack/socketmode"
"go.uber.org/zap"
"houston/internal/diagnostic"
"houston/internal/diagnostic/models"
)
type DiagnosticCommandActionHandler interface {
HandleAction(e *socketmode.Event, alertname string) models.Runbook
}
type HandlerData struct {
logger *zap.Logger
client *socketmode.Client
repository *diagnostic.Repository
}
type GrafanaActionHandler struct {
grafanaHandlerData HandlerData
}
type KibanaActionHandler struct {
kibanaHandlerData HandlerData
}
type DeploymentPortalHandler struct {
deploymentPortalHandlerData HandlerData
}
type DeploymentConfigHandler struct {
deploymentConfigHandlerData HandlerData
}
func NewGrafanaActionHandler(client *socketmode.Client, repository *diagnostic.Repository) *GrafanaActionHandler {
return &GrafanaActionHandler{
grafanaHandlerData: HandlerData{
client: client,
repository: repository,
},
}
}
func NewKibanaActionHandler(client *socketmode.Client) *KibanaActionHandler {
return &KibanaActionHandler{
kibanaHandlerData: HandlerData{
client: client,
},
}
}
func NewDeploymentPortalActionHandler(client *socketmode.Client, repository *diagnostic.Repository) *DeploymentPortalHandler {
return &DeploymentPortalHandler{
deploymentPortalHandlerData: HandlerData{
client: client,
repository: repository,
},
}
}
func NewDeploymentConfigActionHandler(client *socketmode.Client, repository *diagnostic.Repository) *DeploymentConfigHandler {
return &DeploymentConfigHandler{
deploymentConfigHandlerData: HandlerData{
client: client,
repository: repository,
},
}
}
func (gah *GrafanaActionHandler) HandleAction(e *socketmode.Event, alertName string) models.Runbook {
imagePaths := diagnostic.TakeScreenshotAndUpload(gah.grafanaHandlerData.repository, alertName)
var runbook models.Runbook
runbook.ImagePaths = imagePaths
return runbook
}
func (kah *KibanaActionHandler) HandleAction(e *socketmode.Event, alertName string) models.Runbook {
var runbook models.Runbook
kibanaResponse := diagnostic.GetKibana()
kibanaResponseArray := make([]string, 0)
kibanaResponseArray = append(kibanaResponseArray, kibanaResponse)
runbook.TextSnippets = kibanaResponseArray
return runbook
}
func (dph *DeploymentPortalHandler) HandleAction(e *socketmode.Event, alertName string) models.Runbook {
var runbook models.Runbook
deploymentDetails := diagnostic.DeploymentPortalHandler(dph.deploymentPortalHandlerData.repository, alertName)
runbook.TextSnippets = deploymentDetails
return runbook
}
func (dph *DeploymentConfigHandler) HandleAction(e *socketmode.Event, alertName string) models.Runbook {
var runbook models.Runbook
configDiff := diagnostic.DeploymentConfigHandler(dph.deploymentConfigHandlerData.repository, alertName)
runbook.TextSnippets = configDiff
return runbook
}

View File

@@ -2,16 +2,11 @@ package processor
import (
"fmt"
"github.com/slack-go/slack"
"github.com/slack-go/slack/socketmode"
"go.uber.org/zap"
"houston/internal/diagnostic"
"houston/internal/diagnostic/models"
"houston/internal/processor/action"
"houston/logger"
"houston/pkg/slackbot"
rcaService "houston/service/rca/impl"
"strings"
)
type CommandProcessor interface {
@@ -23,24 +18,6 @@ type SlashCommandProcessor struct {
slashCommandAction *action.HoustonCommandAction
}
type DiagnosticCommandProcessor struct {
logger *zap.Logger
socketModeClient *socketmode.Client
diagnosticCommandActions []action.DiagnosticCommandActionHandler
}
func NewDiagnosticCommandProcessor(socketModeClient *socketmode.Client, repository *diagnostic.Repository) *DiagnosticCommandProcessor {
return &DiagnosticCommandProcessor{
socketModeClient: socketModeClient,
diagnosticCommandActions: []action.DiagnosticCommandActionHandler{
action.NewDeploymentConfigActionHandler(socketModeClient, repository),
action.NewGrafanaActionHandler(socketModeClient, repository),
//action.NewKibanaActionHandler(logger, socketModeClient),
action.NewDeploymentPortalActionHandler(socketModeClient, repository),
},
}
}
func NewSlashCommandProcessor(
socketModeClient *socketmode.Client,
slackBot *slackbot.Client,
@@ -61,50 +38,3 @@ func (scp *SlashCommandProcessor) ProcessSlashCommand(event *socketmode.Event) {
scp.slashCommandAction.PerformAction(event)
}
func (dcp *DiagnosticCommandProcessor) ShouldProcessCommand(text string) bool {
commands := strings.Split(text, " ")
return len(commands) > 0 && commands[0] == "diagnose"
}
func (dcp *DiagnosticCommandProcessor) ProcessSlashCommand(e *socketmode.Event) {
dcp.socketModeClient.Ack(*e.Request, nil)
_, ok := e.Data.(slack.SlashCommand)
if !ok {
logger.Error("Unable to convert event to slash command", zap.Any("event", e))
return
}
cmd := e.Data.(slack.SlashCommand)
postAckMessage(&dcp.socketModeClient.Client, &cmd)
commands := strings.Split(cmd.Text, " ")
runbooks := make([]models.Runbook, 0)
for _, actionHandler := range dcp.diagnosticCommandActions {
runbooks = append(runbooks, actionHandler.HandleAction(e, commands[1]))
}
diagnosticDataAssembler := diagnostic.NewDiagnosticDataAssembler2()
image, text := diagnosticDataAssembler.HandleData(runbooks)
postDataOnSlack(&dcp.socketModeClient.Client, &cmd, &image, text)
logger.Error("S3 upload failed", zap.Any("error", e))
}
func postDataOnSlack(api *slack.Client, sh *slack.SlashCommand, message *slack.MsgOption, attachments []slack.Attachment) {
y, x, err := api.PostMessage(
sh.ChannelID,
*message,
slack.MsgOptionAttachments(attachments...),
)
if err != nil {
fmt.Printf("error occured %s", err)
}
fmt.Println(y, x)
}
func postAckMessage(api *slack.Client, sh *slack.SlashCommand) {
textBlock := slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("Your request has been acknowledged for\n> %s", sh.Text), false, false)
block := slack.NewSectionBlock(textBlock, nil, nil)
var messageBlock slack.MsgOption
messageBlock = slack.MsgOptionBlocks(block)
postDataOnSlack(api, sh, &messageBlock, nil)
}

View File

@@ -14,23 +14,20 @@ import (
)
type HoustonCommandResolver struct {
diagnosticCommandProcessor *processor.DiagnosticCommandProcessor
socketModeClient *socketmode.Client
slackBotClient *slackbot.Client
rcaService *rcaService.RcaService
socketModeClient *socketmode.Client
slackBotClient *slackbot.Client
rcaService *rcaService.RcaService
}
func NewHoustonCommandResolver(
diagnosticCommandProcessor *processor.DiagnosticCommandProcessor,
socketModeClient *socketmode.Client,
slackBotClient *slackbot.Client,
rcaService *rcaService.RcaService,
) *HoustonCommandResolver {
return &HoustonCommandResolver{
diagnosticCommandProcessor: diagnosticCommandProcessor,
socketModeClient: socketModeClient,
slackBotClient: slackBotClient,
rcaService: rcaService,
socketModeClient: socketModeClient,
slackBotClient: slackBotClient,
rcaService: rcaService,
}
}
@@ -38,9 +35,6 @@ const logTag = "[houston_command_resolver]"
func (resolver *HoustonCommandResolver) Resolve(evt *socketmode.Event) processor.CommandProcessor {
cmd, _ := evt.Data.(slack.SlashCommand)
if resolver.diagnosticCommandProcessor.ShouldProcessCommand(cmd.Text) {
resolver.diagnosticCommandProcessor.ProcessSlashCommand(evt)
}
logger.Info(fmt.Sprintf("%s received slash command [%s] from channel [%s] by user [%s]", logTag, fmt.Sprintf("%s %s", cmd.Command, cmd.Text), cmd.ChannelName, cmd.UserName))
params := strings.ToLower(cmd.Text)

View File

@@ -1,12 +0,0 @@
package role
import "gorm.io/gorm"
type RoleEntity struct {
gorm.Model
name string `gorm:"column:name"`
}
func (RoleEntity) TableName() string {
return "role"
}

View File

@@ -1,34 +0,0 @@
package role
import (
"fmt"
"houston/logger"
"go.uber.org/zap"
"gorm.io/gorm"
)
type Repository struct {
gormClient *gorm.DB
}
func NewRoleRepository(gormClient *gorm.DB) *Repository {
return &Repository{
gormClient: gormClient,
}
}
func (r *Repository) FindRoleById(id int) (*RoleEntity, error) {
role := RoleEntity{}
tx := r.gormClient.Raw("select * from role where id = ?", id).Scan(&role)
if tx.Error != nil {
logger.Error("Error while getting role", zap.String("exception", fmt.Sprintf("%v", tx.Error)))
return nil, tx.Error
}
if tx.RowsAffected == 0 {
return nil, nil
}
return &role, nil
}