diff --git a/api/docs.go b/api/docs.go index ae2a9f3..391b2a5 100644 --- a/api/docs.go +++ b/api/docs.go @@ -517,54 +517,7 @@ const docTemplate = `{ } } }, - "/api/v1/load/monitoring/agent/install": { - "post": { - "description": "Install a monitoring agent on specific mci.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "[Monitoring Agent Management]" - ], - "summary": "Install Metrics Monitoring Agent", - "operationId": "InstallMonitoringAgent", - "parameters": [ - { - "description": "Monitoring Agent Installation Request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/app.MonitoringAgentInstallationReq" - } - } - ], - "responses": { - "200": { - "description": "Successfully installed monitoring agent", - "schema": { - "$ref": "#/definitions/app.AntResponse-load_MonitoringAgentInstallationResult" - } - }, - "400": { - "description": "Monitoring agent installation info is not correct.", - "schema": { - "$ref": "#/definitions/app.AntResponse-string" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/app.AntResponse-string" - } - } - } - } - }, - "/api/v1/load/monitoring/agents": { + "/api/v1/load/monitoring/agent": { "get": { "description": "Retrieve monitoring agent information based on specified criteria.", "consumes": [ @@ -632,7 +585,54 @@ const docTemplate = `{ } } }, - "/api/v1/load/monitoring/agents/uninstall": { + "/api/v1/load/monitoring/agent/install": { + "post": { + "description": "Install a monitoring agent on specific mci.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Monitoring Agent Management]" + ], + "summary": "Install Metrics Monitoring Agent", + "operationId": "InstallMonitoringAgent", + "parameters": [ + { + "description": "Monitoring Agent Installation Request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/app.MonitoringAgentInstallationReq" + } + } + ], + "responses": { + "200": { + "description": "Successfully installed monitoring agent", + "schema": { + "$ref": "#/definitions/app.AntResponse-load_MonitoringAgentInstallationResult" + } + }, + "400": { + "description": "Monitoring agent installation info is not correct.", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + } + } + } + }, + "/api/v1/load/monitoring/agent/uninstall": { "post": { "description": "Uninstall monitoring agents from specified VMs or all VMs in an mci.", "consumes": [ @@ -679,9 +679,9 @@ const docTemplate = `{ } } }, - "/api/v1/load/test/metrics": { + "/api/v1/load/tests/infos": { "get": { - "description": "Retrieve load test metrics based on provided parameters.", + "description": "Retrieve a list of all load test execution information with pagination support.", "consumes": [ "application/json" ], @@ -689,34 +689,84 @@ const docTemplate = `{ "application/json" ], "tags": [ - "[Load Test Result]" + "[Load Test Execution Management]" ], - "summary": "Get load test metrics", - "operationId": "GetLoadTestMetrics", + "summary": "Get All Load Test Execution Information", + "operationId": "GetAllLoadTestExecutionInfos", + "parameters": [ + { + "type": "integer", + "description": "Page number for pagination (default 1)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Number of items per page (default 10, max 10)", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved load test execution information", + "schema": { + "$ref": "#/definitions/app.AntResponse-load_GetAllLoadTestExecutionInfosResult" + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + }, + "500": { + "description": "Failed to retrieve all load test execution information", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + } + } + } + }, + "/api/v1/load/tests/infos/{loadTestKey}": { + "get": { + "description": "Retrieve the load test execution state information for a specific load test key.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Load Test Execution Management]" + ], + "summary": "Get Load Test Execution State", + "operationId": "GetLoadTestExecutionInfo", "parameters": [ { "type": "string", "description": "Load test key", "name": "loadTestKey", - "in": "query", + "in": "path", "required": true } ], "responses": { "200": { - "description": "Successfully retrieved load test metrics", + "description": "Successfully retrieved load test execution state information", "schema": { - "$ref": "#/definitions/app.AntResponse-array_load_MetricsSummary" + "$ref": "#/definitions/app.AntResponse-load_LoadTestExecutionInfoResult" } }, "400": { - "description": "Invalid request parameters", + "description": "Load test key must be set.", "schema": { "$ref": "#/definitions/app.AntResponse-string" } }, "500": { - "description": "Failed to retrieve load test metrics", + "description": "Failed to retrieve load test execution state information", "schema": { "$ref": "#/definitions/app.AntResponse-string" } @@ -724,7 +774,7 @@ const docTemplate = `{ } } }, - "/api/v1/load/test/result": { + "/api/v1/load/tests/result": { "get": { "description": "Retrieve load test result based on provided parameters.", "consumes": [ @@ -790,9 +840,9 @@ const docTemplate = `{ } } }, - "/api/v1/load/tests/infos": { + "/api/v1/load/tests/result/last": { "get": { - "description": "Retrieve a list of all load test execution information with pagination support.", + "description": "Retrieve last load test result based on provided parameters.", "consumes": [ "application/json" ], @@ -800,29 +850,59 @@ const docTemplate = `{ "application/json" ], "tags": [ - "[Load Test Execution Management]" + "[Load Test Result]" ], - "summary": "Get All Load Test Execution Information", - "operationId": "GetAllLoadTestExecutionInfos", + "summary": "Get last load test result by ns, mci, vm", + "operationId": "GetLastLoadTestResult", "parameters": [ { - "type": "integer", - "description": "Page number for pagination (default 1)", - "name": "page", - "in": "query" + "type": "string", + "description": "ns id", + "name": "nsId", + "in": "query", + "required": true }, { - "type": "integer", - "description": "Number of items per page (default 10, max 10)", - "name": "size", + "type": "string", + "description": "mci id", + "name": "mciId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "vm id", + "name": "vmId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Result format (normal or aggregate)", + "name": "format", "in": "query" } ], "responses": { "200": { - "description": "Successfully retrieved load test execution information", + "description": "Successfully retrieved load test metrics", "schema": { - "$ref": "#/definitions/app.AntResponse-load_GetAllLoadTestExecutionInfosResult" + "allOf": [ + { + "$ref": "#/definitions/app.JsonResult" + }, + { + "type": "object", + "properties": { + "[aggregate]": { + "$ref": "#/definitions/app.AntResponse-array_load_LoadTestStatistics" + }, + "[normal]": { + "$ref": "#/definitions/app.AntResponse-array_load_ResultSummary" + } + } + } + ] } }, "400": { @@ -832,7 +912,7 @@ const docTemplate = `{ } }, "500": { - "description": "Failed to retrieve all load test execution information", + "description": "Failed to retrieve load test result", "schema": { "$ref": "#/definitions/app.AntResponse-string" } @@ -840,9 +920,9 @@ const docTemplate = `{ } } }, - "/api/v1/load/tests/infos/{loadTestKey}": { + "/api/v1/load/tests/result/metrics": { "get": { - "description": "Retrieve the load test execution state information for a specific load test key.", + "description": "Retrieve load test metrics based on provided parameters.", "consumes": [ "application/json" ], @@ -850,34 +930,99 @@ const docTemplate = `{ "application/json" ], "tags": [ - "[Load Test Execution Management]" + "[Load Test Result]" ], - "summary": "Get Load Test Execution State", - "operationId": "GetLoadTestExecutionInfo", + "summary": "Get load test metrics", + "operationId": "GetLoadTestMetrics", "parameters": [ { "type": "string", "description": "Load test key", "name": "loadTestKey", - "in": "path", + "in": "query", "required": true } ], "responses": { "200": { - "description": "Successfully retrieved load test execution state information", + "description": "Successfully retrieved load test metrics", "schema": { - "$ref": "#/definitions/app.AntResponse-load_LoadTestExecutionInfoResult" + "$ref": "#/definitions/app.AntResponse-array_load_MetricsSummary" } }, "400": { - "description": "Load test key must be set.", + "description": "Invalid request parameters", "schema": { "$ref": "#/definitions/app.AntResponse-string" } }, "500": { - "description": "Failed to retrieve load test execution state information", + "description": "Failed to retrieve load test metrics", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + } + } + } + }, + "/api/v1/load/tests/result/metrics/last": { + "get": { + "description": "Retrieve last load test metrics based on provided parameters.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Load Test Result]" + ], + "summary": "Get last load test metrics by ns, mci, vm", + "operationId": "GetLastLoadTestMetrics", + "parameters": [ + { + "type": "string", + "description": "ns id", + "name": "nsId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "mci id", + "name": "mciId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "vm id", + "name": "vmId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Result format (normal for the moment)", + "name": "format", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved load test metrics", + "schema": { + "$ref": "#/definitions/app.AntResponse-array_load_MetricsSummary" + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + }, + "500": { + "description": "Failed to retrieve load test metrics", "schema": { "$ref": "#/definitions/app.AntResponse-string" } @@ -1740,6 +1885,19 @@ const docTemplate = `{ "TestFailed" ] }, + "constant.IconCode": { + "type": "string", + "enum": [ + "IC0001", + "IC0002", + "IC0003" + ], + "x-enum-varnames": [ + "Ok", + "Fail", + "Pending" + ] + }, "constant.InstallLocation": { "type": "string", "enum": [ @@ -2258,12 +2416,18 @@ const docTemplate = `{ "executionStatus": { "$ref": "#/definitions/constant.ExecutionStatus" }, + "expectedFinishAt": { + "type": "string" + }, "failureMessage": { "type": "string" }, "finishAt": { "type": "string" }, + "iconCode": { + "$ref": "#/definitions/constant.IconCode" + }, "id": { "type": "integer" }, diff --git a/api/swagger.json b/api/swagger.json index 594b3f8..f19292b 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -509,54 +509,7 @@ } } }, - "/api/v1/load/monitoring/agent/install": { - "post": { - "description": "Install a monitoring agent on specific mci.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "[Monitoring Agent Management]" - ], - "summary": "Install Metrics Monitoring Agent", - "operationId": "InstallMonitoringAgent", - "parameters": [ - { - "description": "Monitoring Agent Installation Request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/app.MonitoringAgentInstallationReq" - } - } - ], - "responses": { - "200": { - "description": "Successfully installed monitoring agent", - "schema": { - "$ref": "#/definitions/app.AntResponse-load_MonitoringAgentInstallationResult" - } - }, - "400": { - "description": "Monitoring agent installation info is not correct.", - "schema": { - "$ref": "#/definitions/app.AntResponse-string" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/app.AntResponse-string" - } - } - } - } - }, - "/api/v1/load/monitoring/agents": { + "/api/v1/load/monitoring/agent": { "get": { "description": "Retrieve monitoring agent information based on specified criteria.", "consumes": [ @@ -624,7 +577,54 @@ } } }, - "/api/v1/load/monitoring/agents/uninstall": { + "/api/v1/load/monitoring/agent/install": { + "post": { + "description": "Install a monitoring agent on specific mci.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Monitoring Agent Management]" + ], + "summary": "Install Metrics Monitoring Agent", + "operationId": "InstallMonitoringAgent", + "parameters": [ + { + "description": "Monitoring Agent Installation Request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/app.MonitoringAgentInstallationReq" + } + } + ], + "responses": { + "200": { + "description": "Successfully installed monitoring agent", + "schema": { + "$ref": "#/definitions/app.AntResponse-load_MonitoringAgentInstallationResult" + } + }, + "400": { + "description": "Monitoring agent installation info is not correct.", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + } + } + } + }, + "/api/v1/load/monitoring/agent/uninstall": { "post": { "description": "Uninstall monitoring agents from specified VMs or all VMs in an mci.", "consumes": [ @@ -671,9 +671,9 @@ } } }, - "/api/v1/load/test/metrics": { + "/api/v1/load/tests/infos": { "get": { - "description": "Retrieve load test metrics based on provided parameters.", + "description": "Retrieve a list of all load test execution information with pagination support.", "consumes": [ "application/json" ], @@ -681,34 +681,84 @@ "application/json" ], "tags": [ - "[Load Test Result]" + "[Load Test Execution Management]" ], - "summary": "Get load test metrics", - "operationId": "GetLoadTestMetrics", + "summary": "Get All Load Test Execution Information", + "operationId": "GetAllLoadTestExecutionInfos", + "parameters": [ + { + "type": "integer", + "description": "Page number for pagination (default 1)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Number of items per page (default 10, max 10)", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved load test execution information", + "schema": { + "$ref": "#/definitions/app.AntResponse-load_GetAllLoadTestExecutionInfosResult" + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + }, + "500": { + "description": "Failed to retrieve all load test execution information", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + } + } + } + }, + "/api/v1/load/tests/infos/{loadTestKey}": { + "get": { + "description": "Retrieve the load test execution state information for a specific load test key.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Load Test Execution Management]" + ], + "summary": "Get Load Test Execution State", + "operationId": "GetLoadTestExecutionInfo", "parameters": [ { "type": "string", "description": "Load test key", "name": "loadTestKey", - "in": "query", + "in": "path", "required": true } ], "responses": { "200": { - "description": "Successfully retrieved load test metrics", + "description": "Successfully retrieved load test execution state information", "schema": { - "$ref": "#/definitions/app.AntResponse-array_load_MetricsSummary" + "$ref": "#/definitions/app.AntResponse-load_LoadTestExecutionInfoResult" } }, "400": { - "description": "Invalid request parameters", + "description": "Load test key must be set.", "schema": { "$ref": "#/definitions/app.AntResponse-string" } }, "500": { - "description": "Failed to retrieve load test metrics", + "description": "Failed to retrieve load test execution state information", "schema": { "$ref": "#/definitions/app.AntResponse-string" } @@ -716,7 +766,7 @@ } } }, - "/api/v1/load/test/result": { + "/api/v1/load/tests/result": { "get": { "description": "Retrieve load test result based on provided parameters.", "consumes": [ @@ -782,9 +832,9 @@ } } }, - "/api/v1/load/tests/infos": { + "/api/v1/load/tests/result/last": { "get": { - "description": "Retrieve a list of all load test execution information with pagination support.", + "description": "Retrieve last load test result based on provided parameters.", "consumes": [ "application/json" ], @@ -792,29 +842,59 @@ "application/json" ], "tags": [ - "[Load Test Execution Management]" + "[Load Test Result]" ], - "summary": "Get All Load Test Execution Information", - "operationId": "GetAllLoadTestExecutionInfos", + "summary": "Get last load test result by ns, mci, vm", + "operationId": "GetLastLoadTestResult", "parameters": [ { - "type": "integer", - "description": "Page number for pagination (default 1)", - "name": "page", - "in": "query" + "type": "string", + "description": "ns id", + "name": "nsId", + "in": "query", + "required": true }, { - "type": "integer", - "description": "Number of items per page (default 10, max 10)", - "name": "size", + "type": "string", + "description": "mci id", + "name": "mciId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "vm id", + "name": "vmId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Result format (normal or aggregate)", + "name": "format", "in": "query" } ], "responses": { "200": { - "description": "Successfully retrieved load test execution information", + "description": "Successfully retrieved load test metrics", "schema": { - "$ref": "#/definitions/app.AntResponse-load_GetAllLoadTestExecutionInfosResult" + "allOf": [ + { + "$ref": "#/definitions/app.JsonResult" + }, + { + "type": "object", + "properties": { + "[aggregate]": { + "$ref": "#/definitions/app.AntResponse-array_load_LoadTestStatistics" + }, + "[normal]": { + "$ref": "#/definitions/app.AntResponse-array_load_ResultSummary" + } + } + } + ] } }, "400": { @@ -824,7 +904,7 @@ } }, "500": { - "description": "Failed to retrieve all load test execution information", + "description": "Failed to retrieve load test result", "schema": { "$ref": "#/definitions/app.AntResponse-string" } @@ -832,9 +912,9 @@ } } }, - "/api/v1/load/tests/infos/{loadTestKey}": { + "/api/v1/load/tests/result/metrics": { "get": { - "description": "Retrieve the load test execution state information for a specific load test key.", + "description": "Retrieve load test metrics based on provided parameters.", "consumes": [ "application/json" ], @@ -842,34 +922,99 @@ "application/json" ], "tags": [ - "[Load Test Execution Management]" + "[Load Test Result]" ], - "summary": "Get Load Test Execution State", - "operationId": "GetLoadTestExecutionInfo", + "summary": "Get load test metrics", + "operationId": "GetLoadTestMetrics", "parameters": [ { "type": "string", "description": "Load test key", "name": "loadTestKey", - "in": "path", + "in": "query", "required": true } ], "responses": { "200": { - "description": "Successfully retrieved load test execution state information", + "description": "Successfully retrieved load test metrics", "schema": { - "$ref": "#/definitions/app.AntResponse-load_LoadTestExecutionInfoResult" + "$ref": "#/definitions/app.AntResponse-array_load_MetricsSummary" } }, "400": { - "description": "Load test key must be set.", + "description": "Invalid request parameters", "schema": { "$ref": "#/definitions/app.AntResponse-string" } }, "500": { - "description": "Failed to retrieve load test execution state information", + "description": "Failed to retrieve load test metrics", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + } + } + } + }, + "/api/v1/load/tests/result/metrics/last": { + "get": { + "description": "Retrieve last load test metrics based on provided parameters.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Load Test Result]" + ], + "summary": "Get last load test metrics by ns, mci, vm", + "operationId": "GetLastLoadTestMetrics", + "parameters": [ + { + "type": "string", + "description": "ns id", + "name": "nsId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "mci id", + "name": "mciId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "vm id", + "name": "vmId", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Result format (normal for the moment)", + "name": "format", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved load test metrics", + "schema": { + "$ref": "#/definitions/app.AntResponse-array_load_MetricsSummary" + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "$ref": "#/definitions/app.AntResponse-string" + } + }, + "500": { + "description": "Failed to retrieve load test metrics", "schema": { "$ref": "#/definitions/app.AntResponse-string" } @@ -1732,6 +1877,19 @@ "TestFailed" ] }, + "constant.IconCode": { + "type": "string", + "enum": [ + "IC0001", + "IC0002", + "IC0003" + ], + "x-enum-varnames": [ + "Ok", + "Fail", + "Pending" + ] + }, "constant.InstallLocation": { "type": "string", "enum": [ @@ -2250,12 +2408,18 @@ "executionStatus": { "$ref": "#/definitions/constant.ExecutionStatus" }, + "expectedFinishAt": { + "type": "string" + }, "failureMessage": { "type": "string" }, "finishAt": { "type": "string" }, + "iconCode": { + "$ref": "#/definitions/constant.IconCode" + }, "id": { "type": "integer" }, diff --git a/api/swagger.yaml b/api/swagger.yaml index d22e036..93b05d7 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -369,6 +369,16 @@ definitions: - OnFetching - Successed - TestFailed + constant.IconCode: + enum: + - IC0001 + - IC0002 + - IC0003 + type: string + x-enum-varnames: + - Ok + - Fail + - Pending constant.InstallLocation: enum: - local @@ -713,10 +723,14 @@ definitions: type: string executionStatus: $ref: '#/definitions/constant.ExecutionStatus' + expectedFinishAt: + type: string failureMessage: type: string finishAt: type: string + iconCode: + $ref: '#/definitions/constant.IconCode' id: type: integer loadGeneratorInstallInfo: @@ -1195,38 +1209,7 @@ paths: summary: Uninstall Load Generator tags: - '[Load Generator Management]' - /api/v1/load/monitoring/agent/install: - post: - consumes: - - application/json - description: Install a monitoring agent on specific mci. - operationId: InstallMonitoringAgent - parameters: - - description: Monitoring Agent Installation Request - in: body - name: body - required: true - schema: - $ref: '#/definitions/app.MonitoringAgentInstallationReq' - produces: - - application/json - responses: - "200": - description: Successfully installed monitoring agent - schema: - $ref: '#/definitions/app.AntResponse-load_MonitoringAgentInstallationResult' - "400": - description: Monitoring agent installation info is not correct. - schema: - $ref: '#/definitions/app.AntResponse-string' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/app.AntResponse-string' - summary: Install Metrics Monitoring Agent - tags: - - '[Monitoring Agent Management]' - /api/v1/load/monitoring/agents: + /api/v1/load/monitoring/agent: get: consumes: - application/json @@ -1271,7 +1254,38 @@ paths: summary: Retrieve Monitoring Agent Information tags: - '[Monitoring Agent Management]' - /api/v1/load/monitoring/agents/uninstall: + /api/v1/load/monitoring/agent/install: + post: + consumes: + - application/json + description: Install a monitoring agent on specific mci. + operationId: InstallMonitoringAgent + parameters: + - description: Monitoring Agent Installation Request + in: body + name: body + required: true + schema: + $ref: '#/definitions/app.MonitoringAgentInstallationReq' + produces: + - application/json + responses: + "200": + description: Successfully installed monitoring agent + schema: + $ref: '#/definitions/app.AntResponse-load_MonitoringAgentInstallationResult' + "400": + description: Monitoring agent installation info is not correct. + schema: + $ref: '#/definitions/app.AntResponse-string' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/app.AntResponse-string' + summary: Install Metrics Monitoring Agent + tags: + - '[Monitoring Agent Management]' + /api/v1/load/monitoring/agent/uninstall: post: consumes: - application/json @@ -1303,15 +1317,50 @@ paths: summary: Uninstall Monitoring Agents tags: - '[Monitoring Agent Management]' - /api/v1/load/test/metrics: + /api/v1/load/tests/infos: get: consumes: - application/json - description: Retrieve load test metrics based on provided parameters. - operationId: GetLoadTestMetrics + description: Retrieve a list of all load test execution information with pagination + support. + operationId: GetAllLoadTestExecutionInfos parameters: - - description: Load test key + - description: Page number for pagination (default 1) in: query + name: page + type: integer + - description: Number of items per page (default 10, max 10) + in: query + name: size + type: integer + produces: + - application/json + responses: + "200": + description: Successfully retrieved load test execution information + schema: + $ref: '#/definitions/app.AntResponse-load_GetAllLoadTestExecutionInfosResult' + "400": + description: Invalid request parameters + schema: + $ref: '#/definitions/app.AntResponse-string' + "500": + description: Failed to retrieve all load test execution information + schema: + $ref: '#/definitions/app.AntResponse-string' + summary: Get All Load Test Execution Information + tags: + - '[Load Test Execution Management]' + /api/v1/load/tests/infos/{loadTestKey}: + get: + consumes: + - application/json + description: Retrieve the load test execution state information for a specific + load test key. + operationId: GetLoadTestExecutionInfo + parameters: + - description: Load test key + in: path name: loadTestKey required: true type: string @@ -1319,21 +1368,21 @@ paths: - application/json responses: "200": - description: Successfully retrieved load test metrics + description: Successfully retrieved load test execution state information schema: - $ref: '#/definitions/app.AntResponse-array_load_MetricsSummary' + $ref: '#/definitions/app.AntResponse-load_LoadTestExecutionInfoResult' "400": - description: Invalid request parameters + description: Load test key must be set. schema: $ref: '#/definitions/app.AntResponse-string' "500": - description: Failed to retrieve load test metrics + description: Failed to retrieve load test execution state information schema: $ref: '#/definitions/app.AntResponse-string' - summary: Get load test metrics + summary: Get Load Test Execution State tags: - - '[Load Test Result]' - /api/v1/load/test/result: + - '[Load Test Execution Management]' + /api/v1/load/tests/result: get: consumes: - application/json @@ -1374,50 +1423,66 @@ paths: summary: Get load test result tags: - '[Load Test Result]' - /api/v1/load/tests/infos: + /api/v1/load/tests/result/last: get: consumes: - application/json - description: Retrieve a list of all load test execution information with pagination - support. - operationId: GetAllLoadTestExecutionInfos + description: Retrieve last load test result based on provided parameters. + operationId: GetLastLoadTestResult parameters: - - description: Page number for pagination (default 1) + - description: ns id in: query - name: page - type: integer - - description: Number of items per page (default 10, max 10) + name: nsId + required: true + type: string + - description: mci id in: query - name: size - type: integer + name: mciId + required: true + type: string + - description: vm id + in: query + name: vmId + required: true + type: string + - description: Result format (normal or aggregate) + in: query + name: format + type: string produces: - application/json responses: "200": - description: Successfully retrieved load test execution information + description: Successfully retrieved load test metrics schema: - $ref: '#/definitions/app.AntResponse-load_GetAllLoadTestExecutionInfosResult' + allOf: + - $ref: '#/definitions/app.JsonResult' + - properties: + '[aggregate]': + $ref: '#/definitions/app.AntResponse-array_load_LoadTestStatistics' + '[normal]': + $ref: '#/definitions/app.AntResponse-array_load_ResultSummary' + type: object "400": description: Invalid request parameters schema: $ref: '#/definitions/app.AntResponse-string' "500": - description: Failed to retrieve all load test execution information + description: Failed to retrieve load test result schema: $ref: '#/definitions/app.AntResponse-string' - summary: Get All Load Test Execution Information + summary: Get last load test result by ns, mci, vm tags: - - '[Load Test Execution Management]' - /api/v1/load/tests/infos/{loadTestKey}: + - '[Load Test Result]' + /api/v1/load/tests/result/metrics: get: consumes: - application/json - description: Retrieve the load test execution state information for a specific - load test key. - operationId: GetLoadTestExecutionInfo + description: Retrieve load test metrics based on provided parameters. + operationId: GetLoadTestMetrics parameters: - description: Load test key - in: path + in: query name: loadTestKey required: true type: string @@ -1425,20 +1490,64 @@ paths: - application/json responses: "200": - description: Successfully retrieved load test execution state information + description: Successfully retrieved load test metrics schema: - $ref: '#/definitions/app.AntResponse-load_LoadTestExecutionInfoResult' + $ref: '#/definitions/app.AntResponse-array_load_MetricsSummary' "400": - description: Load test key must be set. + description: Invalid request parameters schema: $ref: '#/definitions/app.AntResponse-string' "500": - description: Failed to retrieve load test execution state information + description: Failed to retrieve load test metrics schema: $ref: '#/definitions/app.AntResponse-string' - summary: Get Load Test Execution State + summary: Get load test metrics tags: - - '[Load Test Execution Management]' + - '[Load Test Result]' + /api/v1/load/tests/result/metrics/last: + get: + consumes: + - application/json + description: Retrieve last load test metrics based on provided parameters. + operationId: GetLastLoadTestMetrics + parameters: + - description: ns id + in: query + name: nsId + required: true + type: string + - description: mci id + in: query + name: mciId + required: true + type: string + - description: vm id + in: query + name: vmId + required: true + type: string + - description: Result format (normal for the moment) + in: query + name: format + type: string + produces: + - application/json + responses: + "200": + description: Successfully retrieved load test metrics + schema: + $ref: '#/definitions/app.AntResponse-array_load_MetricsSummary' + "400": + description: Invalid request parameters + schema: + $ref: '#/definitions/app.AntResponse-string' + "500": + description: Failed to retrieve load test metrics + schema: + $ref: '#/definitions/app.AntResponse-string' + summary: Get last load test metrics by ns, mci, vm + tags: + - '[Load Test Result]' /api/v1/load/tests/run: post: consumes: diff --git a/internal/app/estimate_cost_handler.go b/internal/app/estimate_cost_handler.go index 0b5846e..d1aa559 100644 --- a/internal/app/estimate_cost_handler.go +++ b/internal/app/estimate_cost_handler.go @@ -9,8 +9,8 @@ import ( "github.com/cloud-barista/cm-ant/internal/config" "github.com/cloud-barista/cm-ant/internal/core/common/constant" "github.com/cloud-barista/cm-ant/internal/core/cost" - "github.com/cloud-barista/cm-ant/internal/utils" "github.com/labstack/echo/v4" + "github.com/rs/zerolog/log" ) // @Id UpdateAndGetEstimateCost @@ -74,12 +74,12 @@ func (a *AntServer) updateAndGetEstimateCost(c echo.Context) error { splitedCommonImage := strings.Split(ci, delim) if len(splitedCommonSpec) != 3 { - utils.LogErrorf("common spec format is not correct; image: %s; spec: %s", ci, cs) + log.Error().Msgf("common spec format is not correct; image: %s; spec: %s", ci, cs) return errorResponseJson(http.StatusBadRequest, fmt.Sprintf("common spec format is not correct; image: %s; spec: %s", ci, cs)) } if len(splitedCommonImage) == 3 && (splitedCommonImage[0] != splitedCommonSpec[0] || splitedCommonImage[1] != splitedCommonSpec[1]) { - utils.LogErrorf("common image and spec recommendation is wrong; image: %s; spec: %s", ci, cs) + log.Error().Msgf("common image and spec recommendation is wrong; image: %s; spec: %s", ci, cs) return errorResponseJson(http.StatusBadRequest, fmt.Sprintf("common image and spec recommendation is wrong; image: %s; spec: %s", ci, cs)) } diff --git a/internal/app/evaluate_performance_handler.go b/internal/app/evaluate_performance_handler.go index 6bcbd67..16c8add 100644 --- a/internal/app/evaluate_performance_handler.go +++ b/internal/app/evaluate_performance_handler.go @@ -8,7 +8,6 @@ import ( "github.com/cloud-barista/cm-ant/internal/core/common/constant" "github.com/cloud-barista/cm-ant/internal/core/load" - "github.com/cloud-barista/cm-ant/internal/utils" "github.com/google/uuid" "github.com/labstack/echo/v4" "github.com/rs/zerolog/log" @@ -74,20 +73,20 @@ func (s *AntServer) getAllLoadGeneratorInstallInfo(c echo.Context) error { func (s *AntServer) installLoadGenerator(c echo.Context) error { var req InstallLoadGeneratorReq - utils.LogInfo("Received request to install load generator") + log.Info().Msg("Received request to install load generator") if err := c.Bind(&req); err != nil { - utils.LogError("Failed to bind request:", err) + log.Error().Msgf("Failed to bind request:", err) return errorResponseJson(http.StatusBadRequest, "load generator installation info is not correct.") } if req.InstallLocation == "" || (req.InstallLocation != constant.Remote && req.InstallLocation != constant.Local) { - utils.LogError("Invalid install location:", req.InstallLocation) + log.Error().Msgf("Invalid install location:", req.InstallLocation) return errorResponseJson(http.StatusBadRequest, "available install locations are remote or local.") } - utils.LogInfo("Calling service layer to install load generator") + log.Info().Msgf("Calling service layer to install load generator") // call service layer install load generator param := load.InstallLoadGeneratorParam{ @@ -97,11 +96,11 @@ func (s *AntServer) installLoadGenerator(c echo.Context) error { result, err := s.services.loadService.InstallLoadGenerator(param) if err != nil { - utils.LogError("Error installing load generator:", err) + log.Error().Msgf("Error installing load generator:", err) return errorResponseJson(http.StatusBadRequest, err.Error()) } - utils.LogInfo("Load generator installed successfully") + log.Info().Msg("Load generator installed successfully") return successResponseJson( c, @@ -183,24 +182,24 @@ func (s *AntServer) runLoadTest(c echo.Context) error { req.TestName = uuid.New().String() } - if _, err := strconv.Atoi(strings.TrimSpace(req.VirtualUsers)); err != nil { + if v, err := strconv.Atoi(strings.TrimSpace(req.VirtualUsers)); err != nil && (v < 1 || v > 100) { log.Error().Msgf("virtual user count is invalid") - return errorResponseJson(http.StatusBadRequest, "virtual user is not correct. check and retry.") + return errorResponseJson(http.StatusBadRequest, "virtual user is not correct. the range must be in 1 to 100") } - if _, err := strconv.Atoi(strings.TrimSpace(req.Duration)); err != nil { + if v, err := strconv.Atoi(strings.TrimSpace(req.Duration)); err != nil && (v < 1 || v > 300) { log.Error().Msgf("duration is invalid") - return errorResponseJson(http.StatusBadRequest, "duration is not correct. check and retry.") + return errorResponseJson(http.StatusBadRequest, "duration is not correct. the range must be in 1 to 300") } - if _, err := strconv.Atoi(strings.TrimSpace(req.RampUpTime)); err != nil { + if v, err := strconv.Atoi(strings.TrimSpace(req.RampUpTime)); err != nil && (v < 1 || v > 60) { log.Error().Msgf("ramp up time is invalid") - return errorResponseJson(http.StatusBadRequest, "ramp up time is not correct. check and retry.") + return errorResponseJson(http.StatusBadRequest, "ramp up time is not correct. the range must be in 1 to 60") } - if _, err := strconv.Atoi(strings.TrimSpace(req.RampUpSteps)); err != nil { + if v, err := strconv.Atoi(strings.TrimSpace(req.RampUpSteps)); err != nil && (v < 1 || v > 20) { log.Error().Msgf("ramp up steps is invalid") - return errorResponseJson(http.StatusBadRequest, "ramp up steps is not correct. check and retry.") + return errorResponseJson(http.StatusBadRequest, "ramp up steps is not correct. the range must be in 1 to 20") } if len(req.HttpReqs) == 0 { @@ -329,7 +328,7 @@ func (s *AntServer) stopLoadTest(c echo.Context) error { // @Success 200 {object} app.JsonResult{[normal]=app.AntResponse[[]load.ResultSummary],[aggregate]=app.AntResponse[[]load.LoadTestStatistics]} "Successfully retrieved load test metrics" // @Failure 400 {object} app.AntResponse[string] "Invalid request parameters" // @Failure 500 {object} app.AntResponse[string] "Failed to retrieve load test result" -// @Router /api/v1/load/test/result [get] +// @Router /api/v1/load/tests/result [get] func (s *AntServer) getLoadTestResult(c echo.Context) error { var req GetLoadTestResultReq if err := c.Bind(&req); err != nil { @@ -371,7 +370,7 @@ func (s *AntServer) getLoadTestResult(c echo.Context) error { // @success 200 {object} app.AntResponse[[]load.MetricsSummary] "Successfully retrieved load test metrics" // @Failure 400 {object} app.AntResponse[string] "Invalid request parameters" // @Failure 500 {object} app.AntResponse[string] "Failed to retrieve load test metrics" -// @Router /api/v1/load/test/metrics [get] +// @Router /api/v1/load/tests/result/metrics [get] func (s *AntServer) getLoadTestMetrics(c echo.Context) error { var req GetLoadTestResultReq if err := c.Bind(&req); err != nil { @@ -636,7 +635,7 @@ func (s *AntServer) installMonitoringAgent(c echo.Context) error { // @Success 200 {object} app.AntResponse[load.GetAllMonitoringAgentInfoResult] "Successfully retrieved monitoring agent information" // @Failure 400 {object} app.AntResponse[string] "Invalid request parameters" // @Failure 500 {object} app.AntResponse[string] "Internal Server Error" -// @Router /api/v1/load/monitoring/agents [get] +// @Router /api/v1/load/monitoring/agent [get] func (s *AntServer) getAllMonitoringAgentInfos(c echo.Context) error { var req GetAllMonitoringAgentInfosReq if err := c.Bind(&req); err != nil { @@ -677,7 +676,7 @@ func (s *AntServer) getAllMonitoringAgentInfos(c echo.Context) error { // @Success 200 {object} app.AntResponse[int64] "Number of affected results" // @Failure 400 {object} app.AntResponse[string] "Invalid request parameters" // @Failure 500 {object} app.AntResponse[string] "Internal Server Error" -// @Router /api/v1/load/monitoring/agents/uninstall [post] +// @Router /api/v1/load/monitoring/agent/uninstall [post] func (s *AntServer) uninstallMonitoringAgent(c echo.Context) error { var req MonitoringAgentInstallationReq @@ -703,3 +702,91 @@ func (s *AntServer) uninstallMonitoringAgent(c echo.Context) error { affectedResults, ) } + +// getLastLoadTestResult handler function that retrieves a specific load test result. +// @Id GetLastLoadTestResult +// @Summary Get last load test result by ns, mci, vm +// @Description Retrieve last load test result based on provided parameters. +// @Tags [Load Test Result] +// @Accept json +// @Produce json +// @Param nsId query string true "ns id" +// @Param mciId query string true "mci id" +// @Param vmId query string true "vm id" +// @Param format query string false "Result format (normal or aggregate)" +// @Success 200 {object} app.JsonResult{[normal]=app.AntResponse[[]load.ResultSummary],[aggregate]=app.AntResponse[[]load.LoadTestStatistics]} "Successfully retrieved load test metrics" +// @Failure 400 {object} app.AntResponse[string] "Invalid request parameters" +// @Failure 500 {object} app.AntResponse[string] "Failed to retrieve load test result" +// @Router /api/v1/load/tests/result/last [get] +func (s *AntServer) getLastLoadTestResult(c echo.Context) error { + var req GetLastLoadTestResultReq + if err := c.Bind(&req); err != nil { + return errorResponseJson(http.StatusBadRequest, "Invalid request parameters") + } + + if strings.TrimSpace(req.NsId) == "" || strings.TrimSpace(req.MciId) == "" || strings.TrimSpace(req.VmId) == "" { + return errorResponseJson(http.StatusBadRequest, "pass correct nsId / mciId / vmId") + } + + if req.Format == "" { + req.Format = constant.Normal + } else if req.Format != constant.Normal && req.Format != constant.Aggregate { + req.Format = constant.Normal + } + + arg := load.GetLastLoadTestResultParam{ + NsId: req.NsId, + MciId: req.MciId, + VmId: req.VmId, + Format: req.Format, + } + + result, err := s.services.loadService.GetLastLoadTestResult(arg) + + if err != nil { + return errorResponseJson(http.StatusInternalServerError, "Failed to retrieve load test result") + } + + return successResponseJson(c, "Successfully retrieved load test result", result) +} + +// getLastLoadTestMetrics handler function that retrieves metrics for a specific load test. +// @Id GetLastLoadTestMetrics +// @Summary Get last load test metrics by ns, mci, vm +// @Description Retrieve last load test metrics based on provided parameters. +// @Tags [Load Test Result] +// @Accept json +// @Produce json +// @Param nsId query string true "ns id" +// @Param mciId query string true "mci id" +// @Param vmId query string true "vm id" +// @Param format query string false "Result format (normal for the moment)" +// @success 200 {object} app.AntResponse[[]load.MetricsSummary] "Successfully retrieved load test metrics" +// @Failure 400 {object} app.AntResponse[string] "Invalid request parameters" +// @Failure 500 {object} app.AntResponse[string] "Failed to retrieve load test metrics" +// @Router /api/v1/load/tests/result/metrics/last [get] +func (s *AntServer) getLastLoadTestMetrics(c echo.Context) error { + var req GetLastLoadTestResultReq + if err := c.Bind(&req); err != nil { + return errorResponseJson(http.StatusBadRequest, "Invalid request parameters") + } + + if strings.TrimSpace(req.NsId) == "" || strings.TrimSpace(req.MciId) == "" || strings.TrimSpace(req.VmId) == "" { + return errorResponseJson(http.StatusBadRequest, "pass correct nsId / mciId / vmId") + } + + arg := load.GetLastLoadTestResultParam{ + NsId: req.NsId, + MciId: req.MciId, + VmId: req.VmId, + Format: constant.Normal, + } + + result, err := s.services.loadService.GetLastLoadTestMetrics(arg) + + if err != nil { + return errorResponseJson(http.StatusInternalServerError, "Failed to retrieve load test metrics") + } + + return successResponseJson(c, "Successfully retrieved load test metrics", result) +} diff --git a/internal/app/evaluate_performance_req.go b/internal/app/evaluate_performance_req.go index 69c129e..20d9094 100644 --- a/internal/app/evaluate_performance_req.go +++ b/internal/app/evaluate_performance_req.go @@ -90,3 +90,10 @@ type GetLoadTestResultReq struct { LoadTestKey string `query:"loadTestKey"` Format constant.ResultFormat `query:"format"` } + +type GetLastLoadTestResultReq struct { + NsId string `query:"nsId"` + MciId string `query:"mciId"` + VmId string `query:"vmId"` + Format constant.ResultFormat `query:"format"` +} diff --git a/internal/app/middlewares.go b/internal/app/middlewares.go index a9f157c..8b2ed07 100644 --- a/internal/app/middlewares.go +++ b/internal/app/middlewares.go @@ -9,7 +9,6 @@ import ( "github.com/labstack/echo/v4/middleware" - "github.com/cloud-barista/cm-ant/internal/utils" "github.com/labstack/echo/v4" "github.com/rs/zerolog/log" ) @@ -34,7 +33,7 @@ func setMiddleware(e *echo.Echo) { Skipper: middleware.DefaultSkipper, ErrorMessage: "request timeout", OnTimeoutRouteErrorHandler: func(err error, c echo.Context) { - utils.LogInfo(c.Path()) + log.Info().Msg(c.Path()) }, Timeout: 3000 * time.Second, }, diff --git a/internal/app/router.go b/internal/app/router.go index 888a855..099bed5 100644 --- a/internal/app/router.go +++ b/internal/app/router.go @@ -54,6 +54,8 @@ func (server *AntServer) InitRouter() error { // load test result loadTestRouter.GET("/result", server.getLoadTestResult) loadTestRouter.GET("/result/metrics", server.getLoadTestMetrics) + loadTestRouter.GET("/result/last", server.getLastLoadTestResult) + loadTestRouter.GET("/result/metrics/last", server.getLastLoadTestMetrics) } } } diff --git a/internal/core/common/constant/constant.go b/internal/core/common/constant/constant.go index a72aa24..75d98bf 100644 --- a/internal/core/common/constant/constant.go +++ b/internal/core/common/constant/constant.go @@ -119,3 +119,10 @@ const ( Asc OrderType = "asc" Desc OrderType = "desc" ) + +type IconCode string +const ( + Ok IconCode = "IC0001" + Fail IconCode = "IC0002" + Pending IconCode = "IC0003" +) diff --git a/internal/core/cost/cost_collector.go b/internal/core/cost/cost_collector.go index c74c070..c1ec170 100644 --- a/internal/core/cost/cost_collector.go +++ b/internal/core/cost/cost_collector.go @@ -13,6 +13,7 @@ import ( "github.com/cloud-barista/cm-ant/internal/infra/outbound/spider" "github.com/cloud-barista/cm-ant/internal/infra/outbound/tumblebug" "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) type CostCollector interface { @@ -136,7 +137,7 @@ func (a *AwsCostExplorerBaristaCostCollector) GetCostInfos(ctx context.Context, serviceFilterValue, resourceIdFilterValue, err := a.generateFilterValue(param.CostResources, param.AwsAdditionalInfo) if err != nil { - utils.LogError("parsing service and resource id for filtering cost explorer value") + log.Error().Msgf("parsing service and resource id for filtering cost explorer value") return nil, err } @@ -216,33 +217,33 @@ func (a *AwsCostExplorerBaristaCostCollector) GetCostInfos(ctx context.Context, if err != nil { if errors.Is(err, spider.ErrSpiderCostResultEmpty) { - utils.LogError("error from spider: ", err) + log.Error().Msgf("error from spider: ", err) return nil, ErrCostResultEmpty } return nil, err } if res == nil || res.ResultsByTime == nil || len(res.ResultsByTime) == 0 { - utils.LogError("cost result is empty: ") + log.Error().Msgf("cost result is empty: ") return nil, ErrCostResultEmpty } var costInfos = make([]EstimateForecastCostInfo, 0) for _, result := range res.ResultsByTime { if result.Groups == nil { - utils.LogError("groups is nil; it must not be nil") + log.Error().Msgf("groups is nil; it must not be nil") return nil, ErrCostResultFormatInvalid } if result.TimePeriod == nil || result.TimePeriod.Start == nil || result.TimePeriod.End == nil { - utils.LogError("time period is nil; it must not be nil") + log.Error().Msgf("time period is nil; it must not be nil") return nil, ErrCostResultFormatInvalid } for _, group := range result.Groups { if group == nil { - utils.LogError("sinble group is nil; it must not be nil") + log.Error().Msgf("sinble group is nil; it must not be nil") continue } @@ -250,17 +251,17 @@ func (a *AwsCostExplorerBaristaCostCollector) GetCostInfos(ctx context.Context, awsService := constant.AwsService(category) resourceType, ok := serviceToResourceType[awsService] if !ok { - utils.LogErrorf("service : %s does not exist; category: %s", awsService, category) + log.Error().Msgf("service : %s does not exist; category: %s", awsService, category) continue } mt, ok := group.Metrics[metrics] if !ok { - utils.LogError("matric value does not exist:", metrics) + log.Error().Msgf("matric value does not exist:", metrics) continue } cost, err := strconv.ParseFloat(utils.NilSafeStr(mt.Amount), 64) if err != nil { - utils.LogError("cost parsing error:", mt.Amount) + log.Error().Msgf("cost parsing error:", mt.Amount) continue } unit := utils.NilSafeStr(mt.Unit) @@ -274,13 +275,13 @@ func (a *AwsCostExplorerBaristaCostCollector) GetCostInfos(ctx context.Context, startDate, err := time.Parse(time.RFC3339, utils.NilSafeStr(result.TimePeriod.Start)) if err != nil { - utils.LogError("start date parsing error:", result.TimePeriod.Start) + log.Error().Msgf("start date parsing error:", result.TimePeriod.Start) continue } endDate, err := time.Parse(time.RFC3339, utils.NilSafeStr(result.TimePeriod.End)) if err != nil { - utils.LogError("end date parsing error to ") + log.Error().Msgf("end date parsing error to ") continue } @@ -328,7 +329,7 @@ func (a *AwsCostExplorerBaristaCostCollector) UpdateEstimateForecastCost(ctx con mci, err := a.tc.GetMciWithContext(ctx, param.NsId, param.MciId) if err != nil { - utils.LogError("error while get mci from tumblebug; ", err) + log.Error().Msgf("error while get mci from tumblebug; ", err) return res, err } @@ -353,7 +354,7 @@ func (a *AwsCostExplorerBaristaCostCollector) UpdateEstimateForecastCost(ctx con pn := mci.ConnectionConfig.ProviderName if pn == "" || !strings.EqualFold(strings.ToLower(pn), "aws") { - utils.LogWarnf("CSP: %s, does not support yet", pn) + log.Warn().Msgf("CSP: %s, does not support yet", pn) continue } @@ -376,7 +377,7 @@ func (a *AwsCostExplorerBaristaCostCollector) UpdateEstimateForecastCost(ctx con infos, err := a.GetCostInfos(ctx, arg) if err != nil { - utils.LogError("error while get cost info from spider;", err) + log.Error().Msgf("error while get cost info from spider;", err) return res, fmt.Errorf("error from get cost infos +%w", err) } diff --git a/internal/core/cost/price_collector.go b/internal/core/cost/price_collector.go index 6ca512e..5547a9a 100644 --- a/internal/core/cost/price_collector.go +++ b/internal/core/cost/price_collector.go @@ -12,7 +12,7 @@ import ( "github.com/cloud-barista/cm-ant/internal/core/common/constant" "github.com/cloud-barista/cm-ant/internal/infra/outbound/spider" - "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) type PriceCollector interface { @@ -137,23 +137,23 @@ func (s *SpiderPriceCollector) FetchPriceInfos(ctx context.Context, param Recomm currency = s.parseCurrency(policy.Currency) convertedPrice, err := strconv.ParseFloat(policy.Price, 64) if err != nil { - utils.LogWarnf("not allowed for error; %s", err) + log.Warn().Msgf("not allowed for error; %s", err) continue } if convertedPrice == float64(0) { - utils.LogWarn("not allowed for empty price") + log.Warn().Msg("not allowed for empty price") continue } price = s.naChecker(policy.Price) if price == "" { - utils.LogWarn("not allowed for empty price") + log.Warn().Msg("not allowed for empty price") continue } if strings.Contains(strings.ToLower(priceDescription), "dedicated") { - utils.LogWarnf("not allowed for dedicated instance hour; %s", priceDescription) + log.Warn().Msgf("not allowed for dedicated instance hour; %s", priceDescription) continue } @@ -259,7 +259,7 @@ func (s *SpiderPriceCollector) splitMemory(input string) (string, constant.Memor number, err := strconv.ParseFloat(strings.TrimSpace(numberPart), 64) if err != nil { - utils.LogErrorf("error while split memory : %s", err.Error()) + log.Error().Msgf("error while split memory : %s", err.Error()) return "", "" } diff --git a/internal/core/cost/service.go b/internal/core/cost/service.go index 8170b72..e9adb91 100644 --- a/internal/core/cost/service.go +++ b/internal/core/cost/service.go @@ -10,7 +10,6 @@ import ( "time" "github.com/cloud-barista/cm-ant/internal/core/common/constant" - "github.com/cloud-barista/cm-ant/internal/utils" "github.com/rs/zerolog/log" ) @@ -299,14 +298,14 @@ func (c *CostService) UpdateEstimateForecastCost(param UpdateEstimateForecastCos for _, costInfo := range r { u, i, err := c.costRepo.UpsertCostInfo(ctx, costInfo) if err != nil { - utils.LogErrorf("upsert error: %+v", costInfo) + log.Error().Msgf("upsert error: %+v", costInfo) } updatedCount += u insertedCount += i } - utils.LogInfof("updated count: %d; inserted count : %d", updatedCount, insertedCount) + log.Info().Msgf("updated count: %d; inserted count : %d", updatedCount, insertedCount) updateEstimateForecastCostInfoResult.UpdatedDataCount = updatedCount updateEstimateForecastCostInfoResult.InsertedDataCount = insertedCount @@ -356,13 +355,13 @@ func (c *CostService) UpdateEstimateForecastCostRaw(param UpdateEstimateForecast for _, costInfo := range r { u, i, err := c.costRepo.UpsertCostInfo(ctx, costInfo) if err != nil { - utils.LogErrorf("upsert error: %+v", costInfo) + log.Error().Msgf("upsert error: %+v", costInfo) } updatedCount += u insertedCount += i } - utils.LogInfof("updated count: %d; inserted count : %d", updatedCount, insertedCount) + log.Info().Msgf("updated count: %d; inserted count : %d", updatedCount, insertedCount) updateCostInfoResult.UpdatedDataCount = updatedCount updateCostInfoResult.InsertedDataCount = insertedCount diff --git a/internal/core/load/dtos.go b/internal/core/load/dtos.go index 30b67af..3832d6b 100644 --- a/internal/core/load/dtos.go +++ b/internal/core/load/dtos.go @@ -149,6 +149,8 @@ type LoadTestExecutionStateResult struct { ExecutionStatus constant.ExecutionStatus `json:"executionStatus,omitempty"` StartAt time.Time `json:"startAt,omitempty"` FinishAt *time.Time `json:"finishAt,omitempty"` + ExpectedFinishAt time.Time `json:"expectedFinishAt,omitempty"` + IconCode constant.IconCode `json:"iconCode"` TotalExpectedExcutionSecond uint64 `json:"totalExpectedExecutionSecond,omitempty"` FailureMessage string `json:"failureMessage,omitempty"` CompileDuration string `json:"compileDuration,omitempty"` @@ -262,3 +264,10 @@ type GetLoadTestResultParam struct { LoadTestKey string Format constant.ResultFormat } + +type GetLastLoadTestResultParam struct { + NsId string + MciId string + VmId string + Format constant.ResultFormat +} diff --git a/internal/core/load/jmx_parser.go b/internal/core/load/jmx_parser.go index c161ac1..d55a914 100644 --- a/internal/core/load/jmx_parser.go +++ b/internal/core/load/jmx_parser.go @@ -5,12 +5,12 @@ import ( "fmt" "html" "io" - "log" "net/url" "strings" "text/template" "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) type jmxTemplateData struct { @@ -205,7 +205,7 @@ func httpReqParseToJmx(httpReqs []RunLoadTestHttpParam) (string, error) { var buf bytes.Buffer err = tmpl.Execute(&buf, jmxHttpTemplateData) if err != nil { - log.Fatalf("Error executing template: %s", err) + log.Error().Msgf("Error executing template: %s", err) } builder.WriteString(buf.String()) } diff --git a/internal/core/load/load_generator_install_service.go b/internal/core/load/load_generator_install_service.go index 4b2da09..75ba62c 100644 --- a/internal/core/load/load_generator_install_service.go +++ b/internal/core/load/load_generator_install_service.go @@ -4,13 +4,13 @@ import ( "context" "errors" "fmt" - "log" "time" "github.com/cloud-barista/cm-ant/internal/config" "github.com/cloud-barista/cm-ant/internal/core/common/constant" "github.com/cloud-barista/cm-ant/internal/infra/outbound/tumblebug" "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" "gorm.io/gorm" ) @@ -40,7 +40,7 @@ const ( // InstallLoadGenerator installs the load generator either locally or remotely. // Currently remote request is executing via cb-tumblebug. func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (LoadGeneratorInstallInfoResult, error) { - utils.LogInfo("Starting InstallLoadGenerator") + log.Info().Msg("Starting InstallLoadGenerator") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() @@ -56,17 +56,17 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa err := l.loadRepo.GetOrInsertLoadGeneratorInstallInfoTx(ctx, loadGeneratorInstallInfo) if err != nil { - utils.LogError("Failed to insert LoadGeneratorInstallInfo:", err) + log.Error().Msgf("Failed to insert LoadGeneratorInstallInfo; %v", err) return result, err } - utils.LogInfo("LoadGeneratorInstallInfo fetched successfully") + log.Info().Msg("LoadGeneratorInstallInfo fetched successfully") defer func() { if loadGeneratorInstallInfo.Status == "starting" { loadGeneratorInstallInfo.Status = "failed" err = l.loadRepo.UpdateLoadGeneratorInstallInfoTx(ctx, loadGeneratorInstallInfo) if err != nil { - utils.LogError("Error updating LoadGeneratorInstallInfo to failed status:", err) + log.Error().Msgf("Error updating LoadGeneratorInstallInfo to failed status; %v", err) } } }() @@ -81,7 +81,7 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa switch installLocation { case constant.Local: - utils.LogInfo("Starting local installation of JMeter") + log.Info().Msgf("Starting local installation of JMeter") jmeterPath := config.AppConfig.Load.JMeter.Dir jmeterVersion := config.AppConfig.Load.JMeter.Version @@ -94,18 +94,18 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa }) if err != nil { - utils.LogError("Error while installing JMeter locally:", err) + log.Error().Msgf("Error while installing JMeter locally; %v", err) return result, fmt.Errorf("error while installing jmeter; %s", err) } } - utils.LogInfo("Local installation of JMeter completed successfully") + log.Info().Msg("Local installation of JMeter completed successfully") case constant.Remote: - utils.LogInfo("Starting remote installation of JMeter") + log.Info().Msg("Starting remote installation of JMeter") // get the spec and image information recommendVm, err := l.getRecommendVm(ctx, param.Coordinates) if err != nil { - utils.LogError("Failed to get recommended VM:", err) + log.Error().Msgf("Failed to get recommended VM; %v", err) return result, err } antVmCommonSpec := recommendVm[0].Name @@ -113,38 +113,38 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa antVmCommonImage, err := utils.ReplaceAtIndex(antVmCommonSpec, imageOs, "+", 2) if err != nil { - utils.LogError("Error replacing VM spec index:", err) + log.Error().Msgf("Error replacing VM spec index; %v", err) return result, err } // check namespace is valid or not err = l.validDefaultNs(ctx, antNsId) if err != nil { - utils.LogError("Error validating default namespace:", err) + log.Error().Msgf("Error validating default namespace; %v", err) return result, err } // get the ant default mci antMci, err := l.getAndDefaultMci(ctx, antVmCommonSpec, antVmCommonImage, recommendVmConnName) if err != nil { - utils.LogError("Error getting or creating default mci:", err) + log.Error().Msgf("Error getting or creating default mci; %v", err) return result, err } // if server is not running state, try to resume and get mci information retryCount := config.AppConfig.Load.Retry for retryCount > 0 && antMci.StatusCount.CountRunning < 1 { - utils.LogInfof("Attempting to resume MCI, retry count: %d", retryCount) + log.Info().Msgf("Attempting to resume MCI, retry count: %d", retryCount) err = l.tumblebugClient.ControlLifecycleWithContext(ctx, antNsId, antMci.Id, "resume") if err != nil { - utils.LogError("Error resuming MCI:", err) + log.Error().Msgf("Error resuming MCI; %v", err) return result, err } time.Sleep(defaultDelay) antMci, err = l.getAndDefaultMci(ctx, antVmCommonSpec, antVmCommonImage, recommendVmConnName) if err != nil { - utils.LogError("Error getting MCI after resume attempt:", err) + log.Error().Msgf("Error getting MCI after resume attempt; %v", err) return result, err } @@ -152,19 +152,19 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa } if antMci.StatusCount.CountRunning < 1 { - utils.LogError("No running VM on ant default MCI") + log.Error().Msg("No running VM on ant default MCI") return result, errors.New("there is no running vm on ant default mci") } addAuthorizedKeyCommand, err := getAddAuthorizedKeyCommand(antPrivKeyName, antPubKeyName) if err != nil { - utils.LogError("Error getting add authorized key command:", err) + log.Error().Msgf("Error getting add authorized key command; %v", err) return result, err } installationCommand, err := utils.ReadToString(installScriptPath) if err != nil { - utils.LogError("Error reading installation script:", err) + log.Error().Msgf("Error reading installation script; %v", err) return result, err } @@ -174,11 +174,11 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa _, err = l.tumblebugClient.CommandToMciWithContext(ctx, antNsId, antMci.Id, commandReq) if err != nil { - utils.LogError("Error sending command to MCI:", err) + log.Error().Msgf("Error sending command to MCI; %v", err) return result, err } - utils.LogInfo("Commands sent to MCI successfully") + log.Info().Msg("Commands sent to MCI successfully") marking := make(map[string]LoadGeneratorServer) deleteChecker := make(map[uint]bool) @@ -260,7 +260,7 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa if len(deleteList) > 0 { err = l.loadRepo.DeleteLoadGeneratorServerTx(ctx, deleteList) if err != nil { - utils.LogError("Error delete load generator list:", err) + log.Error().Msgf("Error delete load generator list; %s", err) return result, err } } @@ -273,11 +273,11 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa loadGeneratorInstallInfo.Status = "installed" err = l.loadRepo.UpdateLoadGeneratorInstallInfoTx(ctx, loadGeneratorInstallInfo) if err != nil { - utils.LogError("Error updating LoadGeneratorInstallInfo after installed:", err) + log.Error().Msgf("Error updating LoadGeneratorInstallInfo after installed; %v", err) return result, err } - utils.LogInfo("LoadGeneratorInstallInfo updated successfully") + log.Info().Msg("LoadGeneratorInstallInfo updated successfully") loadGeneratorServerResults := make([]LoadGeneratorServerResult, 0) for _, l := range loadGeneratorInstallInfo.LoadGeneratorServers { @@ -317,7 +317,7 @@ func (l *LoadService) InstallLoadGenerator(param InstallLoadGeneratorParam) (Loa result.UpdatedAt = loadGeneratorInstallInfo.UpdatedAt result.LoadGeneratorServers = loadGeneratorServerResults - utils.LogInfo("InstallLoadGenerator completed successfully") + log.Info().Msg("InstallLoadGenerator completed successfully") return result, nil } @@ -480,10 +480,10 @@ func (l *LoadService) UninstallLoadGenerator(param UninstallLoadGeneratorParam) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - utils.LogError("Cannot find valid load generator install info:", err) + log.Error().Msgf("Cannot find valid load generator install info; %v", err) return errors.New("cannot find valid load generator install info") } - utils.LogError("Error retrieving load generator install info:", err) + log.Error().Msgf("Error retrieving load generator install info; %v", err) return err } @@ -496,14 +496,14 @@ func (l *LoadService) UninstallLoadGenerator(param UninstallLoadGeneratorParam) fmt.Sprintf("JMETER_VERSION=%s", config.AppConfig.Load.JMeter.Version), }) if err != nil { - utils.LogErrorf("Error while uninstalling load generator: %s", err) + log.Error().Msgf("Error while uninstalling load generator; %s", err) return fmt.Errorf("error while uninstalling load generator: %s", err) } case constant.Remote: uninstallCommand, err := utils.ReadToString(uninstallScriptPath) if err != nil { - utils.LogError("Error reading uninstall script:", err) + log.Error().Msgf("Error reading uninstall script; %v", err) return err } @@ -514,10 +514,10 @@ func (l *LoadService) UninstallLoadGenerator(param UninstallLoadGeneratorParam) _, err = l.tumblebugClient.CommandToMciWithContext(ctx, antNsId, antMciId, commandReq) if err != nil { if errors.Is(err, context.DeadlineExceeded) { - utils.LogError("VM is not in running state. Cannot connect to the VMs.") + log.Error().Msg("VM is not in running state. Cannot connect to the VMs.") return errors.New("vm is not running state. cannot connect to the vms") } - utils.LogError("Error sending uninstall command to MCI:", err) + log.Error().Msgf("Error sending uninstall command to MCI; %v", err) return err } @@ -534,11 +534,11 @@ func (l *LoadService) UninstallLoadGenerator(param UninstallLoadGeneratorParam) err = l.loadRepo.UpdateLoadGeneratorInstallInfoTx(ctx, &loadGeneratorInstallInfo) if err != nil { - utils.LogError("Error updating load generator install info:", err) + log.Error().Msgf("Error updating load generator install info; %v", err) return err } - utils.LogInfo("Successfully uninstalled load generator.") + log.Info().Msg("Successfully uninstalled load generator.") return nil } @@ -551,7 +551,7 @@ func (l *LoadService) GetAllLoadGeneratorInstallInfo(param GetAllLoadGeneratorIn pagedResult, totalRows, err := l.loadRepo.GetPagingLoadGeneratorInstallInfosTx(ctx, param) if err != nil { - utils.LogError("Error fetching paged load generator install infos:", err) + log.Error().Msgf("Error fetching paged load generator install infos; %v", err) return result, err } @@ -600,7 +600,7 @@ func (l *LoadService) GetAllLoadGeneratorInstallInfo(param GetAllLoadGeneratorIn result.LoadGeneratorInstallInfoResults = infos result.TotalRows = totalRows - utils.LogInfof("Fetched %d load generator install info results.", len(infos)) + log.Info().Msgf("Fetched %d load generator install info results. length: %d", len(infos)) return result, nil } diff --git a/internal/core/load/load_test_execution_service.go b/internal/core/load/load_test_execution_service.go index 2254419..4c70c23 100644 --- a/internal/core/load/load_test_execution_service.go +++ b/internal/core/load/load_test_execution_service.go @@ -20,49 +20,23 @@ import ( // 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. func (l *LoadService) RunLoadTest(param RunLoadTestParam) (string, error) { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() loadTestKey := utils.CreateUniqIdBaseOnUnixTime() param.LoadTestKey = loadTestKey log.Info().Msgf("Starting load test with key: %s", loadTestKey) - // check the installation of load generator. - // if it is not installed, then install it to user selected location. - if param.LoadGeneratorInstallInfoId == uint(0) { - log.Info().Msgf("No LoadGeneratorInstallInfoId provided, installing load generator...") - result, err := l.InstallLoadGenerator(param.InstallLoadGenerator) - if err != nil { - log.Error().Msgf("Error installing load generator: %v", err) - return "", err - } - - param.LoadGeneratorInstallInfoId = result.ID - log.Info().Msgf("Load generator installed with ID: %d", result.ID) - } - - if param.LoadGeneratorInstallInfoId == uint(0) { - log.Error().Msgf("LoadGeneratorInstallInfoId is still 0 after installation.") - return "", errors.New("error while load generator installation process") - } - - loadGeneratorInstallInfo, err := l.loadRepo.GetValidLoadGeneratorInstallInfoByIdTx(ctx, param.LoadGeneratorInstallInfoId) - if err != nil { - log.Error().Msgf("Error retrieving load generator installation info: %v", err) - return "", err - } - - log.Info().Msgf("Retrieved load generator installation info with ID: %d", param.LoadGeneratorInstallInfoId) - duration, err := strconv.Atoi(param.Duration) if err != nil { - return "", err + log.Error().Msgf("error while type convert; %s", err.Error()) + return loadTestKey, err } rampUpTime, err := strconv.Atoi(param.RampUpTime) if err != nil { - return "", err + return loadTestKey, err } totalExecutionSecond := uint64(duration + rampUpTime) @@ -70,7 +44,6 @@ func (l *LoadService) RunLoadTest(param RunLoadTestParam) (string, error) { e := startAt.Add(time.Duration(totalExecutionSecond) * time.Second) stateArg := LoadTestExecutionState{ - LoadGeneratorInstallInfoId: loadGeneratorInstallInfo.ID, LoadTestKey: loadTestKey, ExecutionStatus: constant.OnProcessing, StartAt: startAt, @@ -79,9 +52,59 @@ func (l *LoadService) RunLoadTest(param RunLoadTestParam) (string, error) { NsId: param.NsId, MciId: param.MciId, VmId: param.VmId, + WithMetrics: param.CollectAdditionalSystemMetrics, + } + + err = l.loadRepo.InsertLoadTestExecutionStateTx(ctx, &stateArg) + if err != nil { + log.Error().Msgf("Error saving initial load test execution state: %v", err) + return "", err + } + log.Info().Msgf("Initial load test execution state saved for key: %s", loadTestKey) + + go l.processLoadTestAsync(param, &stateArg) + + return loadTestKey, nil + +} + +func (l *LoadService) processLoadTestAsync(param RunLoadTestParam, loadTestExecutionState *LoadTestExecutionState) { + + var globalErr error + + defer func() { + if globalErr != nil { + _ = l.loadRepo.UpdateLoadTestExecutionStateTx(context.Background(), loadTestExecutionState) + } + }() + + failed := func(logMsg string, occuredError error) { + log.Error().Msg(logMsg) + loadTestExecutionState.ExecutionStatus = constant.TestFailed + loadTestExecutionState.FailureMessage = logMsg + globalErr = occuredError + finishAt := time.Now() + loadTestExecutionState.FinishAt = &finishAt + } + + if param.LoadGeneratorInstallInfoId == uint(0) { + log.Info().Msgf("No LoadGeneratorInstallInfoId provided, installing load generator...") + + result, err := l.InstallLoadGenerator(param.InstallLoadGenerator) + if err != nil { + failed(fmt.Sprintf("Error installing load generator: %v", err), err) + return + } + + param.LoadGeneratorInstallInfoId = result.ID + log.Info().Msgf("Load generator installed with ID: %d", result.ID) } - go l.processLoadTest(param, &loadGeneratorInstallInfo, &stateArg) + loadGeneratorInstallInfo, err := l.loadRepo.GetValidLoadGeneratorInstallInfoByIdTx(context.Background(), param.LoadGeneratorInstallInfoId) + if err != nil { + failed(fmt.Sprintf("Error installing load generator: %v", err), err) + return + } var hs []LoadTestExecutionHttpInfo @@ -98,8 +121,8 @@ func (l *LoadService) RunLoadTest(param RunLoadTestParam) (string, error) { hs = append(hs, hh) } - loadArg := LoadTestExecutionInfo{ - LoadTestKey: loadTestKey, + loadTestExecutionInfoParam := LoadTestExecutionInfo{ + LoadTestKey: param.LoadTestKey, TestName: param.TestName, VirtualUsers: param.VirtualUsers, Duration: param.Duration, @@ -115,19 +138,136 @@ func (l *LoadService) RunLoadTest(param RunLoadTestParam) (string, error) { LoadGeneratorInstallInfoId: loadGeneratorInstallInfo.ID, LoadTestExecutionHttpInfos: hs, + + LoadTestExecutionStateId: loadTestExecutionState.ID, } - log.Info().Msgf("Saving load test execution info for key: %s", loadTestKey) - err = l.loadRepo.SaveForLoadTestExecutionTx(ctx, &loadArg, &stateArg) + err = l.loadRepo.SaveForLoadTestExecutionTx(context.Background(), &loadTestExecutionInfoParam) if err != nil { - log.Error().Msgf("Error saving load test execution info: %v", err) - return "", err + failed(fmt.Sprintf("Error saving load test execution info: %v", err), err) + return } - log.Info().Msgf("Load test started successfully with key: %s", loadTestKey) + loadTestExecutionState.GeneratorInstallInfoId = loadGeneratorInstallInfo.ID + loadTestExecutionState.TestExecutionInfoId = loadTestExecutionInfoParam.ID - return loadTestKey, nil + err = l.loadRepo.UpdateLoadTestExecutionStateTx(context.Background(), loadTestExecutionState) + + if err != nil { + failed(fmt.Sprintf("Error while update load test execution state to save load test execution info id and load generator install info id; %v", err), err) + } + if param.CollectAdditionalSystemMetrics { + if strings.TrimSpace(param.AgentHostname) == "" { + mci, err := l.tumblebugClient.GetMciWithContext(context.Background(), param.NsId, param.MciId) + + if err != nil { + failed(fmt.Sprintf("unexpected error occurred while fetching mci for install metrics agent; %s", err), err) + return + } + + if len(mci.Vm) == 0 { + failed("mci vm's length is zero", errors.New("mci vm's length is zero")) + return + } + + if len(mci.Vm) == 1 { + param.AgentHostname = mci.Vm[0].PublicIP + } else { + for _, v := range mci.Vm { + if v.Id == param.VmId { + param.AgentHostname = v.PublicIP + } + } + } + + if param.AgentHostname == "" { + err := errors.New("agent host name afeter get mci from tumblebug must be set to not nil") + failed(fmt.Sprintf("invalid agent hostname for test %s; %v", param.LoadTestKey, err), err) + return + } + } + + arg := MonitoringAgentInstallationParams{ + NsId: param.NsId, + MciId: param.MciId, + VmIds: []string{param.VmId}, + } + + // install and run the agent for collect metrics + _, err := l.InstallMonitoringAgent(arg) + if err != nil { + failed(fmt.Sprintf("unexpected error occurred while installing monitoring agent; %s", err), err) + return + } + + log.Info().Msgf("metrics agent installed successfully for load test; %s %s %s", arg.NsId, arg.MciId, arg.VmIds) + } + + loadTestDone := make(chan bool) + + var username string + var publicIp string + var port string + for _, s := range loadGeneratorInstallInfo.LoadGeneratorServers { + if s.IsMaster { + username = s.Username + publicIp = s.PublicIp + port = s.SshPort + } + } + + home, err := os.UserHomeDir() + if err != nil { + failed(fmt.Sprintf("user home dir is not valid; %s", err), err) + return + } + + dataParam := &fetchDataParam{ + LoadTestDone: loadTestDone, + LoadTestKey: param.LoadTestKey, + InstallLocation: loadGeneratorInstallInfo.InstallLocation, + InstallPath: loadGeneratorInstallInfo.InstallPath, + PublicKeyName: loadGeneratorInstallInfo.PublicKeyName, + PrivateKeyName: loadGeneratorInstallInfo.PrivateKeyName, + Username: username, + PublicIp: publicIp, + Port: port, + CollectAdditionalSystemMetrics: param.CollectAdditionalSystemMetrics, + Home: home, + } + + go l.fetchData(dataParam) + + defer func() { + loadTestDone <- true + close(loadTestDone) + updateErr := l.loadRepo.UpdateLoadTestExecutionStateTx(context.Background(), loadTestExecutionState) + if updateErr != nil { + failed(fmt.Sprintf("Error updating load test execution state: %v", updateErr), updateErr) + return + } + + log.Info().Msgf("successfully done load test for %s", dataParam.LoadTestKey) + }() + + compileDuration, executionDuration, loadTestErr := l.executeLoadTest(param, &loadGeneratorInstallInfo) + + loadTestExecutionState.CompileDuration = compileDuration + loadTestExecutionState.ExecutionDuration = executionDuration + + if loadTestErr != nil { + failed(fmt.Sprintf("Error while load testing: %v", loadTestErr), loadTestErr) + return + } + + updateErr := l.updateLoadTestExecution(loadTestExecutionState) + if updateErr != nil { + failed(fmt.Sprintf("Error while updating load test execution: %v", updateErr), updateErr) + return + } + + loadTestExecutionState.ExecutionStatus = constant.Successed } // processLoadTest executes the load test. @@ -261,13 +401,13 @@ func (l *LoadService) executeLoadTest(param RunLoadTestParam, loadGeneratorInsta resultFileName := fmt.Sprintf("%s_result.csv", loadTestKey) loadGeneratorInstallVersion := loadGeneratorInstallInfo.InstallVersion - utils.LogInfof("Running load test with key: %s", loadTestKey) + log.Info().Msgf("Running load test with key: %s", loadTestKey) compileDuration := "0" executionDuration := "0" start := time.Now() if installLocation == constant.Remote { - utils.LogInfo("Remote execute detected.") + log.Info().Msg("Remote execute detected.") var buf bytes.Buffer err := parseTestPlanStructToString(&buf, param, loadGeneratorInstallInfo) if err != nil { @@ -305,7 +445,7 @@ func (l *LoadService) executeLoadTest(param RunLoadTestParam, loadGeneratorInsta } } else if installLocation == constant.Local { - utils.LogInfo("Local execute detected.") + log.Info().Msg("Local execute detected.") exist := utils.ExistCheck(loadGeneratorInstallPath) @@ -340,14 +480,14 @@ func (l *LoadService) executeLoadTest(param RunLoadTestParam, loadGeneratorInsta func (l *LoadService) updateLoadTestExecution(loadTestExecutionState *LoadTestExecutionState) error { err := l.loadRepo.UpdateLoadTestExecutionInfoDuration(context.Background(), loadTestExecutionState.LoadTestKey, loadTestExecutionState.CompileDuration, loadTestExecutionState.ExecutionDuration) if err != nil { - utils.LogErrorf("Error updating load test execution info: %v", err) + log.Error().Msgf("Error updating load test execution info; %v", err) return err } loadTestExecutionState.ExecutionStatus = constant.OnFetching err = l.loadRepo.UpdateLoadTestExecutionStateTx(context.Background(), loadTestExecutionState) if err != nil { - utils.LogErrorf("Error updating load test execution state: %v", err) + log.Error().Msgf("Error updating load test execution state; %v", err) return err } return nil @@ -356,7 +496,7 @@ func (l *LoadService) updateLoadTestExecution(loadTestExecutionState *LoadTestEx // generateJmeterExecutionCmd generates the JMeter execution command. // Constructs a JMeter command string that includes the test plan path and result file path. func generateJmeterExecutionCmd(loadGeneratorInstallPath, loadGeneratorInstallVersion, testPlanName, resultFileName string) string { - utils.LogInfof("Generating JMeter execution command for test plan: %s, result file: %s", testPlanName, resultFileName) + log.Info().Msgf("Generating JMeter execution command for test plan: %s, result file: %s", testPlanName, resultFileName) var builder strings.Builder testPath := fmt.Sprintf("%s/test_plan/%s", loadGeneratorInstallPath, testPlanName) @@ -368,7 +508,7 @@ func generateJmeterExecutionCmd(loadGeneratorInstallPath, loadGeneratorInstallVe builder.WriteString(fmt.Sprintf(" -l=%s", resultPath)) builder.WriteString(fmt.Sprintf(" && sudo rm %s", testPath)) - utils.LogInfof("JMeter execution command generated: %s", builder.String()) + log.Info().Msgf("JMeter execution command generated: %s", builder.String()) return builder.String() } @@ -401,7 +541,11 @@ func (l *LoadService) StopLoadTest(param StopLoadTestParam) error { return errors.New("load test is already completed") } - installInfo := state.LoadGeneratorInstallInfo + installInfo, err := l.loadRepo.GetValidLoadGeneratorInstallInfoByIdTx(ctx, state.GeneratorInstallInfoId) + + if err != nil { + return fmt.Errorf("error occurred while retrieve load install info: %w", err) + } killCmd := killCmdGen(param.LoadTestKey) @@ -431,6 +575,6 @@ func (l *LoadService) StopLoadTest(param StopLoadTestParam) error { func killCmdGen(loadTestKey string) string { grepRegex := fmt.Sprintf("'\\/bin\\/ApacheJMeter\\.jar.*%s'", loadTestKey) - utils.LogInfof("Generating kill command for load test key: %s", loadTestKey) + log.Info().Msgf("Generating kill command for load test key: %s", loadTestKey) return fmt.Sprintf("kill -15 $(ps -ef | grep -E %s | awk '{print $2}')", grepRegex) } diff --git a/internal/core/load/metrics_agent_service.go b/internal/core/load/metrics_agent_service.go index 394ef13..46fdb8c 100644 --- a/internal/core/load/metrics_agent_service.go +++ b/internal/core/load/metrics_agent_service.go @@ -9,33 +9,34 @@ import ( "github.com/cloud-barista/cm-ant/internal/infra/outbound/tumblebug" "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) // 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...") + log.Info().Msg("Starting installation of monitoring agent...") ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() var res []MonitoringAgentInstallationResult scriptPath := utils.JoinRootPathWith("/script/install-server-agent.sh") - utils.LogInfof("Reading installation script from %s", scriptPath) + log.Info().Msgf("Reading installation script from %s", scriptPath) installScript, err := os.ReadFile(scriptPath) if err != nil { - utils.LogErrorf("Failed to read installation script: %v", err) + log.Error().Msgf("Failed to read installation script; %v", err) return res, err } username := "cb-user" - utils.LogInfof("Fetching mci object for NS: %s, msi id: %s", param.NsId, param.MciId) + log.Info().Msgf("Fetching mci object for NS: %s, msi id: %s", param.NsId, param.MciId) mci, err := l.tumblebugClient.GetMciWithContext(ctx, param.NsId, param.MciId) if err != nil { - utils.LogErrorf("Failed to fetch mci : %v", err) + log.Error().Msgf("Failed to fetch mci; %v", err) return res, err } if len(mci.Vm) == 0 { - utils.LogErrorf("No VMs found on mci. Provision VM first.") + log.Error().Msg("No VMs found on mci. Provision VM first.") return res, errors.New("there is no vm on mci. provision vm first") } @@ -61,10 +62,10 @@ func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationPa VmId: vm.Id, VmCount: len(mci.Vm), } - utils.LogInfof("Inserting monitoring agent installation info into database vm id : %s", vm.Id) + log.Info().Msgf("Inserting monitoring agent installation info into database vm id : %s", vm.Id) err = l.loadRepo.InsertMonitoringAgentInfoTx(ctx, &m) if err != nil { - utils.LogErrorf("Failed to insert monitoring agent info for vm id %s : %v", vm.Id, err) + log.Error().Msgf("Failed to insert monitoring agent info for vm id %s : %v", vm.Id, err) errorCollection = append(errorCollection, err) continue } @@ -74,16 +75,16 @@ func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationPa UserName: username, } - utils.LogInfof("Sending install command to mci. NS: %s, mci: %s, VMID: %s", param.NsId, param.MciId, vm.Id) + log.Info().Msgf("Sending install command to mci. NS: %s, mci: %s, VMID: %s", param.NsId, param.MciId, vm.Id) _, err = l.tumblebugClient.CommandToVmWithContext(ctx, param.NsId, param.MciId, vm.Id, commandReq) if err != nil { if errors.Is(err, context.DeadlineExceeded) { m.Status = "timeout" - utils.LogErrorf("Timeout of context. Already 15 seconds has been passed. vm id : %s", vm.Id) + log.Error().Msgf("Timeout of context. Already 15 seconds has been passed. vm id; %s", vm.Id) } else { m.Status = "failed" - utils.LogErrorf("Error occurred during command execution: %v", err) + log.Error().Msgf("Error occurred during command execution; %v", err) } errorCollection = append(errorCollection, err) } else { @@ -106,7 +107,7 @@ func (l *LoadService) InstallMonitoringAgent(param MonitoringAgentInstallationPa } res = append(res, r) - utils.LogInfof( + log.Info().Msgf( "Complete installing monitoring agent on mics: %s, vm: %s", m.MciId, m.VmId, @@ -128,15 +129,15 @@ func (l *LoadService) GetAllMonitoringAgentInfos(param GetAllMonitoringAgentInfo ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - utils.LogInfof("GetAllMonitoringAgentInfos called with param: %+v", param) + log.Info().Msgf("GetAllMonitoringAgentInfos called with param: %+v", param) result, totalRows, err := l.loadRepo.GetPagingMonitoringAgentInfosTx(ctx, param) if err != nil { - utils.LogErrorf("Error fetching monitoring agent infos: %v", err) + log.Error().Msgf("Error fetching monitoring agent infos; %v", err) return res, err } - utils.LogInfof("Fetched %d monitoring agent infos", len(result)) + log.Info().Msgf("Fetched %d monitoring agent infos", len(result)) for _, monitoringAgentInfo := range result { var r MonitoringAgentInstallationResult @@ -166,20 +167,20 @@ func (l *LoadService) UninstallMonitoringAgent(param MonitoringAgentInstallation ctx := context.Background() var effectedResults int64 - utils.LogInfo("Starting uninstallation of monitoring agent...") + log.Info().Msg("Starting uninstallation of monitoring agent...") result, err := l.loadRepo.GetAllMonitoringAgentInfosTx(ctx, param) if err != nil { - utils.LogErrorf("Failed to fetch monitoring agent information: %v", err) + log.Error().Msgf("Failed to fetch monitoring agent information; %v", err) return effectedResults, err } scriptPath := utils.JoinRootPathWith("/script/remove-server-agent.sh") - utils.LogInfof("Reading uninstallation script from %s", scriptPath) + log.Info().Msgf("Reading uninstallation script from %s", scriptPath) uninstallPath, err := os.ReadFile(scriptPath) if err != nil { - utils.LogErrorf("Failed to read uninstallation script: %v", err) + log.Error().Msgf("Failed to read uninstallation script; %v", err) return effectedResults, err } @@ -198,19 +199,19 @@ func (l *LoadService) UninstallMonitoringAgent(param MonitoringAgentInstallation _, err = l.tumblebugClient.CommandToVmWithContext(ctx, monitoringAgentInfo.NsId, monitoringAgentInfo.MciId, monitoringAgentInfo.VmId, commandReq) if err != nil { errorCollection = append(errorCollection, err) - utils.LogErrorf("Failed to uninstall monitoring agent on mci: %s, VM: %s - Error: %v", monitoringAgentInfo.MciId, monitoringAgentInfo.VmId, err) + log.Error().Msgf("Failed to uninstall monitoring agent on mci: %s, VM: %s - Error: %v", monitoringAgentInfo.MciId, monitoringAgentInfo.VmId, err) continue } err = l.loadRepo.DeleteAgentInstallInfoStatusTx(ctx, &monitoringAgentInfo) if err != nil { - utils.LogErrorf("Failed to delete agent installation status for mci: %s, VM: %s - Error: %v", monitoringAgentInfo.MciId, monitoringAgentInfo.VmId, err) + log.Error().Msgf("Failed to delete agent installation status for mci: %s, VM: %s - Error: %v", monitoringAgentInfo.MciId, monitoringAgentInfo.VmId, err) errorCollection = append(errorCollection, err) continue } - utils.LogInfof("Successfully uninstalled monitoring agent on mci: %s, VM: %s", monitoringAgentInfo.MciId, monitoringAgentInfo.VmId) + log.Info().Msgf("Successfully uninstalled monitoring agent on mci: %s, VM: %s", monitoringAgentInfo.MciId, monitoringAgentInfo.VmId) time.Sleep(time.Second) } diff --git a/internal/core/load/models.go b/internal/core/load/models.go index 14534c8..1a239a0 100644 --- a/internal/core/load/models.go +++ b/internal/core/load/models.go @@ -83,11 +83,11 @@ type LoadTestExecutionState struct { FailureMessage string CompileDuration string ExecutionDuration string + WithMetrics bool - LoadTestExecutionInfoId uint - - LoadGeneratorInstallInfoId uint - LoadGeneratorInstallInfo LoadGeneratorInstallInfo + // not to make one to one relationship between LoadTestExecutionInfo and LoadGeneratorInstallInfo + TestExecutionInfoId uint + GeneratorInstallInfoId uint } type LoadTestExecutionInfo struct { @@ -110,8 +110,11 @@ type LoadTestExecutionInfo struct { ExecutionDuration string LoadTestExecutionHttpInfos []LoadTestExecutionHttpInfo - LoadTestExecutionState LoadTestExecutionState + // LoadTestExecutionInfo has one LoadTestExecutionState + LoadTestExecutionStateId uint + LoadTestExecutionState LoadTestExecutionState + // LoadTestExecutionInfo has one LoadGeneratorInstallInfo LoadGeneratorInstallInfoId uint LoadGeneratorInstallInfo LoadGeneratorInstallInfo } diff --git a/internal/core/load/performace_evaluation_service.go b/internal/core/load/performace_evaluation_service.go index 6bef8df..f189f35 100644 --- a/internal/core/load/performace_evaluation_service.go +++ b/internal/core/load/performace_evaluation_service.go @@ -4,8 +4,9 @@ import ( "context" "time" + "github.com/cloud-barista/cm-ant/internal/core/common/constant" "github.com/cloud-barista/cm-ant/internal/infra/outbound/tumblebug" - "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) // LoadService represents a service for managing load operations. @@ -50,19 +51,19 @@ func (l *LoadService) GetAllLoadTestExecutionState(param GetAllLoadTestExecution ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - utils.LogInfof("GetAllLoadExecutionStates called with param: %+v", param) + log.Info().Msgf("GetAllLoadExecutionStates called with param: %+v", param) result, totalRows, err := l.loadRepo.GetPagingLoadTestExecutionStateTx(ctx, param) if err != nil { - utils.LogErrorf("Error fetching load test execution state infos: %v", err) + log.Error().Msgf("Error fetching load test execution state infos; %v", err) return res, err } - utils.LogInfof("Fetched %d monitoring agent infos", len(result)) + log.Info().Msgf("Fetched %d monitoring agent infos", len(result)) for _, loadTestExecutionState := range result { state := mapLoadTestExecutionStateResult(loadTestExecutionState) - state.LoadGeneratorInstallInfo = mapLoadGeneratorInstallInfoResult(loadTestExecutionState.LoadGeneratorInstallInfo) + // state.LoadGeneratorInstallInfo = mapLoadGeneratorInstallInfoResult(loadTestExecutionState.LoadGeneratorInstallInfo) states = append(states, state) } @@ -77,16 +78,16 @@ func (l *LoadService) GetLoadTestExecutionState(param GetLoadTestExecutionStateP ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - utils.LogInfof("GetLoadTestExecutionState called with param: %+v", param) + log.Info().Msgf("GetLoadTestExecutionState called with param: %+v", param) state, err := l.loadRepo.GetLoadTestExecutionStateTx(ctx, param) if err != nil { - utils.LogErrorf("Error fetching load test execution state infos: %v", err) + log.Error().Msgf("Error fetching load test execution state infos; %v", err) return res, err } res = mapLoadTestExecutionStateResult(state) - res.LoadGeneratorInstallInfo = mapLoadGeneratorInstallInfoResult(state.LoadGeneratorInstallInfo) + // res.LoadGeneratorInstallInfo = mapLoadGeneratorInstallInfoResult(state.LoadGeneratorInstallInfo) return res, nil } @@ -96,15 +97,15 @@ func (l *LoadService) GetAllLoadTestExecutionInfos(param GetAllLoadTestExecution ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - utils.LogInfof("GetAllLoadTestExecutionInfos called with param: %+v", param) + log.Info().Msgf("GetAllLoadTestExecutionInfos called with param: %+v", param) result, totalRows, err := l.loadRepo.GetPagingLoadTestExecutionHistoryTx(ctx, param) if err != nil { - utils.LogErrorf("Error fetching load test execution infos: %v", err) + log.Error().Msgf("Error fetching load test execution infos; %v", err) return res, err } - utils.LogInfof("Fetched %d load test execution infos:", len(result)) + log.Info().Msgf("Fetched %d load test execution infos:", len(result)) for _, r := range result { rs = append(rs, mapLoadTestExecutionInfoResult(r)) @@ -121,11 +122,11 @@ func (l *LoadService) GetLoadTestExecutionInfo(param GetLoadTestExecutionInfoPar ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - utils.LogInfof("GetLoadTestExecutionInfo called with param: %+v", param) + log.Info().Msgf("GetLoadTestExecutionInfo called with param: %+v", param) executionInfo, err := l.loadRepo.GetLoadTestExecutionInfoTx(ctx, param) if err != nil { - utils.LogErrorf("Error fetching load test execution state infos: %v", err) + log.Error().Msgf("Error fetching load test execution state infos; %v", err) return res, err } @@ -145,12 +146,13 @@ func mapLoadTestExecutionHttpInfoResult(h LoadTestExecutionHttpInfo) LoadTestExe } func mapLoadTestExecutionStateResult(state LoadTestExecutionState) LoadTestExecutionStateResult { - return LoadTestExecutionStateResult{ + stateResult := &LoadTestExecutionStateResult{ ID: state.ID, LoadTestKey: state.LoadTestKey, ExecutionStatus: state.ExecutionStatus, StartAt: state.StartAt, FinishAt: state.FinishAt, + ExpectedFinishAt: state.ExpectedFinishAt, TotalExpectedExcutionSecond: state.TotalExpectedExcutionSecond, FailureMessage: state.FailureMessage, CompileDuration: state.CompileDuration, @@ -158,6 +160,17 @@ func mapLoadTestExecutionStateResult(state LoadTestExecutionState) LoadTestExecu CreatedAt: state.CreatedAt, UpdatedAt: state.UpdatedAt, } + + if stateResult.ExecutionStatus == constant.Successed { + stateResult.IconCode = constant.Ok + } else if stateResult.ExecutionStatus == constant.TestFailed { + stateResult.IconCode = constant.Fail + } else { + stateResult.IconCode = constant.Pending + } + + return *stateResult + } func mapLoadGeneratorServerResult(s LoadGeneratorServer) LoadGeneratorServerResult { diff --git a/internal/core/load/performance_evaluation_result_service.go b/internal/core/load/performance_evaluation_result_service.go index aaeba11..a5258b7 100644 --- a/internal/core/load/performance_evaluation_result_service.go +++ b/internal/core/load/performance_evaluation_result_service.go @@ -1,9 +1,9 @@ package load import ( + "context" "errors" "fmt" - "log" "math" "sort" "strconv" @@ -12,6 +12,7 @@ import ( "github.com/cloud-barista/cm-ant/internal/core/common/constant" "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) type metricsUnits struct { @@ -133,6 +134,105 @@ func (l *LoadService) GetLoadTestMetrics(param GetLoadTestResultParam) ([]Metric return metricsSummaries, nil } +func (l *LoadService) GetLastLoadTestResult(param GetLastLoadTestResultParam) (interface{}, error) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + stateQueryParam := GetLoadTestExecutionStateParam{ + NsId: param.NsId, + MciId: param.MciId, + VmId: param.VmId, + } + state, err := l.loadRepo.GetLoadTestExecutionStateTx(ctx, stateQueryParam) + + if err != nil { + log.Error().Msgf("Error fetching load test execution state infos; %v", err) + return nil, err + } + + loadTestKey := state.LoadTestKey + fileName := fmt.Sprintf("%s_result.csv", loadTestKey) + resultFolderPath := utils.JoinRootPathWith("/result/" + loadTestKey) + toFilePath := fmt.Sprintf("%s/%s", resultFolderPath, fileName) + resultMap, err := appendResultRawData(toFilePath) + if err != nil { + return nil, err + } + + var resultSummaries []ResultSummary + + for label, results := range resultMap { + resultSummaries = append(resultSummaries, ResultSummary{ + Label: label, + Results: results, + }) + } + + formattedDate, err := resultFormat(param.Format, resultSummaries) + + if err != nil { + return nil, err + } + + return formattedDate, nil +} + +func (l *LoadService) GetLastLoadTestMetrics(param GetLastLoadTestResultParam) ([]MetricsSummary, error) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + stateQueryParam := GetLoadTestExecutionStateParam{ + NsId: param.NsId, + MciId: param.MciId, + VmId: param.VmId, + } + + state, err := l.loadRepo.GetLoadTestExecutionStateTx(ctx, stateQueryParam) + + if err != nil { + log.Error().Msgf("Error fetching load test execution state infos; %v", err) + return nil, err + } + + loadTestKey := state.LoadTestKey + + if !state.WithMetrics { + log.Error().Msgf("%s does not contain metrics collection", loadTestKey) + return nil, errors.New("metrics does not collected while performance evaluation") + } + + metrics := []string{"cpu", "disk", "memory", "network"} + resultFolderPath := utils.JoinRootPathWith("/result/" + loadTestKey) + + metricsMap := make(map[string][]*MetricsRawData) + + for _, v := range metrics { + + fileName := fmt.Sprintf("%s_%s_result.csv", loadTestKey, v) + toPath := fmt.Sprintf("%s/%s", resultFolderPath, fileName) + + metricsMap, err = appendMetricsRawData(metricsMap, toPath) + if err != nil { + return nil, err + } + + } + + var metricsSummaries []MetricsSummary + + for label, metrics := range metricsMap { + metricsSummaries = append(metricsSummaries, MetricsSummary{ + Label: label, + Metrics: metrics, + }) + } + + if err != nil { + return nil, err + } + + return metricsSummaries, nil +} func calculatePercentile(elapsedList []int, percentile float64) float64 { index := int(math.Ceil(float64(len(elapsedList))*percentile)) - 1 diff --git a/internal/core/load/repository.go b/internal/core/load/repository.go index e3de251..1d0650d 100644 --- a/internal/core/load/repository.go +++ b/internal/core/load/repository.go @@ -255,8 +255,8 @@ func (r *LoadRepository) InsertLoadTestExecutionStateTx(ctx context.Context, par err := r.execInTransaction(ctx, func(d *gorm.DB) error { err := d. Where( - "load_generator_install_info_id = ? AND load_test_key = ?", - param.LoadGeneratorInstallInfoId, param.LoadTestKey, + "load_test_key = ?", + param.LoadTestKey, ). FirstOrCreate(param).Error @@ -271,7 +271,7 @@ func (r *LoadRepository) InsertLoadTestExecutionStateTx(ctx context.Context, par } -func (r *LoadRepository) SaveForLoadTestExecutionTx(ctx context.Context, loadParam *LoadTestExecutionInfo, stateParam *LoadTestExecutionState) error { +func (r *LoadRepository) SaveForLoadTestExecutionTx(ctx context.Context, loadParam *LoadTestExecutionInfo) error { err := r.execInTransaction(ctx, func(d *gorm.DB) error { err := d. Where( @@ -283,16 +283,6 @@ func (r *LoadRepository) SaveForLoadTestExecutionTx(ctx context.Context, loadPar return err } - stateParam.LoadTestExecutionInfoId = loadParam.ID - err = d. - Where("load_test_key = ?", stateParam.LoadTestKey). - FirstOrCreate(&stateParam). - Error - - if err != nil { - return err - } - return nil }) @@ -338,8 +328,8 @@ func (r *LoadRepository) GetPagingLoadTestExecutionStateTx(ctx context.Context, err := r.execInTransaction(ctx, func(d *gorm.DB) error { q := d.Model(&LoadTestExecutionState{}). - Preload("LoadGeneratorInstallInfo"). - Preload("LoadGeneratorInstallInfo.LoadGeneratorServers"). + // Preload("LoadGeneratorInstallInfo"). + // Preload("LoadGeneratorInstallInfo.LoadGeneratorServers"). Order("load_test_execution_states.created_at desc") if param.LoadTestKey != "" { @@ -371,9 +361,8 @@ func (r *LoadRepository) GetLoadTestExecutionStateTx(ctx context.Context, param err := r.execInTransaction(ctx, func(d *gorm.DB) error { - q := d.Model(&loadTestExecutionState). - Preload("LoadGeneratorInstallInfo"). - Preload("LoadGeneratorInstallInfo.LoadGeneratorServers") + q := d.Model(&loadTestExecutionState) + if param.LoadTestKey != "" { q = q.Where("load_test_execution_states.load_test_key = ?", param.LoadTestKey) diff --git a/internal/core/load/rsync_fetch_service.go b/internal/core/load/rsync_fetch_service.go index abe3136..7d576fa 100644 --- a/internal/core/load/rsync_fetch_service.go +++ b/internal/core/load/rsync_fetch_service.go @@ -126,7 +126,7 @@ func rsyncFiles(f *fetchDataParam) error { toFilePath) } - utils.LogInfo("cmd for rsync: ", cmd) + log.Info().Msgf("cmd for rsync: %s", cmd) err := utils.InlineCmd(cmd) if err == nil { @@ -134,7 +134,7 @@ func rsyncFiles(f *fetchDataParam) error { return // Success, exit the retry loop } - utils.LogError(fmt.Sprintf("Error during rsync attempt %d for %s: %v", attempt, fileName, err)) + log.Error().Msgf(fmt.Sprintf("Error during rsync attempt %d for %s: %v", attempt, fileName, err)) // Wait before retrying if attempt < maxRetries { diff --git a/internal/infra/db/db.go b/internal/infra/db/db.go index fec3b35..caa2246 100644 --- a/internal/infra/db/db.go +++ b/internal/infra/db/db.go @@ -3,8 +3,6 @@ package db import ( "errors" "fmt" - "log" - "os" "strings" "time" @@ -12,12 +10,20 @@ import ( "github.com/cloud-barista/cm-ant/internal/core/cost" "github.com/cloud-barista/cm-ant/internal/core/load" "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" ) +type zerologGormLogger struct{} + +func (z zerologGormLogger) Printf(format string, v ...interface{}) { + log.Printf((fmt.Sprintf(format, v...))) +} + + func migrateDB(defaultDb *gorm.DB) error { err := defaultDb.AutoMigrate( &load.MonitoringAgentInfo{}, @@ -32,19 +38,19 @@ func migrateDB(defaultDb *gorm.DB) error { ) if err != nil { - utils.LogErrorf("Failed to auto migrate database tables: %v\n", err) + log.Error().Msgf("Failed to auto migrate database tables: %v", err) return err } - utils.LogInfo("Database tables auto migration completed successfully") + log.Info().Msg("Database tables auto migration completed successfully") return nil } func connectSqliteDB(dbPath string) (*gorm.DB, error) { - utils.LogInfof("SQLite configuration: meta SQLite DB path is %s\n", dbPath) + log.Info().Msgf("SQLite configuration: meta SQLite DB path is %s", dbPath) newLogger := logger.New( - log.New(os.Stdout, "\r", log.LstdFlags), + zerologGormLogger{}, logger.Config{ SlowThreshold: time.Second, // LogLevel: logger.Info, @@ -58,11 +64,11 @@ func connectSqliteDB(dbPath string) (*gorm.DB, error) { Logger: newLogger, }) if err != nil { - log.Printf("[ERROR] Failed to connect to SQLite database: %v\n", err) + log.Error().Msgf("Failed to connect to SQLite database: %v", err) return nil, err } - log.Println("[INFO] Connected to SQLite database successfully") + log.Info().Msg("Connected to SQLite database successfully") return sqliteDb, nil } @@ -87,29 +93,27 @@ func NewDBConnection() (*gorm.DB, error) { // sqlFilePath := sqliteFilePath(d.Host) // sqliteDB, err := connectSqliteDB(sqlFilePath) // if err != nil { - // utils.LogErrorf("Failed to establish SQLite DB connection: %v\n", err) // return nil, err // } // db = sqliteDB - // utils.LogInfof("Initialized SQLite database successfully [%s]\n", d.Driver) // } else if driver == "postgres" { postgresDb, err := connectPostgresDB(d.Host, d.Port, d.User, d.Password, d.Name) if err != nil { - utils.LogErrorf("Failed to establish Postgres DB connection: %v\n", err) + log.Error().Msgf("Failed to establish Postgres DB connection: %v", err) return nil, err } db = postgresDb - utils.LogInfof("Initialized Postgres database successfully [%s]\n", d.Driver) + log.Info().Msgf("Initialized Postgres database successfully [%s]", d.Driver) } else { return nil, errors.New("unsuppored database driver") } err := migrateDB(db) if err != nil { - utils.LogErrorf("Failed to migrate database: %v\n", err) + log.Info().Msgf("Failed to migrate database: %v", err) return nil, err } @@ -126,7 +130,7 @@ func connectPostgresDB(host, port, user, password, name string) (*gorm.DB, error return nil, errors.New("database connection info is incorrect") } newLogger := logger.New( - log.New(os.Stdout, "\r", log.LstdFlags), + zerologGormLogger{}, logger.Config{ SlowThreshold: time.Second, // LogLevel: logger.Info, @@ -143,10 +147,10 @@ func connectPostgresDB(host, port, user, password, name string) (*gorm.DB, error Logger: newLogger, }) if err != nil { - utils.LogErrorf("Failed to connect to Postgresql database: %v\n", err) + log.Info().Msgf("Failed to connect to Postgresql database: %v", err) return nil, err } - utils.LogInfo("Connected to Postgresql database successfully") + log.Info().Msg("Connected to Postgresql database successfully") return db, nil } diff --git a/internal/infra/outbound/spider/price.go b/internal/infra/outbound/spider/price.go index c24d3ca..6608917 100644 --- a/internal/infra/outbound/spider/price.go +++ b/internal/infra/outbound/spider/price.go @@ -5,10 +5,9 @@ import ( "encoding/json" "errors" "fmt" - "log" "net/http" - "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) const ( @@ -23,14 +22,14 @@ func (s *SpiderClient) GetPriceInfoWithContext(ctx context.Context, regionName s marshalledBody, err := json.Marshal(body) if err != nil { - log.Println("marshalling body error;", err) + log.Error().Msgf("marshalling body error; %v", err) return cloudPriceData, err } resBytes, err := s.requestWithContext(ctx, http.MethodPost, url, marshalledBody, nil) if err != nil { - utils.LogError("error sending get price info data request:", err) + log.Error().Msgf("error sending get price info data request; %v", err) return cloudPriceData, fmt.Errorf("failed to send request: %w", err) } @@ -38,7 +37,7 @@ func (s *SpiderClient) GetPriceInfoWithContext(ctx context.Context, regionName s err = json.Unmarshal(resBytes, &cloudPriceData) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return cloudPriceData, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -57,14 +56,14 @@ func (s *SpiderClient) GetCostWithResourceWithContext(ctx context.Context, body marshalledBody, err := json.Marshal(body) if err != nil { - log.Println("marshalling body error;", err) + log.Error().Msgf("marshalling body error; %v", err) return &costWithResourceRes, err } resBytes, err := s.requestWithContext(ctx, http.MethodPost, url, marshalledBody, nil) if err != nil { - utils.LogError("error sending get cost info data request:", err) + log.Error().Msgf("error sending get cost info data request; %v", err) return &costWithResourceRes, fmt.Errorf("failed to send request: %w", err) } @@ -72,7 +71,7 @@ func (s *SpiderClient) GetCostWithResourceWithContext(ctx context.Context, body err = json.Unmarshal(resBytes, &anycallRes) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return &costWithResourceRes, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -83,7 +82,7 @@ func (s *SpiderClient) GetCostWithResourceWithContext(ctx context.Context, body err = json.Unmarshal([]byte(anycallRes.OKeyValueList[0].Value), &costWithResourceRes) if err != nil { - utils.LogError("error unmarshaling :", err) + log.Error().Msgf("error unmarshaling; %v", err) return &costWithResourceRes, fmt.Errorf("failed to unmarshal response body: %w", err) } diff --git a/internal/infra/outbound/spider/spider_client.go b/internal/infra/outbound/spider/spider_client.go index ba97371..69a446c 100644 --- a/internal/infra/outbound/spider/spider_client.go +++ b/internal/infra/outbound/spider/spider_client.go @@ -11,7 +11,7 @@ import ( "strings" "github.com/cloud-barista/cm-ant/internal/config" - "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) var ( @@ -62,7 +62,7 @@ func (s *SpiderClient) withUrl(endpoint string) string { 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) + log.Error().Msgf("Failed to create request with context; %v", err) return nil, fmt.Errorf("failed to create request: %w", err) } @@ -71,17 +71,17 @@ func (s *SpiderClient) requestWithContext(ctx context.Context, method, url strin req.Header.Add(k, v) } - utils.LogInfof("Sending request to client with endpoint [%s - %s]\n", method, url) + log.Info().Msgf("Sending request to client with endpoint [%s - %s]\n", method, url) resp, err := s.client.Do(req) if err != nil { - utils.LogErrorf("Failed to send request: %v", err) + log.Error().Msgf("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 || resp.StatusCode >= http.StatusBadRequest { rb, _ := io.ReadAll(resp.Body) - utils.LogErrorf("Unexpected status code: %d, response: %s", resp.StatusCode, string(rb)) + log.Error().Msgf("Unexpected status code: %d, response: %s", resp.StatusCode, string(rb)) if resp.StatusCode == http.StatusNotFound { return nil, ErrNotFound @@ -96,11 +96,11 @@ func (s *SpiderClient) requestWithContext(ctx context.Context, method, url strin rb, err := io.ReadAll(resp.Body) if err != nil { - utils.LogErrorf("Failed to read response body: %v", err) + log.Error().Msgf("Failed to read response body; %v", err) return nil, fmt.Errorf("failed to read response body: %w", err) } - utils.LogInfo("Request with context completed successfully.") + log.Info().Msg("Request with context completed successfully.") return rb, nil } @@ -114,7 +114,7 @@ func (s *SpiderClient) ReadyzWithContext(ctx context.Context) error { _, err := s.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) if err != nil { - utils.LogError("error sending tumblebug readyz request:", err) + log.Error().Msgf("error sending tumblebug readyz request; %v", err) return err } diff --git a/internal/infra/outbound/tumblebug/mci.go b/internal/infra/outbound/tumblebug/mci.go index 14d4593..2930622 100644 --- a/internal/infra/outbound/tumblebug/mci.go +++ b/internal/infra/outbound/tumblebug/mci.go @@ -7,7 +7,7 @@ import ( "fmt" "net/http" - "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) func (t *TumblebugClient) GetMciWithContext(ctx context.Context, nsId, mciId string) (MciRes, error) { @@ -17,7 +17,7 @@ func (t *TumblebugClient) GetMciWithContext(ctx context.Context, nsId, mciId str resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) if err != nil { - utils.LogError("error sending get mci request:", err) + log.Error().Msgf("error sending get mci request; %v", err) if errors.Is(err, ErrInternalServerError) { return mciObject, ErrNotFound @@ -28,7 +28,7 @@ func (t *TumblebugClient) GetMciWithContext(ctx context.Context, nsId, mciId str err = json.Unmarshal(resBytes, &mciObject) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return mciObject, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -41,14 +41,14 @@ func (t *TumblebugClient) CommandToMciWithContext(ctx context.Context, nsId, mci marshalledBody, err := json.Marshal(body) if err != nil { - utils.LogError("error marshaling request body:", err) + log.Error().Msgf("error marshaling request body; %v", err) return "", err } resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodPost, url, marshalledBody) if err != nil { - utils.LogError("error sending command to mci request:", err) + log.Error().Msgf("error sending command to mci request; %v", err) return "", fmt.Errorf("failed to send request: %w", err) } @@ -63,14 +63,14 @@ func (t *TumblebugClient) CommandToVmWithContext(ctx context.Context, nsId, mciI marshalledBody, err := json.Marshal(body) if err != nil { - utils.LogError("error marshaling request body:", err) + log.Error().Msgf("error marshaling request body; %v", err) return "", err } resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodPost, url, marshalledBody) if err != nil { - utils.LogError("error sending command to vm request:", err) + log.Error().Msgf("error sending command to vm request; %v", err) return "", fmt.Errorf("failed to send request: %w", err) } @@ -86,14 +86,14 @@ func (t *TumblebugClient) GetNsWithContext(ctx context.Context, nsId string) (Ge resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) if err != nil { - utils.LogError("error sending get mci request:", err) + log.Error().Msgf("error sending get mci request; %v", err) return nsRes, fmt.Errorf("failed to send request: %w", err) } err = json.Unmarshal(resBytes, &nsRes) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return nsRes, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -106,21 +106,21 @@ func (t *TumblebugClient) GetRecommendVmWithContext(ctx context.Context, body Re marshalledBody, err := json.Marshal(body) if err != nil { - utils.LogError("error marshaling request body:", err) + log.Error().Msgf("error marshaling request body; %v", err) return res, err } resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodPost, url, marshalledBody) if err != nil { - utils.LogError("error sending get recommend vm request:", err) + log.Error().Msgf("error sending get recommend vm request; %v", err) return res, fmt.Errorf("failed to send request: %w", err) } err = json.Unmarshal(resBytes, &res) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return res, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -132,14 +132,14 @@ func (t *TumblebugClient) CreateNsWithContext(ctx context.Context, body CreateNs marshalledBody, err := json.Marshal(body) if err != nil { - utils.LogError("error marshaling request body:", err) + log.Error().Msgf("error marshaling request body; %v", err) return err } _, err = t.requestWithBaseAuthWithContext(ctx, http.MethodPost, url, marshalledBody) if err != nil { - utils.LogError("error sending create ns request:", err) + log.Error().Msgf("error sending create ns request; %v", err) return fmt.Errorf("failed to send request: %w", err) } @@ -152,21 +152,21 @@ func (t *TumblebugClient) DynamicVmWithContext(ctx context.Context, nsId, mciId marshalledBody, err := json.Marshal(body) if err != nil { - utils.LogError("error marshaling request body:", err) + log.Error().Msgf("error marshaling request body; %v", err) return res, err } resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodPost, url, marshalledBody) if err != nil { - utils.LogError("error sending dynamic vm request:", err) + log.Error().Msgf("error sending dynamic vm request; %v", err) return res, fmt.Errorf("failed to send request: %w", err) } err = json.Unmarshal(resBytes, &res) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return res, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -179,21 +179,21 @@ func (t *TumblebugClient) DynamicMciWithContext(ctx context.Context, nsId string marshalledBody, err := json.Marshal(body) if err != nil { - utils.LogError("error marshaling request body:", err) + log.Error().Msgf("error marshaling request body; %v", err) return res, err } resBytes, err := t.requestWithBaseAuthWithContext(ctx, http.MethodPost, url, marshalledBody) if err != nil { - utils.LogError("error sending dynamic mci request:", err) + log.Error().Msgf("error sending dynamic mci request; %v", err) return res, fmt.Errorf("failed to send request: %w", err) } err = json.Unmarshal(resBytes, &res) if err != nil { - utils.LogError("error unmarshaling response body:", err) + log.Error().Msgf("error unmarshaling response body; %v", err) return res, fmt.Errorf("failed to unmarshal response body: %w", err) } @@ -208,7 +208,7 @@ func (t *TumblebugClient) ControlLifecycleWithContext(ctx context.Context, nsId, _, err := t.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) if err != nil { - utils.LogError("error sending control lifecycle request:", err) + log.Error().Msgf("error sending control lifecycle request; %v", err) return fmt.Errorf("failed to send request: %w", err) } @@ -224,7 +224,7 @@ func (t *TumblebugClient) DeleteAllMciWithContext(ctx context.Context, nsId stri _, err := t.requestWithBaseAuthWithContext(ctx, http.MethodDelete, url, nil) if err != nil { - utils.LogError("error sending delete all mci request:", err) + log.Error().Msgf("error sending delete all mci request; %v", err) return fmt.Errorf("failed to send request: %w", err) } @@ -239,7 +239,7 @@ func (t *TumblebugClient) DeleteAllResourcesWithContext(ctx context.Context, nsI _, err := t.requestWithBaseAuthWithContext(ctx, http.MethodDelete, url, nil) if err != nil { - utils.LogError("error sending delete all mci request:", err) + log.Error().Msgf("error sending delete all mci request; %v", err) return fmt.Errorf("failed to send request: %w", err) } diff --git a/internal/infra/outbound/tumblebug/tumblebug_client.go b/internal/infra/outbound/tumblebug/tumblebug_client.go index 145ded1..9983bfa 100644 --- a/internal/infra/outbound/tumblebug/tumblebug_client.go +++ b/internal/infra/outbound/tumblebug/tumblebug_client.go @@ -7,12 +7,11 @@ import ( "errors" "fmt" "io" - "log" "net/http" "strings" "github.com/cloud-barista/cm-ant/internal/config" - "github.com/cloud-barista/cm-ant/internal/utils" + "github.com/rs/zerolog/log" ) var ( @@ -58,7 +57,7 @@ func (t *TumblebugClient) withUrl(endpoint string) string { func (t *TumblebugClient) 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 { - log.Printf("[ERROR] Failed to create request with context: %v", err) + log.Error().Msgf("failed to create request with context: %v", err) return nil, fmt.Errorf("failed to create request: %w", err) } @@ -67,17 +66,17 @@ func (t *TumblebugClient) requestWithContext(ctx context.Context, method, url st req.Header.Add(k, v) } - utils.LogInfof("Sending request to client with endpoint [%s - %s]\n", method, url) + log.Info().Msgf("Sending request to client with endpoint [%s - %s]", method, url) resp, err := t.client.Do(req) if err != nil { - log.Printf("[ERROR] Failed to send request: %v", err) + log.Error().Msgf("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 || resp.StatusCode >= http.StatusBadRequest { rb, _ := io.ReadAll(resp.Body) - log.Printf("[ERROR] Unexpected status code: %d, response: %s", resp.StatusCode, string(rb)) + log.Error().Msgf("unexpected status code: %d, response: %s", resp.StatusCode, string(rb)) if resp.StatusCode == http.StatusNotFound { return nil, ErrNotFound @@ -92,11 +91,11 @@ func (t *TumblebugClient) requestWithContext(ctx context.Context, method, url st rb, err := io.ReadAll(resp.Body) if err != nil { - log.Printf("[ERROR] Failed to read response body: %v", err) + log.Error().Msgf("failed to read response body: %v", err) return nil, fmt.Errorf("failed to read response body: %w", err) } - utils.LogInfo("Request with context completed successfully.") + log.Info().Msg("Request with context completed successfully.") return rb, nil } @@ -110,7 +109,7 @@ func (t *TumblebugClient) ReadyzWithContext(ctx context.Context) error { _, err := t.requestWithBaseAuthWithContext(ctx, http.MethodGet, url, nil) if err != nil { - utils.LogError("error sending tumblebug readyz request:", err) + log.Error().Msgf("error sending tumblebug readyz request; %v", err) return err } diff --git a/internal/render/templates.go b/internal/render/templates.go index dcb904b..f527bc3 100644 --- a/internal/render/templates.go +++ b/internal/render/templates.go @@ -4,12 +4,12 @@ import ( "errors" "fmt" "io" - "log" "path/filepath" "text/template" "github.com/cloud-barista/cm-ant/internal/utils" "github.com/labstack/echo/v4" + "github.com/rs/zerolog/log" ) type Template struct { //the map[key] in key means 'Your html file name' @@ -20,7 +20,7 @@ func NewTemplate() *Template { templates, err := generateTemplateCache() if err != nil { - log.Fatal("template parsing error", err) + log.Error().Msgf("template parsing error; %v", err) } return &Template{ diff --git a/internal/utils/bash.go b/internal/utils/bash.go index f2b23a0..3235ab1 100644 --- a/internal/utils/bash.go +++ b/internal/utils/bash.go @@ -1,9 +1,10 @@ package utils import ( - "log" "os" "os/exec" + + "github.com/rs/zerolog/log" ) func InlineCmd(cmdStr string) error { @@ -11,12 +12,12 @@ func InlineCmd(cmdStr string) error { out, err := cmd.CombinedOutput() if err != nil { - log.Println("error while execute bash call,", err) - log.Println(string(out)) + log.Error().Msgf("error while execute bash call; %v", err) + log.Error().Msg(string(out)) return err } - log.Println(string(out)) + log.Info().Msgf(string(out)) return nil } @@ -30,12 +31,12 @@ func Script(scriptPath string, envs []string, args ...string) error { out, err := cmd.CombinedOutput() if err != nil { - log.Println("error while execute bash call,", err) - log.Println(string(out)) + log.Error().Msgf("error while execute bash call; %v", err) + log.Error().Msgf(string(out)) return err } - log.Println(string(out)) + log.Info().Msgf(string(out)) return nil } @@ -45,7 +46,7 @@ func InlineCmdAsync(cmdStr string) error { var err error if err = cmd.Start(); err != nil { - log.Println("error while async bash call:", err) + log.Error().Msgf("error while async bash call; %v", err) return err } diff --git a/internal/utils/ioes.go b/internal/utils/ioes.go index 5a191b0..73ae165 100644 --- a/internal/utils/ioes.go +++ b/internal/utils/ioes.go @@ -4,9 +4,10 @@ import ( "encoding/csv" "fmt" "io" - "log" "os" "strings" + + "github.com/rs/zerolog/log" ) func WritePropertiesFile(filePath string, properties map[string]interface{}, emptyOmit bool) error { @@ -52,7 +53,7 @@ func CreateFolder(filePath string) error { func ReadCSV(filename string) (*[][]string, error) { file, err := os.Open(filename) if err != nil { - LogErrorf("can not opent files: %s; %s", filename, err) + log.Error().Msgf("can not opent files: %s; %s", filename, err) return nil, err } defer file.Close() @@ -68,7 +69,7 @@ func ReadCSV(filename string) (*[][]string, error) { return &parsedCsv, nil } - log.Println(err) + log.Error().Msgf("failed to read csv file from path %s; %v", filename, err) break } @@ -83,10 +84,10 @@ func ExistCheck(path string) bool { if err != nil { if os.IsNotExist(err) { - LogErrorf("file / folder does not exist: %s", path) + log.Error().Msgf("file / folder does not exist: %s", path) } else { - LogError(err) + log.Error().Msg(err.Error()) } return false @@ -102,7 +103,7 @@ func ExistCheck(path string) bool { func ReadToString(path string) (string, error) { data, err := os.ReadFile(path) if err != nil { - log.Println("file doesn't exist on correct path") + log.Error().Msgf("file doesn't exist on correct path; %v", err) return "", err } diff --git a/internal/utils/log.go b/internal/utils/log.go index ce685bb..243eab4 100644 --- a/internal/utils/log.go +++ b/internal/utils/log.go @@ -1,77 +1,77 @@ package utils -import ( - "fmt" - "log" -) +// import ( +// "fmt" +// "log" +// ) -const ( - colorReset = "\033[0m" - colorRed = "\033[31m" - colorGreen = "\033[32m" - colorYellow = "\033[33m" -) +// const ( +// colorReset = "\033[0m" +// colorRed = "\033[31m" +// colorGreen = "\033[32m" +// colorYellow = "\033[33m" +// ) -// LogLevel type to represent different log levels -type LogLevel string +// // LogLevel type to represent different log levels +// type LogLevel string -const ( - Info LogLevel = "INFO" - Warn LogLevel = "WARN" - Error LogLevel = "ERROR" -) +// const ( +// Info LogLevel = "INFO" +// Warn LogLevel = "WARN" +// Error LogLevel = "ERROR" +// ) -// Utility function for logging messages with color -func Log(level LogLevel, v ...interface{}) { - var color string - switch level { - case Info: - color = colorGreen - case Warn: - color = colorYellow - case Error: - color = colorRed - default: - color = colorReset - } - log.Println(color+fmt.Sprintf("[%s]", level)+colorReset, fmt.Sprint(v...)) -} +// // Utility function for logging messages with color +// func Log(level LogLevel, v ...interface{}) { +// var color string +// switch level { +// case Info: +// color = colorGreen +// case Warn: +// color = colorYellow +// case Error: +// color = colorRed +// default: +// color = colorReset +// } +// log.Println(color+fmt.Sprintf("[%s]", level)+colorReset, fmt.Sprint(v...)) +// } -func Logf(level LogLevel, format string, v ...interface{}) { - var color string - switch level { - case Info: - color = colorGreen - case Error: - color = colorRed - default: - color = colorReset - } - content := fmt.Sprintf(format, v...) - log.Println(color+fmt.Sprintf("[%s]", level)+colorReset, content) -} +// func Logf(level LogLevel, format string, v ...interface{}) { +// var color string +// switch level { +// case Info: +// color = colorGreen +// case Error: +// color = colorRed +// default: +// color = colorReset +// } +// content := fmt.Sprintf(format, v...) +// log.Println(color+fmt.Sprintf("[%s]", level)+colorReset, content) +// } -// Wrapper functions for specific log levels -func LogInfo(v ...interface{}) { - Log(Info, v...) -} +// // Wrapper functions for specific log levels +// func LogInfo(v ...interface{}) { +// Log(Info, v...) +// } -func LogInfof(format string, v ...interface{}) { - Logf(Info, format, v...) -} +// func LogInfof(format string, v ...interface{}) { +// Logf(Info, format, v...) +// } -func LogWarn(v ...interface{}) { - Log(Warn, v...) -} +// func LogWarn(v ...interface{}) { +// Log(Warn, v...) +// } -func LogWarnf(format string, v ...interface{}) { - Logf(Warn, format, v...) -} +// func LogWarnf(format string, v ...interface{}) { +// Logf(Warn, format, v...) +// } -func LogError(v ...interface{}) { - Log(Error, v...) -} +// func LogError(v ...interface{}) { +// Log(Error, v...) +// } -func LogErrorf(format string, v ...interface{}) { - Logf(Error, format, v...) -} +// func LogErrorf(format string, v ...interface{}) { +// Logf(Error, format, v...) +// } diff --git a/internal/utils/ssh.go b/internal/utils/ssh.go index 3386882..2fcf122 100644 --- a/internal/utils/ssh.go +++ b/internal/utils/ssh.go @@ -8,12 +8,12 @@ import ( "errors" "fmt" "io" - "log" "net" "os" "github.com/melbahja/goph" "github.com/pkg/sftp" + "github.com/rs/zerolog/log" "golang.org/x/crypto/ssh" ) @@ -43,7 +43,7 @@ func AddToKnownHost(pemFilePath, publicIp, username string) error { return err } - log.Println(string(out)) + log.Info().Msg(string(out)) return nil } diff --git a/internal/utils/worker.go b/internal/utils/worker.go index 2e7fa40..12f49e3 100644 --- a/internal/utils/worker.go +++ b/internal/utils/worker.go @@ -2,10 +2,11 @@ package utils import ( "fmt" - "log" "os" "strconv" "time" + + "github.com/rs/zerolog/log" ) type Worker interface { @@ -29,17 +30,16 @@ func NewWorker(interval time.Duration) Worker { } func (w *tempFileRemoveWorker) Run() { - - log.Println("TempFileRemoveWorker Started") + log.Info().Msg("TempFileRemoveWorker Started") for { select { case <-w.ShutdownChannel: - log.Println("worker shut down..") + log.Info().Msg("worker shut down..") w.ShutdownChannel <- "Down" return default: - log.Println("worker actions called") + log.Info().Msg("worker actions called") } w.Action()