diff --git a/api/docs.go b/api/docs.go index 512edb3..21fe804 100644 --- a/api/docs.go +++ b/api/docs.go @@ -833,6 +833,493 @@ const docTemplate = `{ } } }, + "/tr/{trId}/message-broker": { + "get": { + "description": "Get resource info of Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Get resource info of Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "refined", + "description": "Resource info by detail (refined, raw)", + "name": "detail", + "in": "query" + }, + { + "type": "string", + "description": "custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + }, + "post": { + "description": "Create Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Create Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + }, + "delete": { + "description": "Destroy Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Destroy Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/env": { + "post": { + "description": "Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ Broker (ActiveMQ))", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ Broker (ActiveMQ))", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "enum": [ + "aws" + ], + "type": "string", + "default": "aws", + "description": "Provider", + "name": "provider", + "in": "query" + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + }, + "delete": { + "description": "Clear the entire directory and configuration files", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Clear the entire directory and configuration files", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "enum": [ + "force" + ], + "type": "string", + "default": "", + "description": "Action", + "name": "action", + "in": "query" + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/infracode": { + "post": { + "description": "Create the infracode for Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Create the infracode for Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "description": "Parameters of infracode for Message Broker", + "name": "ParamsForInfracode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.CreateInfracodeOfMessageBrokerRequest" + } + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/plan": { + "post": { + "description": "Check and show changes by the current infracode", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Check and show changes by the current infracode", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/request/{requestId}": { + "get": { + "description": "Check the status of a specific request by its ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Check the status of a specific request by its ID", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Request ID", + "name": "requestId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, "/tr/{trId}/object-storage": { "get": { "description": "Get resource info of Object Storage", @@ -2858,11 +3345,19 @@ const docTemplate = `{ } } }, + "model.CreateInfracodeOfMessageBrokerRequest": { + "type": "object", + "properties": { + "tfVars": { + "$ref": "#/definitions/model.TfVarsMessageBroker" + } + } + }, "model.CreateInfracodeOfObjectStorageRequest": { "type": "object", "properties": { "tfVars": { - "$ref": "#/definitions/model.TfVarsObjectStorage" + "$ref": "#/definitions/model.TfVarsMessageBroker" } } }, @@ -3017,16 +3512,16 @@ const docTemplate = `{ } } }, - "model.TfVarsObjectStorage": { + "model.TfVarsMessageBroker": { "type": "object", "properties": { "csp_region": { "type": "string", "example": "ap-northeast-2" }, - "csp_resource_group": { + "csp_vnet_id": { "type": "string", - "example": "koreacentral" + "example": "vpc-12345678" }, "terrarium_id": { "type": "string", diff --git a/api/swagger.json b/api/swagger.json index 6d748ae..cd47031 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -827,6 +827,493 @@ } } }, + "/tr/{trId}/message-broker": { + "get": { + "description": "Get resource info of Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Get resource info of Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "refined", + "description": "Resource info by detail (refined, raw)", + "name": "detail", + "in": "query" + }, + { + "type": "string", + "description": "custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + }, + "post": { + "description": "Create Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Create Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + }, + "delete": { + "description": "Destroy Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Destroy Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/env": { + "post": { + "description": "Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ Broker (ActiveMQ))", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ Broker (ActiveMQ))", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "enum": [ + "aws" + ], + "type": "string", + "default": "aws", + "description": "Provider", + "name": "provider", + "in": "query" + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + }, + "delete": { + "description": "Clear the entire directory and configuration files", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Clear the entire directory and configuration files", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "enum": [ + "force" + ], + "type": "string", + "default": "", + "description": "Action", + "name": "action", + "in": "query" + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/infracode": { + "post": { + "description": "Create the infracode for Message Broker", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Create the infracode for Message Broker", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "description": "Parameters of infracode for Message Broker", + "name": "ParamsForInfracode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.CreateInfracodeOfMessageBrokerRequest" + } + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/plan": { + "post": { + "description": "Check and show changes by the current infracode", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Check and show changes by the current infracode", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Custom request ID", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, + "/tr/{trId}/message-broker/request/{requestId}": { + "get": { + "description": "Check the status of a specific request by its ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Message Broker] Operations" + ], + "summary": "Check the status of a specific request by its ID", + "parameters": [ + { + "type": "string", + "default": "tr01", + "description": "Terrarium ID", + "name": "trId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Request ID", + "name": "requestId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.Response" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } + }, "/tr/{trId}/object-storage": { "get": { "description": "Get resource info of Object Storage", @@ -2852,11 +3339,19 @@ } } }, + "model.CreateInfracodeOfMessageBrokerRequest": { + "type": "object", + "properties": { + "tfVars": { + "$ref": "#/definitions/model.TfVarsMessageBroker" + } + } + }, "model.CreateInfracodeOfObjectStorageRequest": { "type": "object", "properties": { "tfVars": { - "$ref": "#/definitions/model.TfVarsObjectStorage" + "$ref": "#/definitions/model.TfVarsMessageBroker" } } }, @@ -3011,16 +3506,16 @@ } } }, - "model.TfVarsObjectStorage": { + "model.TfVarsMessageBroker": { "type": "object", "properties": { "csp_region": { "type": "string", "example": "ap-northeast-2" }, - "csp_resource_group": { + "csp_vnet_id": { "type": "string", - "example": "koreacentral" + "example": "vpc-12345678" }, "terrarium_id": { "type": "string", diff --git a/api/swagger.yaml b/api/swagger.yaml index 021bb13..3c6ba26 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -71,10 +71,15 @@ definitions: tfVars: $ref: '#/definitions/model.TfVarsGcpAzureVpnTunnel' type: object + model.CreateInfracodeOfMessageBrokerRequest: + properties: + tfVars: + $ref: '#/definitions/model.TfVarsMessageBroker' + type: object model.CreateInfracodeOfObjectStorageRequest: properties: tfVars: - $ref: '#/definitions/model.TfVarsObjectStorage' + $ref: '#/definitions/model.TfVarsMessageBroker' type: object model.CreateInfracodeOfSqlDbRequest: properties: @@ -185,13 +190,13 @@ definitions: example: "" type: string type: object - model.TfVarsObjectStorage: + model.TfVarsMessageBroker: properties: csp_region: example: ap-northeast-2 type: string - csp_resource_group: - example: koreacentral + csp_vnet_id: + example: vpc-12345678 type: string terrarium_id: example: "" @@ -816,6 +821,335 @@ paths: summary: Read a terrarium tags: - '[Terrarium] An environment to enrich the multi-cloud infrastructure' + /tr/{trId}/message-broker: + delete: + consumes: + - application/json + description: Destroy Message Broker + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - description: Custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Destroy Message Broker + tags: + - '[Message Broker] Operations' + get: + consumes: + - application/json + description: Get resource info of Message Broker + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - default: refined + description: Resource info by detail (refined, raw) + in: query + name: detail + type: string + - description: custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Get resource info of Message Broker + tags: + - '[Message Broker] Operations' + post: + consumes: + - application/json + description: Create Message Broker + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - description: Custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Create Message Broker + tags: + - '[Message Broker] Operations' + /tr/{trId}/message-broker/env: + delete: + consumes: + - application/json + description: Clear the entire directory and configuration files + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - default: "" + description: Action + enum: + - force + in: query + name: action + type: string + - description: Custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Clear the entire directory and configuration files + tags: + - '[Message Broker] Operations' + post: + consumes: + - application/json + description: Initialize a multi-cloud terrarium for Message Broker (e.g., AWS + MQ Broker (ActiveMQ)) + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - default: aws + description: Provider + enum: + - aws + in: query + name: provider + type: string + - description: Custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ + Broker (ActiveMQ)) + tags: + - '[Message Broker] Operations' + /tr/{trId}/message-broker/infracode: + post: + consumes: + - application/json + description: Create the infracode for Message Broker + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - description: Parameters of infracode for Message Broker + in: body + name: ParamsForInfracode + required: true + schema: + $ref: '#/definitions/model.CreateInfracodeOfMessageBrokerRequest' + - description: Custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Create the infracode for Message Broker + tags: + - '[Message Broker] Operations' + /tr/{trId}/message-broker/plan: + post: + consumes: + - application/json + description: Check and show changes by the current infracode + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - description: Custom request ID + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Check and show changes by the current infracode + tags: + - '[Message Broker] Operations' + /tr/{trId}/message-broker/request/{requestId}: + get: + consumes: + - application/json + description: Check the status of a specific request by its ID + parameters: + - default: tr01 + description: Terrarium ID + in: path + name: trId + required: true + type: string + - description: Request ID + in: path + name: requestId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.Response' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.Response' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/model.Response' + summary: Check the status of a specific request by its ID + tags: + - '[Message Broker] Operations' /tr/{trId}/object-storage: delete: consumes: diff --git a/pkg/api/rest/handler/message-broker.go b/pkg/api/rest/handler/message-broker.go new file mode 100644 index 0000000..b184de3 --- /dev/null +++ b/pkg/api/rest/handler/message-broker.go @@ -0,0 +1,857 @@ +/* +Copyright 2019 The Cloud-Barista Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package handler + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "strings" + + "github.com/cloud-barista/mc-terrarium/pkg/api/rest/model" + "github.com/cloud-barista/mc-terrarium/pkg/config" + "github.com/cloud-barista/mc-terrarium/pkg/terrarium" + "github.com/cloud-barista/mc-terrarium/pkg/tofu" + "github.com/labstack/echo/v4" + "github.com/rs/zerolog/log" + "github.com/tidwall/gjson" +) + +var validProvidersForMessageBroker = map[string]bool{ + "aws": true, + // "azure": true, + // "gcp": true, + // "ncp": true, +} + +func getValidProvidersForMessageBroker() []string { + validProviders := []string{} + for provider := range validProvidersForMessageBroker { + if validProvidersForMessageBroker[provider] { + validProviders = append(validProviders, provider) + } + } + return validProviders +} + +// InitEnvForMessageBroker godoc +// @Summary Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ Broker (ActiveMQ)) +// @Description Initialize a multi-cloud terrarium for Message Broker (e.g., AWS MQ Broker (ActiveMQ)) +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param provider query string false "Provider" Enums(aws) default(aws) +// @Param x-request-id header string false "Custom request ID" +// @Success 201 {object} model.Response "Created" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker/env [post] +func InitEnvForMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + provider := c.QueryParam("provider") + if provider == "" { + err := fmt.Errorf("invalid request, provider is required") + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + if !validProvidersForMessageBroker[provider] { + providerList := getValidProviderListForMessageBroker() + err := fmt.Errorf("invalid request, provider must be one of %v", providerList) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + // Get the request ID + reqId := c.Response().Header().Get(echo.HeaderXRequestID) + + // Set the enrichments + enrichments := "message-broker" + + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + trInfo.Enrichments = enrichments + err = terrarium.UpdateTerrariumInfo(trInfo) + if err != nil { + err2 := fmt.Errorf("failed to update terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Create a working directory for the terrarium + projectRoot := config.Terrarium.Root + workingDir := projectRoot + "/.terrarium/" + trId + "/" + enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err := os.MkdirAll(workingDir, 0755) + if err != nil { + err2 := fmt.Errorf("failed to create a working directory") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + } + + // Copy template files to the working directory (overwrite) + templateTfsPath := projectRoot + "/templates/" + enrichments + "/" + provider + + err = tofu.CopyFiles(templateTfsPath, workingDir) + if err != nil { + err2 := fmt.Errorf("failed to copy template files to working directory") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + if provider == "gcp" { + // Always overwrite credential-gcp.json + credentialPath := workingDir + "/credential-gcp.json" + + err = tofu.CopyGCPCredentials(credentialPath) + if err != nil { + err2 := fmt.Errorf("failed to copy gcp credentials") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + } + + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId}/message-broker + // init: subcommand + ret, err := tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "init") + if err != nil { + err2 := fmt.Errorf("failed to initialize an infrastructure terrarium") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + res := model.Response{ + Success: true, + Message: "the infrastructure terrarium is successfully initialized", + Detail: ret, + } + + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusCreated, res) +} + +// ClearEnvOfMessageBroker godoc +// @Summary Clear the entire directory and configuration files +// @Description Clear the entire directory and configuration files +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param action query string false "Action" Enums(force) default() +// @Param x-request-id header string false "Custom request ID" +// @Success 200 {object} model.Response "OK" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker/env [delete] +func ClearEnvOfMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + projectRoot := config.Terrarium.Root + + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Check if the working directory exists + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + err = os.RemoveAll(workingDir) + if err != nil { + err2 := fmt.Errorf("failed to remove working directory and all configuration files") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + text := "successfully remove all in the working directory" + res := model.Response{ + Success: true, + Message: text, + } + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusOK, res) +} + +// CreateInfracodeForMessageBroker godoc +// @Summary Create the infracode for Message Broker +// @Description Create the infracode for Message Broker +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param ParamsForInfracode body model.CreateInfracodeOfMessageBrokerRequest true "Parameters of infracode for Message Broker" +// @Param x-request-id header string false "Custom request ID" +// @Success 201 {object} model.Response "Created" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker/infracode [post] +func CreateInfracodeForMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + req := new(model.CreateInfracodeOfMessageBrokerRequest) + if err := c.Bind(req); err != nil { + err2 := fmt.Errorf("invalid request format, %v", err) + log.Warn().Err(err).Msg("invalid request format") + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + log.Debug().Msgf("%+v", req) // debug + + projectRoot := config.Terrarium.Root + + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Check if the working directory exists + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // Save the tfVars to a file + tfVarsPath := workingDir + "/terraform.tfvars.json" + // Note + // Terraform also automatically loads a number of variable definitions files + // if they are present: + // - Files named exactly terraform.tfvars or terraform.tfvars.json. + // - Any files with names ending in .auto.tfvars or .auto.tfvars.json. + + if req.TfVars.TerrariumID == "" { + log.Warn().Msgf("terrarium ID is not set, Use path param: %s", trId) // warn + req.TfVars.TerrariumID = trId + } + + err = tofu.SaveTfVarsToFile(req.TfVars, tfVarsPath) + if err != nil { + err2 := fmt.Errorf("failed to save tfVars to a file") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + res := model.Response{ + Success: true, + Message: "the infracode for a message broker is successfully created", + } + + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusCreated, res) +} + +// CheckInfracodeForMessageBroker godoc +// @Summary Check and show changes by the current infracode +// @Description Check and show changes by the current infracode +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param x-request-id header string false "Custom request ID" +// @Success 200 {object} model.Response "OK" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker/plan [post] +func CheckInfracodeForMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + // Get the request ID + reqId := c.Response().Header().Get(echo.HeaderXRequestID) + + projectRoot := config.Terrarium.Root + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Check if the working directory exists + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId}/message-broker + // subcommand: plan + ret, err := tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "plan") + if err != nil { + err2 := fmt.Errorf("returned: %s", ret) + log.Error().Err(err).Msg(err2.Error()) // error + res := model.Response{ + Success: false, + Message: err2.Error(), + Detail: ret, + } + return c.JSON(http.StatusInternalServerError, res) + } + res := model.Response{ + Success: true, + Message: "the infracode checking process is successfully completed", + Detail: ret, + } + + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusOK, res) +} + +// CreateMessageBroker godoc +// @Summary Create Message Broker +// @Description Create Message Broker +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param x-request-id header string false "Custom request ID" +// @Success 200 {object} model.Response "OK" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker [post] +func CreateMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + // Get the request ID + reqId := c.Response().Header().Get(echo.HeaderXRequestID) + + projectRoot := config.Terrarium.Root + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Check if the working directory exists + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId}/message-broker + // subcommand: apply + _, err = tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "apply", "-auto-approve") + if err != nil { + err2 := fmt.Errorf("failed, previous request in progress") + log.Error().Err(err).Msg(err2.Error()) // error + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId}/message-broker + // show: subcommand + ret, err := tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "output", "-json", "message_broker_info") + if err != nil { + err2 := fmt.Errorf("failed to read resource info (detail: %s) specified as 'output' in the state file", "refined") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + var resourceInfo map[string]interface{} + err = json.Unmarshal([]byte(ret), &resourceInfo) + if err != nil { + log.Error().Err(err).Msg("") // error + res := model.Response{ + Success: false, + Message: "failed to unmarshal resource info", + } + return c.JSON(http.StatusInternalServerError, res) + } + + res := model.Response{ + Success: true, + Message: "refined read resource info (map)", + Object: resourceInfo, + } + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusOK, res) +} + +// GetResourceInfoOfMessageBroker godoc +// @Summary Get resource info of Message Broker +// @Description Get resource info of Message Broker +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param detail query string false "Resource info by detail (refined, raw)" default(refined) +// @Param x-request-id header string false "custom request ID" +// @Success 200 {object} model.Response "OK" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker [get] +func GetResourceInfoOfMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + // Use this struct like the enum + var DetailOptions = struct { + Refined string + Raw string + }{ + Refined: "refined", + Raw: "raw", + } + + // valid detail options + validDetailOptions := map[string]bool{ + DetailOptions.Refined: true, + DetailOptions.Raw: true, + } + + detail := c.QueryParam("detail") + detail = strings.ToLower(detail) + + if detail == "" || !validDetailOptions[detail] { + err := fmt.Errorf("invalid detail (%s), use the default (%s)", detail, DetailOptions.Refined) + log.Warn().Msg(err.Error()) + detail = DetailOptions.Refined + } + + // Get the request ID + reqId := c.Response().Header().Get(echo.HeaderXRequestID) + + projectRoot := config.Terrarium.Root + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Check if the working directory exists + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // Get the resource info by the detail option + switch detail { + case DetailOptions.Refined: + // Code for handling "refined" detail option + + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId}/message-broker + // show: subcommand + ret, err := tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "output", "-json", "message_broker_info") + if err != nil { + err2 := fmt.Errorf("failed to read resource info (detail: %s) specified as 'output' in the state file", DetailOptions.Refined) + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + var resourceInfo map[string]interface{} + err = json.Unmarshal([]byte(ret), &resourceInfo) + if err != nil { + log.Error().Err(err).Msg("") // error + res := model.Response{ + Success: false, + Message: "failed to unmarshal resource info", + } + return c.JSON(http.StatusInternalServerError, res) + } + + res := model.Response{ + Success: true, + Message: "refined read resource info (map)", + Object: resourceInfo, + } + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusOK, res) + + case DetailOptions.Raw: + // Code for handling "raw" detail option + + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId}/message-broker + // show: subcommand + // Get resource info from the state or plan file + ret, err := tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "show", "-json") + if err != nil { + err2 := fmt.Errorf("failed to read resource info (detail: %s) from the state or plan file", DetailOptions.Raw) + log.Error().Err(err).Msg(err2.Error()) // error + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // Parse the resource info + resourcesString := gjson.Get(ret, "values.root_module.resources").String() + if resourcesString == "" { + err2 := fmt.Errorf("could not find resource info (trId: %s)", trId) + log.Warn().Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusOK, res) + } + + var resourceInfoList []interface{} + err = json.Unmarshal([]byte(resourcesString), &resourceInfoList) + if err != nil { + log.Error().Err(err).Msg("") // error + res := model.Response{ + Success: false, + Message: "failed to unmarshal resource info", + } + return c.JSON(http.StatusInternalServerError, res) + } + + res := model.Response{ + Success: true, + Message: "raw resource info (list)", + List: resourceInfoList, + } + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusOK, res) + default: + err2 := fmt.Errorf("invalid detail option (%s)", detail) + log.Warn().Err(err2).Msg("") // warn + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } +} + +// DestroyMessageBroker godoc +// @Summary Destroy Message Broker +// @Description Destroy Message Broker +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param x-request-id header string false "Custom request ID" +// @Success 200 {object} model.Response "OK" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker [delete] +func DestroyMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + // Get the request ID + reqId := c.Response().Header().Get(echo.HeaderXRequestID) + + projectRoot := config.Terrarium.Root + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + // Check if the working directory exists + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + // Destroy the infrastructure + // global option to set working dir: -chdir=/home/ubuntu/dev/cloud-barista/mc-terrarium/.terrarium/{trId} + // subcommand: destroy + ret, err := tofu.ExecuteTofuCommand(trId, reqId, "-chdir="+workingDir, "destroy", "-auto-approve") + if err != nil { + err2 := fmt.Errorf("failed, previous request in progress") + log.Error().Err(err).Msg(err2.Error()) // error + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + res := model.Response{ + Success: true, + Message: fmt.Sprintf("the destroying process is successfully completed (trId: %s, enrichments: %s)", trId, trInfo.Enrichments), + Detail: ret, + } + + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusCreated, res) +} + +// GetRequestStatusOfMessageBroker godoc +// @Summary Check the status of a specific request by its ID +// @Description Check the status of a specific request by its ID +// @Tags [Message Broker] Operations +// @Accept json +// @Produce json +// @Param trId path string true "Terrarium ID" default(tr01) +// @Param requestId path string true "Request ID" +// @Success 200 {object} model.Response "OK" +// @Failure 400 {object} model.Response "Bad Request" +// @Failure 500 {object} model.Response "Internal Server Error" +// @Failure 503 {object} model.Response "Service Unavailable" +// @Router /tr/{trId}/message-broker/request/{requestId} [get] +func GetRequestStatusOfMessageBroker(c echo.Context) error { + + trId := c.Param("trId") + if trId == "" { + err := fmt.Errorf("invalid request, terrarium ID (trId: %s) is required", trId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + reqId := c.Param("requestId") + if reqId == "" { + err := fmt.Errorf("invalid request, request ID (requestId: %s) is required", reqId) + log.Warn().Msg(err.Error()) + res := model.Response{ + Success: false, + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + + projectRoot := config.Terrarium.Root + // Read and set the enrichments to terrarium information + trInfo, err := terrarium.ReadTerrariumInfo(trId) + if err != nil { + err2 := fmt.Errorf("failed to read terrarium information") + log.Error().Err(err).Msg(err2.Error()) + res := model.Response{Success: false, Message: err2.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + workingDir := projectRoot + "/.terrarium/" + trId + "/" + trInfo.Enrichments + if _, err := os.Stat(workingDir); os.IsNotExist(err) { + err2 := fmt.Errorf("working directory dose not exist") + log.Warn().Err(err).Msg(err2.Error()) + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + statusLogFile := fmt.Sprintf("%s/runningLogs/%s.log", workingDir, reqId) + + // Check the statusReport of the request + statusReport, err := tofu.GetRunningStatus(trId, statusLogFile) + if err != nil { + err2 := fmt.Errorf("failed to get the status of the request") + log.Error().Err(err).Msg(err2.Error()) // error + res := model.Response{ + Success: false, + Message: err2.Error(), + } + return c.JSON(http.StatusInternalServerError, res) + } + + res := model.Response{ + Success: true, + Message: "the status of a specific request", + Detail: statusReport, + } + + log.Debug().Msgf("%+v", res) // debug + + return c.JSON(http.StatusOK, res) +} diff --git a/pkg/api/rest/handler/object-storage.go b/pkg/api/rest/handler/object-storage.go index 98a5f51..4cf5661 100644 --- a/pkg/api/rest/handler/object-storage.go +++ b/pkg/api/rest/handler/object-storage.go @@ -29,6 +29,23 @@ import ( "github.com/tidwall/gjson" ) +var validProvidersForObjectStorage = map[string]bool{ + "aws": true, + "azure": true, + "gcp": true, + "ncp": true, +} + +func getValidProviderListForMessageBroker() []string { + validProviders := []string{} + for provider := range validProvidersForObjectStorage { + if validProvidersForObjectStorage[provider] { + validProviders = append(validProviders, provider) + } + } + return validProviders +} + // InitEnvForObjectStorage godoc // @Summary Initialize a multi-cloud terrarium for Object Storage (e.g., AWS S3 Bucket, Azure Blob Storage) // @Description Initialize a multi-cloud terrarium for Object Storage (e.g., AWS S3 Bucket, Azure Blob Storage) @@ -67,8 +84,9 @@ func InitEnvForObjectStorage(c echo.Context) error { return c.JSON(http.StatusBadRequest, res) } - if !validProvidersForSqlDb[provider] { - err := fmt.Errorf("invalid request, provider must be one of [aws, azure, gcp, ncpvpc]") + if !validProvidersForObjectStorage[provider] { + providerList := getValidProviderListForMessageBroker() + err := fmt.Errorf("invalid request, provider must be one of %v", providerList) log.Warn().Msg(err.Error()) res := model.Response{ Success: false, @@ -326,7 +344,7 @@ func CreateInfracodeForObjectStorage(c echo.Context) error { res := model.Response{ Success: true, - Message: "the infracode for SQL database is Successfully created", + Message: "the infracode for an object storage is successfully created", } log.Debug().Msgf("%+v", res) // debug diff --git a/pkg/api/rest/handler/sql-db.go b/pkg/api/rest/handler/sql-db.go index 456cd0f..1558a2d 100644 --- a/pkg/api/rest/handler/sql-db.go +++ b/pkg/api/rest/handler/sql-db.go @@ -333,7 +333,7 @@ func CreateInfracodeForSqlDb(c echo.Context) error { res := model.Response{ Success: true, - Message: "the infracode for SQL database is Successfully created", + Message: "the infracode for SQL database is successfully created", } log.Debug().Msgf("%+v", res) // debug diff --git a/pkg/api/rest/model/message-broker.go b/pkg/api/rest/model/message-broker.go new file mode 100644 index 0000000..f2bea88 --- /dev/null +++ b/pkg/api/rest/model/message-broker.go @@ -0,0 +1,44 @@ +package model + +// TfVarsMessageBroker represents the configuration structure based on the Terraform variables +type TfVarsMessageBroker struct { + TerrariumID string `json:"terrarium_id" default:"" example:""` + CSPRegion string `json:"csp_region" example:"ap-northeast-2"` + CSPVNetID string `json:"csp_vnet_id,omitempty" example:"vpc-12345678"` + // CSPResourceGroup string `json:"csp_resource_group,omitempty" example:"koreacentral"` +} + +// OutputMessageBrokerInfo represents the Message Broker information structure +type OutputMessageBrokerInfo struct { + Terrarium TerrariumInfo `json:"terrarium"` + MessageBrokerDetail MessageBrokerDetail `json:"message_broker_detail"` +} + +type MessageBrokerDetail struct { + // Basic Information + BrokerName string `json:"broker_name"` + BrokerID string `json:"broker_id"` + EngineType string `json:"engine_type"` + EngineVersion string `json:"engine_version"` + HostInstanceType string `json:"host_instance_type"` + DeploymentMode string `json:"deployment_mode"` + + // Connection Details + BrokerEndpoint string `json:"broker_endpoint"` + PubliclyAccessible bool `json:"publicly_accessible"` + + // Authentication + Username string `json:"username"` + + // Provider Specific Details + ProviderSpecificDetail ProviderSpecificMessageBrokerDetail `json:"provider_specific_detail"` +} + +type ProviderSpecificMessageBrokerDetail struct { + Provider string `json:"provider"` + Region string `json:"region"` + ResourceIdentifier string `json:"resource_identifier"` + SecurityGroupIDs []string `json:"security_group_ids"` + SubnetIDs []string `json:"subnet_ids"` + StorageType string `json:"storage_type"` +} diff --git a/pkg/api/rest/model/request.go b/pkg/api/rest/model/request.go index d0808d1..77acaa1 100644 --- a/pkg/api/rest/model/request.go +++ b/pkg/api/rest/model/request.go @@ -22,5 +22,10 @@ type CreateInfracodeOfSqlDbRequest struct { // Request body for object-storage type CreateInfracodeOfObjectStorageRequest struct { - TfVars TfVarsObjectStorage `json:"tfVars"` + TfVars TfVarsMessageBroker `json:"tfVars"` +} + +// Request body for message-broker +type CreateInfracodeOfMessageBrokerRequest struct { + TfVars TfVarsMessageBroker `json:"tfVars"` } diff --git a/pkg/api/rest/model/sql-db.go b/pkg/api/rest/model/sql-db.go index 18c50af..a5fdf4a 100644 --- a/pkg/api/rest/model/sql-db.go +++ b/pkg/api/rest/model/sql-db.go @@ -21,14 +21,14 @@ type TfVarsSqlDb struct { // OutputSQLDBInfo represents the SQL Database information structure type OutputSQLDBInfo struct { Terrarium Terrarium `json:"terrarium"` - SQLDBDetail SQLDBDetail `json:"sql_db_detail"` + SQLDBDetail SqlDbDetail `json:"sql_db_detail"` } type Terrarium struct { ID string `json:"id"` } -type SQLDBDetail struct { +type SqlDbDetail struct { // Basic Information InstanceName string `json:"instance_name"` InstanceResourceID string `json:"instance_resource_id"` @@ -54,10 +54,10 @@ type SQLDBDetail struct { AdminUsername string `json:"admin_username"` // Provider Specific Details - ProviderSpecificDetail ProviderSpecificDetail `json:"provider_specific_detail"` + ProviderSpecificDetail ProviderSpecificSqlDbDetail `json:"provider_specific_detail"` } -type ProviderSpecificDetail struct { +type ProviderSpecificSqlDbDetail struct { // Common Fields Provider string `json:"provider"` // aws, azure, gcp, ncp Region string `json:"region,omitempty"` diff --git a/pkg/api/rest/server.go b/pkg/api/rest/server.go index adf6534..115e893 100644 --- a/pkg/api/rest/server.go +++ b/pkg/api/rest/server.go @@ -226,6 +226,16 @@ func RunServer(port string) { groupTerrarium.DELETE("/tr/:trId/object-storage", handler.DestroyObjectStorage) groupTerrarium.GET("/tr/:trId/object-storage/request/:requestId", handler.GetRequestStatusOfObjectStorage) + // Message Broker APIs + groupTerrarium.POST("/tr/:trId/message-broker/env", handler.InitEnvForMessageBroker) + groupTerrarium.DELETE("/tr/:trId/message-broker/env", handler.ClearEnvOfMessageBroker) + groupTerrarium.POST("/tr/:trId/message-broker/infracode", handler.CreateInfracodeForMessageBroker) + groupTerrarium.POST("/tr/:trId/message-broker/plan", handler.CheckInfracodeForMessageBroker) + groupTerrarium.POST("/tr/:trId/message-broker", handler.CreateMessageBroker) + groupTerrarium.GET("/tr/:trId/message-broker", handler.GetResourceInfoOfMessageBroker) + groupTerrarium.DELETE("/tr/:trId/message-broker", handler.DestroyMessageBroker) + groupTerrarium.GET("/tr/:trId/message-broker/request/:requestId", handler.GetRequestStatusOfMessageBroker) + // Sample API group (for developers to add new API) groupSample := groupTerrarium.Group("/sample") route.RegisterSampleRoutes(groupSample) diff --git a/templates/message-broker/aws/mq-broker.tf b/templates/message-broker/aws/mq-broker.tf new file mode 100644 index 0000000..e2e2712 --- /dev/null +++ b/templates/message-broker/aws/mq-broker.tf @@ -0,0 +1,35 @@ +# Amazon MQ Broker (ActiveMQ) +resource "aws_mq_broker" "message_broker" { + broker_name = "${var.terrarium_id}-broker" + engine_type = "ActiveMQ" # RabbitMQ is also available + engine_version = "5.17.6" # Valid values: [5.18, 5.17.6, 5.16.7] + # auto_minor_version_upgrade = true # Brokers on [ActiveMQ] version [5.18] must have [autoMinorVersionUpgrade] set to [true] + host_instance_type = "mq.t3.micro" + publicly_accessible = true + + user { + username = var.username + password = var.password + } +} + +# # Security Group for Amazon MQ +# resource "aws_security_group" "mq_sg" { +# name_prefix = "tofu-mq-sg-" +# description = "MQ Broker Security Group" +# vpc_id = var.csp_vnet_id + +# ingress { +# from_port = 5671 +# to_port = 5671 +# protocol = "tcp" +# cidr_blocks = ["0.0.0.0/0"] +# } + +# egress { +# from_port = 0 +# to_port = 0 +# protocol = "-1" +# cidr_blocks = ["0.0.0.0/0"] +# } +# } diff --git a/templates/message-broker/aws/output.tf b/templates/message-broker/aws/output.tf new file mode 100644 index 0000000..56db69d --- /dev/null +++ b/templates/message-broker/aws/output.tf @@ -0,0 +1,33 @@ +output "message_broker_info" { + description = "Information of the Amazon MQ Broker instance in AWS." + value = { + terrarium = { + id = var.terrarium_id + } + message_broker_detail = { + # Basic Information + broker_name = aws_mq_broker.message_broker.broker_name + broker_id = aws_mq_broker.message_broker.id + engine_type = aws_mq_broker.message_broker.engine_type + engine_version = aws_mq_broker.message_broker.engine_version + host_instance_type = aws_mq_broker.message_broker.host_instance_type + deployment_mode = aws_mq_broker.message_broker.deployment_mode + + # Connection Details + broker_endpoint = aws_mq_broker.message_broker.instances[0].endpoints[0] + publicly_accessible = aws_mq_broker.message_broker.publicly_accessible + + # Authentication + username = var.username + + provider_specific_detail = { + provider = "aws" + region = var.csp_region + resource_identifier = aws_mq_broker.message_broker.arn + security_group_ids = aws_mq_broker.message_broker.security_groups + subnet_ids = aws_mq_broker.message_broker.subnet_ids + storage_type = aws_mq_broker.message_broker.storage_type + } + } + } +} diff --git a/templates/message-broker/aws/providers.tf b/templates/message-broker/aws/providers.tf new file mode 100644 index 0000000..b791134 --- /dev/null +++ b/templates/message-broker/aws/providers.tf @@ -0,0 +1,18 @@ +# Define the required version of Terraform and the providers that will be used in the project +terraform { + # Required Tofu version + required_version = "~>1.8.3" + + required_providers { + # AWS provider is specified with its source and version + aws = { + source = "registry.opentofu.org/hashicorp/aws" + version = "~>5.42" + } + } +} + +# Provider block for AWS specifies the configuration for the provider +provider "aws" { + region = var.csp_region +} diff --git a/templates/message-broker/aws/variables.tf b/templates/message-broker/aws/variables.tf new file mode 100644 index 0000000..7c752d7 --- /dev/null +++ b/templates/message-broker/aws/variables.tf @@ -0,0 +1,41 @@ +variable "terrarium_id" { + type = string + description = "Unique ID to distinguish and manage infrastructure." + # default = "terrarium01" # # Used for testing + + validation { + condition = var.terrarium_id != "" + error_message = "The terrarium ID must be set" + } +} + +####################################################################### +# Amazon Web Services (AWS) +variable "csp_region" { + type = string + description = "A region in AWS." + default = "ap-northeast-2" + # AWS regions mapping list: + # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html +} + +# Required network information +variable "csp_vnet_id" { + type = string + description = "The VPC ID in AWS." +} + +# (Required) Username of the user. +variable "username" { + type = string + description = "The username for the message broker." + default = "mybrokeruser1" +} + +# (Required) Password of the user. +# It must be 12 to 250 characters long, at least 4 unique characters, and must not contain commas. +variable "password" { + type = string + description = "The password for the message broker." # + default = "Pa$$word1234Secure!" +}