From e0f72f5c8247ac526a6e931672e18c63becb0f19 Mon Sep 17 00:00:00 2001 From: hippo-an Date: Tue, 27 Aug 2024 13:48:45 +0900 Subject: [PATCH 1/3] add rsync in ant runtime --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ac262a4..bb92982 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH make build FROM ubuntu:22.04 as prod RUN apt update && \ - apt install -y sudo curl + apt install -y sudo curl rsync # ANT ROOT PATH ENV ANT_ROOT_PATH=/app From a9b91799b072335b560e4da0f0b20255ab339bf8 Mon Sep 17 00:00:00 2001 From: hippo-an Date: Tue, 27 Aug 2024 14:01:32 +0900 Subject: [PATCH 2/3] seperate dto from service file to dto file --- internal/core/load/dtos.go | 254 ++++++++++++++++++++++++++++++++++ internal/core/load/service.go | 247 +-------------------------------- 2 files changed, 255 insertions(+), 246 deletions(-) create mode 100644 internal/core/load/dtos.go diff --git a/internal/core/load/dtos.go b/internal/core/load/dtos.go new file mode 100644 index 0000000..f8b28d2 --- /dev/null +++ b/internal/core/load/dtos.go @@ -0,0 +1,254 @@ +package load + +import ( + "time" + + "github.com/cloud-barista/cm-ant/internal/core/common/constant" +) + +// MonitoringAgentInstallationParams represents parameters for installing a monitoring agent. +type MonitoringAgentInstallationParams struct { + NsId string `json:"nsId"` + MciId string `json:"mciId"` + VmIds []string `json:"vmIds,omitempty"` +} + +// MonitoringAgentInstallationResult represents the result of a monitoring agent installation. +type MonitoringAgentInstallationResult struct { + ID uint `json:"id,omitempty"` + NsId string `json:"nsId,omitempty"` + MciId string `json:"mciId,omitempty"` + VmId string `json:"vmId,omitempty"` + VmCount int `json:"vmCount,omitempty"` + Status string `json:"status,omitempty"` + Username string `json:"username,omitempty"` + AgentType string `json:"agentType,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` +} + +type GetAllMonitoringAgentInfosParam struct { + Page int `json:"page"` + Size int `json:"size"` + NsId string `json:"nsId,omitempty"` + MciId string `json:"mciId,omitempty"` + VmId string `json:"vmId,omitempty"` +} + +type GetAllMonitoringAgentInfoResult struct { + MonitoringAgentInfos []MonitoringAgentInstallationResult `json:"monitoringAgentInfos,omitempty"` + TotalRow int64 `json:"totalRow,omitempty"` +} + +type InstallLoadGeneratorParam struct { + InstallLocation constant.InstallLocation `json:"installLocation,omitempty"` + Coordinates []string `json:"coordinate"` +} + +type LoadGeneratorServerResult struct { + ID uint `json:"id,omitempty"` + Csp string `json:"csp,omitempty"` + Region string `json:"region,omitempty"` + Zone string `json:"zone,omitempty"` + PublicIp string `json:"publicIp,omitempty"` + PrivateIp string `json:"privateIp,omitempty"` + PublicDns string `json:"publicDns,omitempty"` + MachineType string `json:"machineType,omitempty"` + Status string `json:"status,omitempty"` + SshPort string `json:"sshPort,omitempty"` + Lat string `json:"lat,omitempty"` + Lon string `json:"lon,omitempty"` + Username string `json:"username,omitempty"` + VmId string `json:"vmId,omitempty"` + StartTime time.Time `json:"startTime,omitempty"` + AdditionalVmKey string `json:"additionalVmKey,omitempty"` + Label string `json:"label,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` +} + +type LoadGeneratorInstallInfoResult struct { + ID uint `json:"id,omitempty"` + InstallLocation constant.InstallLocation `json:"installLocation,omitempty"` + InstallType string `json:"installType,omitempty"` + InstallPath string `json:"installPath,omitempty"` + InstallVersion string `json:"installVersion,omitempty"` + Status string `json:"status,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` + + PublicKeyName string `json:"publicKeyName,omitempty"` + PrivateKeyName string `json:"privateKeyName,omitempty"` + LoadGeneratorServers []LoadGeneratorServerResult `json:"loadGeneratorServers,omitempty"` +} + +type UninstallLoadGeneratorParam struct { + LoadGeneratorInstallInfoId uint +} + +type GetAllLoadGeneratorInstallInfoParam struct { + Page int `json:"page"` + Size int `json:"size"` + Status string `json:"Status"` +} + +type GetAllLoadGeneratorInstallInfoResult struct { + LoadGeneratorInstallInfoResults []LoadGeneratorInstallInfoResult `json:"loadGeneratorInstallInfoResults,omitempty"` + TotalRows int64 `json:"totalRows,omitempty"` +} + +type RunLoadTestParam struct { + LoadTestKey string `json:"loadTestKey"` + InstallLoadGenerator InstallLoadGeneratorParam `json:"installLoadGenerator"` + LoadGeneratorInstallInfoId uint `json:"loadGeneratorInstallInfoId"` + TestName string `json:"testName"` + VirtualUsers string `json:"virtualUsers"` + Duration string `json:"duration"` + RampUpTime string `json:"rampUpTime"` + RampUpSteps string `json:"rampUpSteps"` + Hostname string `json:"hostname"` + Port string `json:"port"` + AgentInstalled bool `json:"agentInstalled"` + AgentHostname string `json:"agentHostname"` + + HttpReqs []RunLoadTestHttpParam `json:"httpReqs,omitempty"` +} + +type RunLoadTestHttpParam struct { + Method string `json:"method"` + Protocol string `json:"protocol"` + Hostname string `json:"hostname"` + Port string `json:"port"` + Path string `json:"path,omitempty"` + BodyData string `json:"bodyData,omitempty"` +} + +type GetAllLoadTestExecutionStateParam struct { + Page int `json:"page"` + Size int `json:"size"` + LoadTestKey string `json:"loadTestKey"` + ExecutionStatus constant.ExecutionStatus `json:"executionStatus"` +} + +type GetAllLoadTestExecutionStateResult struct { + LoadTestExecutionStates []LoadTestExecutionStateResult `json:"loadTestExecutionStates,omitempty"` + TotalRow int64 `json:"totalRow,omitempty"` +} + +type LoadTestExecutionStateResult struct { + ID uint `json:"id"` + LoadGeneratorInstallInfoId uint `json:"loadGeneratorInstallInfoId,omitempty"` + LoadGeneratorInstallInfo LoadGeneratorInstallInfoResult `json:"loadGeneratorInstallInfo,omitempty"` + LoadTestKey string `json:"loadTestKey,omitempty"` + ExecutionStatus constant.ExecutionStatus `json:"executionStatus,omitempty"` + StartAt time.Time `json:"startAt,omitempty"` + FinishAt *time.Time `json:"finishAt,omitempty"` + TotalExpectedExcutionSecond uint64 `json:"totalExpectedExecutionSecond,omitempty"` + FailureMessage string `json:"failureMessage,omitempty"` + CompileDuration string `json:"compileDuration,omitempty"` + ExecutionDuration string `json:"executionDuration,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` +} + +type GetLoadTestExecutionStateParam struct { + LoadTestKey string `json:"loadTestKey"` +} + +type GetAllLoadTestExecutionInfosParam struct { + Page int `json:"page"` + Size int `json:"size"` +} + +type GetAllLoadTestExecutionInfosResult struct { + TotalRow int64 `json:"totalRow,omitempty"` + LoadTestExecutionInfos []LoadTestExecutionInfoResult `json:"loadTestExecutionInfos,omitempty"` +} + +type LoadTestExecutionInfoResult struct { + ID uint `json:"id"` + LoadTestKey string `json:"loadTestKey,omitempty"` + TestName string `json:"testName,omitempty"` + VirtualUsers string `json:"virtualUsers,omitempty"` + Duration string `json:"duration,omitempty"` + RampUpTime string `json:"rampUpTime,omitempty"` + RampUpSteps string `json:"rampUpSteps,omitempty"` + Hostname string `json:"hostname,omitempty"` + Port string `json:"port,omitempty"` + AgentHostname string `json:"agentHostname,omitempty"` + AgentInstalled bool `json:"agentInstalled,omitempty"` + CompileDuration string `json:"compileDuration,omitempty"` + ExecutionDuration string `json:"executionDuration,omitempty"` + LoadTestExecutionHttpInfos []LoadTestExecutionHttpInfoResult `json:"loadTestExecutionHttpInfos,omitempty"` + LoadTestExecutionState LoadTestExecutionStateResult `json:"loadTestExecutionState,omitempty"` + LoadGeneratorInstallInfo LoadGeneratorInstallInfoResult `json:"loadGeneratorInstallInfo,omitempty"` +} + +type LoadTestExecutionHttpInfoResult struct { + ID uint `json:"id"` + Method string `json:"method,omitempty"` + Protocol string `json:"protocol,omitempty"` + Hostname string `json:"hostname,omitempty"` + Port string `json:"port,omitempty"` + Path string `json:"path,omitempty"` + BodyData string `json:"bodyData,omitempty"` +} + +type GetLoadTestExecutionInfoParam struct { + LoadTestKey string `json:"loadTestKey"` +} + +type StopLoadTestParam struct { + LoadTestKey string `json:"loadTestKey"` +} + +type ResultSummary struct { + Label string + Results []*ResultRawData +} + +type MetricsSummary struct { + Label string + Metrics []*MetricsRawData +} + +type ResultRawData struct { + No int + Elapsed int // time to last byte + Bytes int + SentBytes int + URL string + Latency int // time to first byte + IdleTime int // time not spent sampling in jmeter (milliseconds) (generally 0) + Connection int // time to establish connection + IsError bool + Timestamp time.Time +} + +type MetricsRawData struct { + Value string + Unit string + IsError bool + Timestamp time.Time +} + +type LoadTestStatistics struct { + Label string `json:"label"` + RequestCount int `json:"requestCount"` + Average float64 `json:"average"` + Median float64 `json:"median"` + NinetyPercent float64 `json:"ninetyPercent"` + NinetyFive float64 `json:"ninetyFive"` + NinetyNine float64 `json:"ninetyNine"` + MinTime float64 `json:"minTime"` + MaxTime float64 `json:"maxTime"` + ErrorPercent float64 `json:"errorPercent"` + Throughput float64 `json:"throughput"` + ReceivedKB float64 `json:"receivedKB"` + SentKB float64 `json:"sentKB"` +} + +type GetLoadTestResultParam struct { + LoadTestKey string + Format constant.ResultFormat +} diff --git a/internal/core/load/service.go b/internal/core/load/service.go index 0c7e638..c7f9e78 100644 --- a/internal/core/load/service.go +++ b/internal/core/load/service.go @@ -35,27 +35,6 @@ func NewLoadService(loadRepo *LoadRepository, client *tumblebug.TumblebugClient) } } -// MonitoringAgentInstallationParams represents parameters for installing a monitoring agent. -type MonitoringAgentInstallationParams struct { - NsId string `json:"nsId"` - MciId string `json:"mciId"` - VmIds []string `json:"vmIds,omitempty"` -} - -// MonitoringAgentInstallationResult represents the result of a monitoring agent installation. -type MonitoringAgentInstallationResult struct { - ID uint `json:"id,omitempty"` - NsId string `json:"nsId,omitempty"` - MciId string `json:"mciId,omitempty"` - VmId string `json:"vmId,omitempty"` - VmCount int `json:"vmCount,omitempty"` - Status string `json:"status,omitempty"` - Username string `json:"username,omitempty"` - AgentType string `json:"agentType,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty"` - UpdatedAt time.Time `json:"updatedAt,omitempty"` -} - // InstallMonitoringAgent installs a monitoring agent on specified VMs or all VM on mci. func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationParams) ([]MonitoringAgentInstallationResult, error) { utils.LogInfo("Starting installation of monitoring agent...") @@ -85,7 +64,7 @@ func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationPa } var mapSet map[string]struct{} - if param.VmIds != nil && len(param.VmIds) > 0 { + if len(param.VmIds) > 0 { mapSet = utils.SliceToMap(param.VmIds) } @@ -167,19 +146,6 @@ func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationPa return res, nil } -type GetAllMonitoringAgentInfosParam struct { - Page int `json:"page"` - Size int `json:"size"` - NsId string `json:"nsId,omitempty"` - MciId string `json:"mciId,omitempty"` - VmId string `json:"vmId,omitempty"` -} - -type GetAllMonitoringAgentInfoResult struct { - MonitoringAgentInfos []MonitoringAgentInstallationResult `json:"monitoringAgentInfos,omitempty"` - TotalRow int64 `json:"totalRow,omitempty"` -} - func (l *LoadService) GetAllMonitoringAgentInfos(param GetAllMonitoringAgentInfosParam) (GetAllMonitoringAgentInfoResult, error) { var res GetAllMonitoringAgentInfoResult var monitoringAgentInfos []MonitoringAgentInstallationResult @@ -280,48 +246,6 @@ func (l *LoadService) UninstallMonitoringAgent(param MonitoringAgentInstallation return effectedResults, nil } -type InstallLoadGeneratorParam struct { - InstallLocation constant.InstallLocation `json:"installLocation,omitempty"` - Coordinates []string `json:"coordinate"` -} - -type LoadGeneratorServerResult struct { - ID uint `json:"id,omitempty"` - Csp string `json:"csp,omitempty"` - Region string `json:"region,omitempty"` - Zone string `json:"zone,omitempty"` - PublicIp string `json:"publicIp,omitempty"` - PrivateIp string `json:"privateIp,omitempty"` - PublicDns string `json:"publicDns,omitempty"` - MachineType string `json:"machineType,omitempty"` - Status string `json:"status,omitempty"` - SshPort string `json:"sshPort,omitempty"` - Lat string `json:"lat,omitempty"` - Lon string `json:"lon,omitempty"` - Username string `json:"username,omitempty"` - VmId string `json:"vmId,omitempty"` - StartTime time.Time `json:"startTime,omitempty"` - AdditionalVmKey string `json:"additionalVmKey,omitempty"` - Label string `json:"label,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty"` - UpdatedAt time.Time `json:"updatedAt,omitempty"` -} - -type LoadGeneratorInstallInfoResult struct { - ID uint `json:"id,omitempty"` - InstallLocation constant.InstallLocation `json:"installLocation,omitempty"` - InstallType string `json:"installType,omitempty"` - InstallPath string `json:"installPath,omitempty"` - InstallVersion string `json:"installVersion,omitempty"` - Status string `json:"status,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty"` - UpdatedAt time.Time `json:"updatedAt,omitempty"` - - PublicKeyName string `json:"publicKeyName,omitempty"` - PrivateKeyName string `json:"privateKeyName,omitempty"` - LoadGeneratorServers []LoadGeneratorServerResult `json:"loadGeneratorServers,omitempty"` -} - const ( antNsId = "ant-default-ns" antMciDescription = "Default MCI for Cloud Migration Verification" @@ -748,10 +672,6 @@ func (l *LoadService) validDefaultNs(ctx context.Context, antNsId string) error return nil } -type UninstallLoadGeneratorParam struct { - LoadGeneratorInstallInfoId uint -} - func (l *LoadService) UninstallLoadGenerator(param UninstallLoadGeneratorParam) error { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() @@ -822,17 +742,6 @@ func (l *LoadService) UninstallLoadGenerator(param UninstallLoadGeneratorParam) return nil } -type GetAllLoadGeneratorInstallInfoParam struct { - Page int `json:"page"` - Size int `json:"size"` - Status string `json:"Status"` -} - -type GetAllLoadGeneratorInstallInfoResult struct { - LoadGeneratorInstallInfoResults []LoadGeneratorInstallInfoResult `json:"loadGeneratorInstallInfoResults,omitempty"` - TotalRows int64 `json:"totalRows,omitempty"` -} - func (l *LoadService) GetAllLoadGeneratorInstallInfo(param GetAllLoadGeneratorInstallInfoParam) (GetAllLoadGeneratorInstallInfoResult, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -896,32 +805,6 @@ func (l *LoadService) GetAllLoadGeneratorInstallInfo(param GetAllLoadGeneratorIn return result, nil } -type RunLoadTestParam struct { - LoadTestKey string `json:"loadTestKey"` - InstallLoadGenerator InstallLoadGeneratorParam `json:"installLoadGenerator"` - LoadGeneratorInstallInfoId uint `json:"loadGeneratorInstallInfoId"` - TestName string `json:"testName"` - VirtualUsers string `json:"virtualUsers"` - Duration string `json:"duration"` - RampUpTime string `json:"rampUpTime"` - RampUpSteps string `json:"rampUpSteps"` - Hostname string `json:"hostname"` - Port string `json:"port"` - AgentInstalled bool `json:"agentInstalled"` - AgentHostname string `json:"agentHostname"` - - HttpReqs []RunLoadTestHttpParam `json:"httpReqs,omitempty"` -} - -type RunLoadTestHttpParam struct { - Method string `json:"method"` - Protocol string `json:"protocol"` - Hostname string `json:"hostname"` - Port string `json:"port"` - Path string `json:"path,omitempty"` - BodyData string `json:"bodyData,omitempty"` -} - // RunLoadTest initiates the load test and performs necessary initializations. // Generates a load test key, installs the load generator or retrieves existing installation information, // saves the load test execution state, and then asynchronously runs the load test. @@ -1348,34 +1231,6 @@ func generateJmeterExecutionCmd(loadGeneratorInstallPath, loadGeneratorInstallVe return builder.String() } -type GetAllLoadTestExecutionStateParam struct { - Page int `json:"page"` - Size int `json:"size"` - LoadTestKey string `json:"loadTestKey"` - ExecutionStatus constant.ExecutionStatus `json:"executionStatus"` -} - -type GetAllLoadTestExecutionStateResult struct { - LoadTestExecutionStates []LoadTestExecutionStateResult `json:"loadTestExecutionStates,omitempty"` - TotalRow int64 `json:"totalRow,omitempty"` -} - -type LoadTestExecutionStateResult struct { - ID uint `json:"id"` - LoadGeneratorInstallInfoId uint `json:"loadGeneratorInstallInfoId,omitempty"` - LoadGeneratorInstallInfo LoadGeneratorInstallInfoResult `json:"loadGeneratorInstallInfo,omitempty"` - LoadTestKey string `json:"loadTestKey,omitempty"` - ExecutionStatus constant.ExecutionStatus `json:"executionStatus,omitempty"` - StartAt time.Time `json:"startAt,omitempty"` - FinishAt *time.Time `json:"finishAt,omitempty"` - TotalExpectedExcutionSecond uint64 `json:"totalExpectedExecutionSecond,omitempty"` - FailureMessage string `json:"failureMessage,omitempty"` - CompileDuration string `json:"compileDuration,omitempty"` - ExecutionDuration string `json:"executionDuration,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty"` - UpdatedAt time.Time `json:"updatedAt,omitempty"` -} - func (l *LoadService) GetAllLoadTestExecutionState(param GetAllLoadTestExecutionStateParam) (GetAllLoadTestExecutionStateResult, error) { var res GetAllLoadTestExecutionStateResult var states []LoadTestExecutionStateResult @@ -1404,10 +1259,6 @@ func (l *LoadService) GetAllLoadTestExecutionState(param GetAllLoadTestExecution return res, nil } -type GetLoadTestExecutionStateParam struct { - LoadTestKey string `json:"loadTestKey"` -} - func (l *LoadService) GetLoadTestExecutionState(param GetLoadTestExecutionStateParam) (LoadTestExecutionStateResult, error) { var res LoadTestExecutionStateResult ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) @@ -1426,45 +1277,6 @@ func (l *LoadService) GetLoadTestExecutionState(param GetLoadTestExecutionStateP return res, nil } -type GetAllLoadTestExecutionInfosParam struct { - Page int `json:"page"` - Size int `json:"size"` -} - -type GetAllLoadTestExecutionInfosResult struct { - TotalRow int64 `json:"totalRow,omitempty"` - LoadTestExecutionInfos []LoadTestExecutionInfoResult `json:"loadTestExecutionInfos,omitempty"` -} - -type LoadTestExecutionInfoResult struct { - ID uint `json:"id"` - LoadTestKey string `json:"loadTestKey,omitempty"` - TestName string `json:"testName,omitempty"` - VirtualUsers string `json:"virtualUsers,omitempty"` - Duration string `json:"duration,omitempty"` - RampUpTime string `json:"rampUpTime,omitempty"` - RampUpSteps string `json:"rampUpSteps,omitempty"` - Hostname string `json:"hostname,omitempty"` - Port string `json:"port,omitempty"` - AgentHostname string `json:"agentHostname,omitempty"` - AgentInstalled bool `json:"agentInstalled,omitempty"` - CompileDuration string `json:"compileDuration,omitempty"` - ExecutionDuration string `json:"executionDuration,omitempty"` - LoadTestExecutionHttpInfos []LoadTestExecutionHttpInfoResult `json:"loadTestExecutionHttpInfos,omitempty"` - LoadTestExecutionState LoadTestExecutionStateResult `json:"loadTestExecutionState,omitempty"` - LoadGeneratorInstallInfo LoadGeneratorInstallInfoResult `json:"loadGeneratorInstallInfo,omitempty"` -} - -type LoadTestExecutionHttpInfoResult struct { - ID uint `json:"id"` - Method string `json:"method,omitempty"` - Protocol string `json:"protocol,omitempty"` - Hostname string `json:"hostname,omitempty"` - Port string `json:"port,omitempty"` - Path string `json:"path,omitempty"` - BodyData string `json:"bodyData,omitempty"` -} - func (l *LoadService) GetAllLoadTestExecutionInfos(param GetAllLoadTestExecutionInfosParam) (GetAllLoadTestExecutionInfosResult, error) { var res GetAllLoadTestExecutionInfosResult var rs []LoadTestExecutionInfoResult @@ -1491,10 +1303,6 @@ func (l *LoadService) GetAllLoadTestExecutionInfos(param GetAllLoadTestExecution return res, nil } -type GetLoadTestExecutionInfoParam struct { - LoadTestKey string `json:"loadTestKey"` -} - func (l *LoadService) GetLoadTestExecutionInfo(param GetLoadTestExecutionInfoParam) (LoadTestExecutionInfoResult, error) { var res LoadTestExecutionInfoResult ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) @@ -1612,10 +1420,6 @@ func mapLoadTestExecutionInfoResult(executionInfo LoadTestExecutionInfo) LoadTes } } -type StopLoadTestParam struct { - LoadTestKey string `json:"loadTestKey"` -} - func (l *LoadService) StopLoadTest(param StopLoadTestParam) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -1666,54 +1470,10 @@ func killCmdGen(loadTestKey string) string { return fmt.Sprintf("kill -15 $(ps -ef | grep -E %s | awk '{print $2}')", grepRegex) } -type ResultSummary struct { - Label string - Results []*ResultRawData -} - -type MetricsSummary struct { - Label string - Metrics []*MetricsRawData -} - -type ResultRawData struct { - No int - Elapsed int // time to last byte - Bytes int - SentBytes int - URL string - Latency int // time to first byte - IdleTime int // time not spent sampling in jmeter (milliseconds) (generally 0) - Connection int // time to establish connection - IsError bool - Timestamp time.Time -} - -type MetricsRawData struct { - Value string - Unit string - IsError bool - Timestamp time.Time -} type metricsUnits struct { Multiple float64 Unit string } -type LoadTestStatistics struct { - Label string `json:"label"` - RequestCount int `json:"requestCount"` - Average float64 `json:"average"` - Median float64 `json:"median"` - NinetyPercent float64 `json:"ninetyPercent"` - NinetyFive float64 `json:"ninetyFive"` - NinetyNine float64 `json:"ninetyNine"` - MinTime float64 `json:"minTime"` - MaxTime float64 `json:"maxTime"` - ErrorPercent float64 `json:"errorPercent"` - Throughput float64 `json:"throughput"` - ReceivedKB float64 `json:"receivedKB"` - SentKB float64 `json:"sentKB"` -} var tags = map[string]metricsUnits{ "cpu_all_combined": { @@ -1766,11 +1526,6 @@ var tags = map[string]metricsUnits{ }, } -type GetLoadTestResultParam struct { - LoadTestKey string - Format constant.ResultFormat -} - func (l *LoadService) GetLoadTestResult(param GetLoadTestResultParam) (interface{}, error) { loadTestKey := param.LoadTestKey fileName := fmt.Sprintf("%s_result.csv", loadTestKey) From e4b77eb2aa575970f9b08b1de4327f8b670f1250 Mon Sep 17 00:00:00 2001 From: hippo-an Date: Wed, 11 Sep 2024 18:09:54 +0900 Subject: [PATCH 3/3] Update readyz API to check database connection and subsystem readiness - Modified readyz API to include health checks for the database connection. - Added readiness checks for related subsystems. - Update readyz endpoint from /ant/api/v1/readyz to /ant/readyz - Update readyz swagger documentation --- .gitignore | 3 +- Dockerfile | 2 +- Makefile | 82 +----------- api/docs.go | 36 ++++++ api/swagger.json | 36 ++++++ api/swagger.yaml | 26 ++++ docker-compose.yaml | 14 +-- internal/app/common_handler.go | 37 ++++++ ..._handler.go => cost_estimation_handler.go} | 0 .../{cost_req.go => cost_estimation_req.go} | 0 internal/app/middlewares.go | 118 ++++++++++++++++++ ...r.go => performance_evaluation_handler.go} | 5 - ...d_req.go => performance_evaluation_req.go} | 0 .../app/{helper.go => response_helper.go} | 0 internal/app/router.go | 75 +---------- internal/core/cost/cost_collector.go | 10 ++ internal/core/cost/price_collector.go | 10 ++ internal/core/cost/service.go | 27 ++++ internal/core/load/service.go | 22 ++++ internal/infra/outbound/spider/req.go | 4 +- .../spider/{spider.go => spider_client.go} | 27 ++-- .../outbound/tumblebug/tumblebug_client.go | 15 ++- 22 files changed, 369 insertions(+), 180 deletions(-) create mode 100644 internal/app/common_handler.go rename internal/app/{cost_handler.go => cost_estimation_handler.go} (100%) rename internal/app/{cost_req.go => cost_estimation_req.go} (100%) create mode 100644 internal/app/middlewares.go rename internal/app/{load_handler.go => performance_evaluation_handler.go} (99%) rename internal/app/{load_req.go => performance_evaluation_req.go} (100%) rename internal/app/{helper.go => response_helper.go} (100%) rename internal/infra/outbound/spider/{spider.go => spider_client.go} (77%) diff --git a/.gitignore b/.gitignore index 77bc7f1..a558c8e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ meta/*.db ant data conf -container-volume \ No newline at end of file +container-volume +./bin/** \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2585b90..c40188c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ARG TARGETOS=linux ARG TARGETARCH=amd64 RUN apt-get update && \ - apt-get install -y --no-install-recommends make && \ + apt-get install -y --no-install-recommends make rsync && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* diff --git a/Makefile b/Makefile index 03fa44b..7daf09d 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,3 @@ -########################################################### -ANT_NETWORK=cm-ant-local-net -DB_CONTAINER_NAME=ant-local-postgres -DB_NAME=cm-ant-db -DB_USER=cm-ant-user -DB_PASSWORD=cm-ant-secret - -ANT_CONTAINER_NAME=cm-ant -OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') -ARCH := $(shell uname -m) - -ifeq ($(ARCH),x86_64) - ARCH := amd64 -else ifeq ($(ARCH),arm64) - ARCH := arm64 -else ifeq ($(ARCH),aarch64) - ARCH := arm64 -endif -########################################################### - ########################################################### .PHONY: swag swag: @@ -32,66 +12,6 @@ build: ########################################################### .PHONY: run -run: run-db +run: @go run cmd/cm-ant/main.go ########################################################### - -########################################################### -.PHONY: create-network -create-network: - @if [ -z "$$(docker network ls -q -f name=$(ANT_NETWORK))" ]; then \ - echo "Creating cm-ant network..."; \ - docker network create --driver bridge $(ANT_NETWORK); \ - echo "cm-ant network created!"; \ - else \ - echo "cm-ant network already exist..."; \ - fi -########################################################### - -########################################################### -.PHONY: run-db -run-db: create-network - @if [ -z "$$(docker container ps -q -f name=$(DB_CONTAINER_NAME))" ]; then \ - echo "Run database container...."; \ - docker container run \ - --name $(DB_CONTAINER_NAME) \ - --network $(ANT_NETWORK) \ - -p 5432:5432 \ - -e POSTGRES_USER=$(DB_USER) \ - -e POSTGRES_PASSWORD=$(DB_PASSWORD) \ - -e POSTGRES_DB=$(DB_NAME) \ - -d --rm \ - timescale/timescaledb:latest-pg16; \ - echo "Started Postgres database container!"; \ - echo "Waiting for database to be ready..."; \ - for i in $$(seq 1 10); do \ - docker container exec $(DB_CONTAINER_NAME) pg_isready -U $(DB_USER) -d $(DB_NAME); \ - if [ $$? -eq 0 ]; then \ - echo "Database is ready!"; \ - break; \ - fi; \ - echo "Database is not ready yet. Waiting..."; \ - sleep 5; \ - done; \ - if [ $$i -eq 10 ]; then \ - echo "Failed to start the database"; \ - exit 1; \ - fi; \ - echo "Database $(DB_NAME) successfully started!"; \ - else \ - echo "Database container is already running."; \ - fi -########################################################### - -########################################################### -.PHONY: down -down: - @echo "Checking if the database container is running..." - @if [ -n "$$(docker container ps -q -f name=$(DB_CONTAINER_NAME))" ]; then \ - echo "Stopping and removing the database container..."; \ - docker container stop $(DB_CONTAINER_NAME); \ - echo "Database container stopped!"; \ - else \ - echo "No running database container found."; \ - fi -########################################################### \ No newline at end of file diff --git a/api/docs.go b/api/docs.go index 666eb9f..0c885eb 100644 --- a/api/docs.go +++ b/api/docs.go @@ -1006,6 +1006,42 @@ const docTemplate = `{ } } } + }, + "/readyz": { + "get": { + "description": "This endpoint checks if the CB-Ant API server is ready by verifying the status of both the load service and the cost service. If either service is unavailable, it returns a 503 status indicating the server is not ready.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Server Health]" + ], + "summary": "Check CB-Ant API server readiness", + "operationId": "AntServerReadiness", + "responses": { + "200": { + "description": "CM-Ant API server is ready", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "503": { + "description": "CB-Ant API server is not ready", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } } }, "definitions": { diff --git a/api/swagger.json b/api/swagger.json index a19e00f..42848e0 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -998,6 +998,42 @@ } } } + }, + "/readyz": { + "get": { + "description": "This endpoint checks if the CB-Ant API server is ready by verifying the status of both the load service and the cost service. If either service is unavailable, it returns a 503 status indicating the server is not ready.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Server Health]" + ], + "summary": "Check CB-Ant API server readiness", + "operationId": "AntServerReadiness", + "responses": { + "200": { + "description": "CM-Ant API server is ready", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "503": { + "description": "CB-Ant API server is not ready", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } } }, "definitions": { diff --git a/api/swagger.yaml b/api/swagger.yaml index 1811f11..a835ed8 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -1335,4 +1335,30 @@ paths: $ref: '#/definitions/app.AntResponse-string' tags: - '[Price Management]' + /readyz: + get: + consumes: + - application/json + description: This endpoint checks if the CB-Ant API server is ready by verifying + the status of both the load service and the cost service. If either service + is unavailable, it returns a 503 status indicating the server is not ready. + operationId: AntServerReadiness + produces: + - application/json + responses: + "200": + description: CM-Ant API server is ready + schema: + additionalProperties: + type: string + type: object + "503": + description: CB-Ant API server is not ready + schema: + additionalProperties: + type: string + type: object + summary: Check CB-Ant API server readiness + tags: + - '[Server Health]' swagger: "2.0" diff --git a/docker-compose.yaml b/docker-compose.yaml index 3a65d1d..a627c31 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -24,9 +24,9 @@ services: - ANT_TUMBLEBUG_PORT=1323 - ANT_DATABASE_HOST=ant-postgres healthcheck: - test: [ "CMD", "curl", "-f", "http://localhost:8880/ant/api/v1/readyz" ] + test: [ "CMD", "curl", "-f", "http://localhost:8880/ant/readyz" ] interval: 1m - timeout: 5s + timeout: 7s retries: 5 start_period: 10s restart: unless-stopped @@ -50,7 +50,7 @@ services: restart: unless-stopped cb-tumblebug: - image: cloudbaristaorg/cb-tumblebug:0.9.7 + image: cloudbaristaorg/cb-tumblebug:0.9.11 container_name: cb-tumblebug platform: linux/amd64 ports: @@ -100,8 +100,6 @@ services: retries: 3 start_period: 10s restart: unless-stopped - - cb-tumblebug-etcd: image: gcr.io/etcd-development/etcd:v3.5.14 container_name: cb-tumblebug-etcd @@ -140,8 +138,8 @@ services: - stderr - --auth-token - simple - healthcheck: # for etcd - test: [ "CMD", "/usr/local/bin/etcd", "--version"] + healthcheck: + test: [ "CMD", "/usr/local/bin/etcd", "--version"] interval: 1m timeout: 5s retries: 3 @@ -149,7 +147,7 @@ services: restart: unless-stopped cb-spider: - image: cloudbaristaorg/cb-spider:0.9.0 + image: cloudbaristaorg/cb-spider:0.9.4 container_name: cb-spider platform: linux/amd64 networks: diff --git a/internal/app/common_handler.go b/internal/app/common_handler.go new file mode 100644 index 0000000..ff3fd38 --- /dev/null +++ b/internal/app/common_handler.go @@ -0,0 +1,37 @@ +package app + +import ( + "net/http" + + "github.com/labstack/echo/v4" +) + +// @Id AntServerReadiness +// @Summary Check CB-Ant API server readiness +// @Description This endpoint checks if the CB-Ant API server is ready by verifying the status of both the load service and the cost service. If either service is unavailable, it returns a 503 status indicating the server is not ready. +// @Tags [Server Health] +// @Accept json +// @Produce json +// @Success 200 {object} map[string]string "CM-Ant API server is ready" +// @Failure 503 {object} map[string]string "CB-Ant API server is not ready" +// @Router /readyz [get] +func (s *AntServer) readyz(c echo.Context) error { + err := s.services.loadService.Readyz() + if err != nil { + return echo.NewHTTPError(http.StatusServiceUnavailable, map[string]string{ + "message": "CM-Ant API server is not ready", + }) + } + + err = s.services.costService.Readyz() + + if err != nil { + return echo.NewHTTPError(http.StatusServiceUnavailable, map[string]string{ + "message": "CM-Ant API server is not ready", + }) + } + + return c.JSON(http.StatusOK, map[string]string{ + "message": "CM-Ant API server is ready", + }) +} diff --git a/internal/app/cost_handler.go b/internal/app/cost_estimation_handler.go similarity index 100% rename from internal/app/cost_handler.go rename to internal/app/cost_estimation_handler.go diff --git a/internal/app/cost_req.go b/internal/app/cost_estimation_req.go similarity index 100% rename from internal/app/cost_req.go rename to internal/app/cost_estimation_req.go diff --git a/internal/app/middlewares.go b/internal/app/middlewares.go new file mode 100644 index 0000000..54d5bed --- /dev/null +++ b/internal/app/middlewares.go @@ -0,0 +1,118 @@ +package app + +import ( + "strings" + "time" + + _ "github.com/cloud-barista/cm-ant/api" + + "github.com/labstack/echo/v4/middleware" + + "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/labstack/echo/v4" + zerolog "github.com/rs/zerolog/log" +) + +// setMiddleware configures middleware for the Echo server. +func setMiddleware(e *echo.Echo) { + logSkipPattern := [][]string{ + {"/ant/swagger/*"}, + } + e.Use( + middleware.RequestLoggerWithConfig( + middleware.RequestLoggerConfig{ + Skipper: func(c echo.Context) bool { + path := c.Request().URL.Path + query := c.Request().URL.RawQuery + for _, patterns := range logSkipPattern { + isAllMatched := true + for _, pattern := range patterns { + if !strings.Contains(path+query, pattern) { + isAllMatched = false + break + } + } + if isAllMatched { + return true + } + } + return false + }, + LogError: true, + LogRequestID: true, + LogRemoteIP: true, + LogHost: true, + LogMethod: true, + LogURI: true, + LogUserAgent: false, + LogStatus: true, + LogLatency: true, + LogContentLength: true, + LogResponseSize: true, + LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error { + if v.Error == nil { + zerolog.Info(). + Str("id", v.RequestID). + Str("client_ip", v.RemoteIP). + // Str("host", v.Host). + Str("method", v.Method). + Str("URI", v.URI). + Int("status", v.Status). + // Int64("latency", v.Latency.Nanoseconds()). + Str("latency_human", v.Latency.String()). + Str("bytes_in", v.ContentLength). + Int64("bytes_out", v.ResponseSize). + Msg("request") + } else { + zerolog.Error(). + Err(v.Error). + Str("id", v.RequestID). + Str("client_ip", v.RemoteIP). + // Str("host", v.Host). + Str("method", v.Method). + Str("URI", v.URI). + Int("status", v.Status). + // Int64("latency", v.Latency.Nanoseconds()). + Str("latency_human", v.Latency.String()). + Str("bytes_in", v.ContentLength). + Int64("bytes_out", v.ResponseSize). + Msg("request error") + } + return nil + }, + }, + ), + middleware.TimeoutWithConfig( + middleware.TimeoutConfig{ + Skipper: middleware.DefaultSkipper, + ErrorMessage: "request timeout", + OnTimeoutRouteErrorHandler: func(err error, c echo.Context) { + utils.LogInfo(c.Path()) + }, + Timeout: 300 * time.Second, + }, + ), + middleware.Recover(), + middleware.RequestID(), + middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)), + middleware.CORS(), + ) +} + +func RequestIdAndDetailsIssuer(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + // Make X-Request-Id visible to all handlers + c.Response().Header().Set("Access-Control-Expose-Headers", echo.HeaderXRequestID) + + // Get or generate Request ID + reqID := c.Request().Header.Get(echo.HeaderXRequestID) + if reqID == "" { + reqID = utils.CreateUniqIdBaseOnUnixTime() + } + + // Set Request on the context + c.Set("RequestID", reqID) + + return next(c) + } +} diff --git a/internal/app/load_handler.go b/internal/app/performance_evaluation_handler.go similarity index 99% rename from internal/app/load_handler.go rename to internal/app/performance_evaluation_handler.go index 0c199ea..fb038e5 100644 --- a/internal/app/load_handler.go +++ b/internal/app/performance_evaluation_handler.go @@ -16,11 +16,6 @@ const ( seoul = "37.53/127.02" ) -func (s *AntServer) readyz(c echo.Context) error { - return c.JSON(http.StatusOK, map[string]string{ - "message": "CM-Ant API server is running", - }) -} // getAllLoadGeneratorInstallInfo handler function that retrieves all load generator installation information. // @Id GetAllLoadGeneratorInstallInfo diff --git a/internal/app/load_req.go b/internal/app/performance_evaluation_req.go similarity index 100% rename from internal/app/load_req.go rename to internal/app/performance_evaluation_req.go diff --git a/internal/app/helper.go b/internal/app/response_helper.go similarity index 100% rename from internal/app/helper.go rename to internal/app/response_helper.go diff --git a/internal/app/router.go b/internal/app/router.go index 656ddfb..4a05fdb 100644 --- a/internal/app/router.go +++ b/internal/app/router.go @@ -1,16 +1,10 @@ package app import ( - "time" - - "github.com/cloud-barista/cm-ant/internal/utils" - _ "github.com/cloud-barista/cm-ant/api" - "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" - zerolog "github.com/rs/zerolog/log" echoSwagger "github.com/swaggo/echo-swagger" ) @@ -20,14 +14,13 @@ func (server *AntServer) InitRouter() error { antRouter := server.e.Group("/ant") { + antRouter.GET("/readyz", server.readyz) antRouter.GET("/swagger/*", echoSwagger.WrapHandler) } apiRouter := antRouter.Group("/api") versionRouter := apiRouter.Group("/v1") - versionRouter.GET("/readyz", server.readyz) - { loadRouter := versionRouter.Group("/load") @@ -87,69 +80,3 @@ func (server *AntServer) InitRouter() error { // e.Static("/css", utils.RootPath()+"/web/css") // e.Static("/js", utils.RootPath()+"/web/js") // } - -// setMiddleware configures middleware for the Echo server. -func setMiddleware(e *echo.Echo) { - e.Use( - middleware.RequestLoggerWithConfig( - middleware.RequestLoggerConfig{ - LogError: true, - LogRequestID: true, - LogRemoteIP: true, - LogHost: true, - LogMethod: true, - LogURI: true, - LogUserAgent: false, - LogStatus: true, - LogLatency: true, - LogContentLength: true, - LogResponseSize: true, - LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error { - if v.Error == nil { - zerolog.Info(). - Str("id", v.RequestID). - Str("client_ip", v.RemoteIP). - Str("host", v.Host). - Str("method", v.Method). - Str("URI", v.URI). - Int("status", v.Status). - Int64("latency", v.Latency.Nanoseconds()). - Str("latency_human", v.Latency.String()). - Str("bytes_in", v.ContentLength). - Int64("bytes_out", v.ResponseSize). - Msg("request") - } else { - zerolog.Error(). - Err(v.Error). - Str("id", v.RequestID). - Str("client_ip", v.RemoteIP). - Str("host", v.Host). - Str("method", v.Method). - Str("URI", v.URI). - Int("status", v.Status). - Int64("latency", v.Latency.Nanoseconds()). - Str("latency_human", v.Latency.String()). - Str("bytes_in", v.ContentLength). - Int64("bytes_out", v.ResponseSize). - Msg("request error") - } - return nil - }, - }, - ), - middleware.TimeoutWithConfig( - middleware.TimeoutConfig{ - Skipper: middleware.DefaultSkipper, - ErrorMessage: "request timeout", - OnTimeoutRouteErrorHandler: func(err error, c echo.Context) { - utils.LogInfo(c.Path()) - }, - Timeout: 300 * time.Second, - }, - ), - middleware.Recover(), - middleware.RequestID(), - middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)), - middleware.CORS(), - ) -} diff --git a/internal/core/cost/cost_collector.go b/internal/core/cost/cost_collector.go index 5695798..9033f2c 100644 --- a/internal/core/cost/cost_collector.go +++ b/internal/core/cost/cost_collector.go @@ -15,6 +15,7 @@ import ( ) type CostCollector interface { + Readyz(context.Context) error GetCostInfos(context.Context, UpdateCostInfoParam) (CostInfos, error) } @@ -28,6 +29,15 @@ func NewAwsCostExplorerSpiderCostCollector(sc *spider.SpiderClient) CostCollecto } } +func (a *AwsCostExplorerSpiderCostCollector) Readyz(ctx context.Context) error { + err := a.sc.ReadyzWithContext(ctx) + if err != nil { + return err + } + + return nil +} + var ( resourceFilterMap = map[constant.ResourceType][]constant.AwsService{ constant.VM: { diff --git a/internal/core/cost/price_collector.go b/internal/core/cost/price_collector.go index bfd2dd2..9403315 100644 --- a/internal/core/cost/price_collector.go +++ b/internal/core/cost/price_collector.go @@ -15,6 +15,7 @@ import ( ) type PriceCollector interface { + Readyz(context.Context) error GetPriceInfos(context.Context, UpdatePriceInfosParam) (PriceInfos, error) } @@ -67,6 +68,15 @@ func NewSpiderPriceCollector(sc *spider.SpiderClient) PriceCollector { } } +func (s *SpiderPriceCollector) Readyz(ctx context.Context) error { + err := s.sc.ReadyzWithContext(ctx) + if err != nil { + return err + } + + return nil +} + func (s *SpiderPriceCollector) GetPriceInfos(ctx context.Context, param UpdatePriceInfosParam) (PriceInfos, error) { connectionName := fmt.Sprintf("%s-%s", strings.ToLower(param.ProviderName), strings.ToLower(param.RegionName)) diff --git a/internal/core/cost/service.go b/internal/core/cost/service.go index 7a8d63d..3976ec2 100644 --- a/internal/core/cost/service.go +++ b/internal/core/cost/service.go @@ -25,6 +25,33 @@ func NewCostService(costRepo *CostRepository, priceCollector PriceCollector, cos } } +func (c *CostService) Readyz() error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + sqlDB, err := c.costRepo.db.DB() + if err != nil { + return err + } + + err = sqlDB.Ping() + if err != nil { + return err + } + + err = c.costCollector.Readyz(ctx) + if err != nil { + return err + } + + err = c.priceCollector.Readyz(ctx) + if err != nil { + return err + } + + return nil +} + func (c *CostService) UpdatePriceInfos(param UpdatePriceInfosParam) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() diff --git a/internal/core/load/service.go b/internal/core/load/service.go index c7f9e78..9e423fe 100644 --- a/internal/core/load/service.go +++ b/internal/core/load/service.go @@ -35,6 +35,28 @@ func NewLoadService(loadRepo *LoadRepository, client *tumblebug.TumblebugClient) } } +func (l *LoadService) Readyz() error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + sqlDB, err := l.loadRepo.db.DB() + if err != nil { + return err + } + + err = sqlDB.Ping() + if err != nil { + return err + } + + err = l.tumblebugClient.ReadyzWithContext(ctx) + if err != nil { + return err + } + + return nil +} + // InstallMonitoringAgent installs a monitoring agent on specified VMs or all VM on mci. func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationParams) ([]MonitoringAgentInstallationResult, error) { utils.LogInfo("Starting installation of monitoring agent...") diff --git a/internal/infra/outbound/spider/req.go b/internal/infra/outbound/spider/req.go index 50958d3..e5b1e47 100644 --- a/internal/infra/outbound/spider/req.go +++ b/internal/infra/outbound/spider/req.go @@ -11,7 +11,7 @@ type FilterReq struct { } type AnycallReq struct { - ConnectionName string `json:"ConnectionName"` + ConnectionName string `json:"ConnectionName"` ReqInfo ReqInfo `json:"ReqInfo"` } type ReqInfo struct { @@ -22,4 +22,4 @@ type ReqInfo struct { type KeyValue struct { Key string `json:"Key"` Value string `json:"Value"` -} \ No newline at end of file +} diff --git a/internal/infra/outbound/spider/spider.go b/internal/infra/outbound/spider/spider_client.go similarity index 77% rename from internal/infra/outbound/spider/spider.go rename to internal/infra/outbound/spider/spider_client.go index 66dac36..ba97371 100644 --- a/internal/infra/outbound/spider/spider.go +++ b/internal/infra/outbound/spider/spider_client.go @@ -54,12 +54,12 @@ func NewSpiderClient(client *http.Client) *SpiderClient { } } -func (t *SpiderClient) withUrl(endpoint string) string { +func (s *SpiderClient) withUrl(endpoint string) string { trimmedEndpoint := strings.TrimPrefix(endpoint, "/") - return fmt.Sprintf("%s/spider/%s", t.domain, trimmedEndpoint) + return fmt.Sprintf("%s/spider/%s", s.domain, trimmedEndpoint) } -func (t *SpiderClient) requestWithContext(ctx context.Context, method, url string, body []byte, header map[string]string) ([]byte, error) { +func (s *SpiderClient) requestWithContext(ctx context.Context, method, url string, body []byte, header map[string]string) ([]byte, error) { req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewBuffer(body)) if err != nil { utils.LogErrorf("Failed to create request with context: %v", err) @@ -72,14 +72,14 @@ func (t *SpiderClient) requestWithContext(ctx context.Context, method, url strin } utils.LogInfof("Sending request to client with endpoint [%s - %s]\n", method, url) - resp, err := t.client.Do(req) + resp, err := s.client.Do(req) if err != nil { utils.LogErrorf("Failed to send request: %v", err) return nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest { rb, _ := io.ReadAll(resp.Body) utils.LogErrorf("Unexpected status code: %d, response: %s", resp.StatusCode, string(rb)) @@ -104,6 +104,19 @@ func (t *SpiderClient) requestWithContext(ctx context.Context, method, url strin return rb, nil } -func (t *SpiderClient) requestWithBaseAuthWithContext(ctx context.Context, method, url string, body []byte) ([]byte, error) { - return t.requestWithContext(ctx, method, url, body, map[string]string{"Authorization": t.authHeader}) +func (s *SpiderClient) requestWithBaseAuthWithContext(ctx context.Context, method, url string, body []byte) ([]byte, error) { + return s.requestWithContext(ctx, method, url, body, map[string]string{"Authorization": s.authHeader}) +} + +func (s *SpiderClient) ReadyzWithContext(ctx context.Context) error { + + url := s.withUrl("/readyz") + _, err := s.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) + + if err != nil { + utils.LogError("error sending tumblebug readyz request:", err) + return err + } + + return nil } diff --git a/internal/infra/outbound/tumblebug/tumblebug_client.go b/internal/infra/outbound/tumblebug/tumblebug_client.go index b2e6d9c..145ded1 100644 --- a/internal/infra/outbound/tumblebug/tumblebug_client.go +++ b/internal/infra/outbound/tumblebug/tumblebug_client.go @@ -75,7 +75,7 @@ func (t *TumblebugClient) requestWithContext(ctx context.Context, method, url st } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest { rb, _ := io.ReadAll(resp.Body) log.Printf("[ERROR] Unexpected status code: %d, response: %s", resp.StatusCode, string(rb)) @@ -103,3 +103,16 @@ func (t *TumblebugClient) requestWithContext(ctx context.Context, method, url st func (t *TumblebugClient) requestWithBaseAuthWithContext(ctx context.Context, method, url string, body []byte) ([]byte, error) { return t.requestWithContext(ctx, method, url, body, map[string]string{"Authorization": t.authHeader}) } + +func (t *TumblebugClient) ReadyzWithContext(ctx context.Context) error { + + url := t.withUrl("/readyz") + _, err := t.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) + + if err != nil { + utils.LogError("error sending tumblebug readyz request:", err) + return err + } + + return nil +}