From 34cf5d628a23665e9c409aa0246496155e647f31 Mon Sep 17 00:00:00 2001 From: Yunkon Kim Date: Wed, 5 Jun 2024 17:44:40 +0900 Subject: [PATCH] Update to provide site-to-site VPN * Integrate and test with mc-terrarium v0.0.7 * Enhance the sites info struct and extraction mechanism from an MCIS info * Change and provide a Site-to-site VPN instead of a GCP-AWS VPN * Specify stream-response in the API URL --- go.mod | 2 +- go.sum | 6 + src/api/rest/docs/docs.go | 504 +++++------ src/api/rest/docs/swagger.json | 504 +++++------ src/api/rest/docs/swagger.yaml | 355 ++++---- src/api/rest/server/mcis/network.go | 785 ++++++++++++------ src/api/rest/server/model/network.go | 41 +- src/api/rest/server/server.go | 17 +- .../test-clis/vpn-tunnel/gcp-aws/app.go | 44 +- .../test-clis/vpn-tunnel/gcp-aws/config.yaml | 2 +- 10 files changed, 1318 insertions(+), 942 deletions(-) diff --git a/go.mod b/go.mod index 921e899d..3956de9d 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cloud-barista/cb-log v0.8.0 // indirect - github.com/cloud-barista/mc-terrarium v0.0.6-0.20240516045927-43023b6a0e18 // indirect + github.com/cloud-barista/mc-terrarium v0.0.7 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect diff --git a/go.sum b/go.sum index 64e1f1f8..e24c9837 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,12 @@ github.com/cloud-barista/mc-terrarium v0.0.6-0.20240516022714-7bafe50e1df5 h1:4/ github.com/cloud-barista/mc-terrarium v0.0.6-0.20240516022714-7bafe50e1df5/go.mod h1:qey9GFrJidyJ3tVfeL/gcImgWLqsF64j/fVmBfaddDI= github.com/cloud-barista/mc-terrarium v0.0.6-0.20240516045927-43023b6a0e18 h1:tsBHD7Gh+Q0jpZ3NCh4jDM+ozlxFCfpMc2gto+G6tZQ= github.com/cloud-barista/mc-terrarium v0.0.6-0.20240516045927-43023b6a0e18/go.mod h1:qey9GFrJidyJ3tVfeL/gcImgWLqsF64j/fVmBfaddDI= +github.com/cloud-barista/mc-terrarium v0.0.6 h1:6HKwnzJ1i3xRiFeboJhMMzTq/qvTt11adIBkmJrSV04= +github.com/cloud-barista/mc-terrarium v0.0.6/go.mod h1:qey9GFrJidyJ3tVfeL/gcImgWLqsF64j/fVmBfaddDI= +github.com/cloud-barista/mc-terrarium v0.0.7-0.20240605063928-b1786b261c06 h1:zAovyT3dYd77t2PkP2IsayYNQ3emxUyldDfmVBvRw6Y= +github.com/cloud-barista/mc-terrarium v0.0.7-0.20240605063928-b1786b261c06/go.mod h1:qey9GFrJidyJ3tVfeL/gcImgWLqsF64j/fVmBfaddDI= +github.com/cloud-barista/mc-terrarium v0.0.7 h1:rXBbAxZyOuwWx77xekrBylGVj9ZIOmHyYcPZkykpCag= +github.com/cloud-barista/mc-terrarium v0.0.7/go.mod h1:qey9GFrJidyJ3tVfeL/gcImgWLqsF64j/fVmBfaddDI= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= diff --git a/src/api/rest/docs/docs.go b/src/api/rest/docs/docs.go index 785127ff..f075911c 100644 --- a/src/api/rest/docs/docs.go +++ b/src/api/rest/docs/docs.go @@ -4319,19 +4319,19 @@ const docTemplate = `{ } } }, - "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws": { + "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}": { "get": { - "description": "Update VPN tunnels between GCP and AWS", + "description": "Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported)", "consumes": [ "application/json" ], "produces": [ - "application/x-json-stream" + "application/json" ], "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" + "[VPN] Site-to-site VPN (under development)" ], - "summary": "Get resource info of VPN tunnels between GCP and AWS", + "summary": "Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported)", "operationId": "GetVpnGcpToAws", "parameters": [ { @@ -4392,235 +4392,19 @@ const docTemplate = `{ } } } - }, - "put": { - "description": "Update VPN tunnels between GCP and AWS", - "consumes": [ - "application/json" - ], - "produces": [ - "application/x-json-stream" - ], - "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" - ], - "summary": "(To be provided) Update VPN tunnels between GCP and AWS", - "operationId": "PutVpnGcpToAws", - "parameters": [ - { - "type": "string", - "default": "ns01", - "description": "Namespace ID", - "name": "nsId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "mcis01", - "description": "MCIS ID", - "name": "mcisId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "vpn01", - "description": "VPN ID", - "name": "vpnId", - "in": "path", - "required": true - }, - { - "description": "Resources info for VPN tunnel configuration between GCP and AWS", - "name": "vpnReq", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/model.RestPostVpnGcpToAwsRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - } - } - }, - "post": { - "description": "Create VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/x-json-stream" - ], - "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" - ], - "summary": "Create VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "operationId": "PostVpnGcpToAws", - "parameters": [ - { - "type": "string", - "default": "ns01", - "description": "Namespace ID", - "name": "nsId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "mcis01", - "description": "MCIS ID", - "name": "mcisId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "vpn01", - "description": "VPN ID", - "name": "vpnId", - "in": "path", - "required": true - }, - { - "description": "Resources info for VPN tunnel configuration between GCP and AWS", - "name": "vpnReq", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/model.RestPostVpnGcpToAwsRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - } - } - }, - "delete": { - "description": "Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/x-json-stream" - ], - "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" - ], - "summary": "Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "operationId": "DeleteVpnGcpToAws", - "parameters": [ - { - "type": "string", - "default": "ns01", - "description": "Namespace ID", - "name": "nsId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "mcis01", - "description": "MCIS ID", - "name": "mcisId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "vpn01", - "description": "VPN ID", - "name": "vpnId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - } - } } }, - "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws/request/{requestId}": { + "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/request/{requestId}": { "get": { "description": "Check the status of a specific request by its ID", "consumes": [ "application/json" ], "produces": [ - "application/x-json-stream" + "application/json" ], "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" + "[VPN] Site-to-site VPN (under development)" ], "summary": "Check the status of a specific request by its ID", "operationId": "GetRequestStatusOfGcpAwsVpn", @@ -8560,6 +8344,224 @@ const docTemplate = `{ } } }, + "/stream-response/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}": { + "put": { + "description": "(To be provided) Update a site-to-site VPN", + "consumes": [ + "application/json" + ], + "produces": [ + "application/x-json-stream" + ], + "tags": [ + "[VPN] Site-to-site VPN (under development)" + ], + "summary": "(To be provided) Update a site-to-site VPN", + "operationId": "PutVpnGcpToAws", + "parameters": [ + { + "type": "string", + "default": "ns01", + "description": "Namespace ID", + "name": "nsId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "mcis01", + "description": "MCIS ID", + "name": "mcisId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "vpn01", + "description": "VPN ID", + "name": "vpnId", + "in": "path", + "required": true + }, + { + "description": "Resources info for VPN tunnel configuration between GCP and AWS", + "name": "vpnReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.RestPostVpnGcpToAwsRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + }, + "post": { + "description": "Create a site-to-site VPN (Currently, GCP-AWS is supported)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/x-json-stream" + ], + "tags": [ + "[VPN] Site-to-site VPN (under development)" + ], + "summary": "Create a site-to-site VPN (Currently, GCP-AWS is supported)", + "operationId": "PostVpnGcpToAws", + "parameters": [ + { + "type": "string", + "default": "ns01", + "description": "Namespace ID", + "name": "nsId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "mcis01", + "description": "MCIS ID", + "name": "mcisId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "vpn01", + "description": "VPN ID", + "name": "vpnId", + "in": "path", + "required": true + }, + { + "description": "Sites info for VPN configuration", + "name": "vpnReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.RestPostVpnRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + }, + "delete": { + "description": "Delete a site-to-site VPN (Currently, GCP-AWS is supported)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/x-json-stream" + ], + "tags": [ + "[VPN] Site-to-site VPN (under development)" + ], + "summary": "Delete a site-to-site VPN (Currently, GCP-AWS is supported)", + "operationId": "DeleteVpnGcpToAws", + "parameters": [ + { + "type": "string", + "default": "ns01", + "description": "Namespace ID", + "name": "nsId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "mcis01", + "description": "MCIS ID", + "name": "mcisId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "vpn01", + "description": "VPN ID", + "name": "vpnId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + } + }, "/systemMcis": { "post": { "description": "Create System MCIS Dynamically for Special Purpose", @@ -12756,17 +12758,21 @@ const docTemplate = `{ "type": "array", "items": {} }, + "message": { + "type": "string", + "example": "Any message" + }, "object": { "type": "object", "additionalProperties": true }, + "status": { + "type": "integer", + "example": 200 + }, "success": { "type": "boolean", "example": true - }, - "text": { - "type": "string", - "example": "Any text" } } }, @@ -12778,6 +12784,17 @@ const docTemplate = `{ } } }, + "model.RestPostVpnRequest": { + "type": "object", + "properties": { + "site1": { + "$ref": "#/definitions/model.SiteDetail" + }, + "site2": { + "$ref": "#/definitions/model.SiteDetail" + } + } + }, "model.SiteDetail": { "type": "object", "properties": { @@ -12827,13 +12844,7 @@ const docTemplate = `{ "example": "ns-01" }, "sites": { - "type": "object", - "additionalProperties": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/model.SiteDetail" - } - } + "$ref": "#/definitions/model.sites" } } }, @@ -12876,6 +12887,29 @@ const docTemplate = `{ } } }, + "model.sites": { + "type": "object", + "properties": { + "aws": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SiteDetail" + } + }, + "azure": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SiteDetail" + } + }, + "gcp": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SiteDetail" + } + } + } + }, "netutil.Network": { "type": "object", "properties": { diff --git a/src/api/rest/docs/swagger.json b/src/api/rest/docs/swagger.json index 1c0b795e..04f23daf 100644 --- a/src/api/rest/docs/swagger.json +++ b/src/api/rest/docs/swagger.json @@ -4312,19 +4312,19 @@ } } }, - "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws": { + "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}": { "get": { - "description": "Update VPN tunnels between GCP and AWS", + "description": "Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported)", "consumes": [ "application/json" ], "produces": [ - "application/x-json-stream" + "application/json" ], "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" + "[VPN] Site-to-site VPN (under development)" ], - "summary": "Get resource info of VPN tunnels between GCP and AWS", + "summary": "Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported)", "operationId": "GetVpnGcpToAws", "parameters": [ { @@ -4385,235 +4385,19 @@ } } } - }, - "put": { - "description": "Update VPN tunnels between GCP and AWS", - "consumes": [ - "application/json" - ], - "produces": [ - "application/x-json-stream" - ], - "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" - ], - "summary": "(To be provided) Update VPN tunnels between GCP and AWS", - "operationId": "PutVpnGcpToAws", - "parameters": [ - { - "type": "string", - "default": "ns01", - "description": "Namespace ID", - "name": "nsId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "mcis01", - "description": "MCIS ID", - "name": "mcisId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "vpn01", - "description": "VPN ID", - "name": "vpnId", - "in": "path", - "required": true - }, - { - "description": "Resources info for VPN tunnel configuration between GCP and AWS", - "name": "vpnReq", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/model.RestPostVpnGcpToAwsRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - } - } - }, - "post": { - "description": "Create VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/x-json-stream" - ], - "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" - ], - "summary": "Create VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "operationId": "PostVpnGcpToAws", - "parameters": [ - { - "type": "string", - "default": "ns01", - "description": "Namespace ID", - "name": "nsId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "mcis01", - "description": "MCIS ID", - "name": "mcisId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "vpn01", - "description": "VPN ID", - "name": "vpnId", - "in": "path", - "required": true - }, - { - "description": "Resources info for VPN tunnel configuration between GCP and AWS", - "name": "vpnReq", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/model.RestPostVpnGcpToAwsRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - } - } - }, - "delete": { - "description": "Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "consumes": [ - "application/json" - ], - "produces": [ - "application/x-json-stream" - ], - "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" - ], - "summary": "Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response)", - "operationId": "DeleteVpnGcpToAws", - "parameters": [ - { - "type": "string", - "default": "ns01", - "description": "Namespace ID", - "name": "nsId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "mcis01", - "description": "MCIS ID", - "name": "mcisId", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "vpn01", - "description": "VPN ID", - "name": "vpnId", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - }, - "503": { - "description": "Service Unavailable", - "schema": { - "$ref": "#/definitions/common.SimpleMsg" - } - } - } } }, - "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws/request/{requestId}": { + "/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/request/{requestId}": { "get": { "description": "Check the status of a specific request by its ID", "consumes": [ "application/json" ], "produces": [ - "application/x-json-stream" + "application/json" ], "tags": [ - "[VPN] GCP-AWS VPN tunnel (under development)" + "[VPN] Site-to-site VPN (under development)" ], "summary": "Check the status of a specific request by its ID", "operationId": "GetRequestStatusOfGcpAwsVpn", @@ -8553,6 +8337,224 @@ } } }, + "/stream-response/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}": { + "put": { + "description": "(To be provided) Update a site-to-site VPN", + "consumes": [ + "application/json" + ], + "produces": [ + "application/x-json-stream" + ], + "tags": [ + "[VPN] Site-to-site VPN (under development)" + ], + "summary": "(To be provided) Update a site-to-site VPN", + "operationId": "PutVpnGcpToAws", + "parameters": [ + { + "type": "string", + "default": "ns01", + "description": "Namespace ID", + "name": "nsId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "mcis01", + "description": "MCIS ID", + "name": "mcisId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "vpn01", + "description": "VPN ID", + "name": "vpnId", + "in": "path", + "required": true + }, + { + "description": "Resources info for VPN tunnel configuration between GCP and AWS", + "name": "vpnReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.RestPostVpnGcpToAwsRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + }, + "post": { + "description": "Create a site-to-site VPN (Currently, GCP-AWS is supported)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/x-json-stream" + ], + "tags": [ + "[VPN] Site-to-site VPN (under development)" + ], + "summary": "Create a site-to-site VPN (Currently, GCP-AWS is supported)", + "operationId": "PostVpnGcpToAws", + "parameters": [ + { + "type": "string", + "default": "ns01", + "description": "Namespace ID", + "name": "nsId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "mcis01", + "description": "MCIS ID", + "name": "mcisId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "vpn01", + "description": "VPN ID", + "name": "vpnId", + "in": "path", + "required": true + }, + { + "description": "Sites info for VPN configuration", + "name": "vpnReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.RestPostVpnRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + }, + "delete": { + "description": "Delete a site-to-site VPN (Currently, GCP-AWS is supported)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/x-json-stream" + ], + "tags": [ + "[VPN] Site-to-site VPN (under development)" + ], + "summary": "Delete a site-to-site VPN (Currently, GCP-AWS is supported)", + "operationId": "DeleteVpnGcpToAws", + "parameters": [ + { + "type": "string", + "default": "ns01", + "description": "Namespace ID", + "name": "nsId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "mcis01", + "description": "MCIS ID", + "name": "mcisId", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "vpn01", + "description": "VPN ID", + "name": "vpnId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + } + }, "/systemMcis": { "post": { "description": "Create System MCIS Dynamically for Special Purpose", @@ -12749,17 +12751,21 @@ "type": "array", "items": {} }, + "message": { + "type": "string", + "example": "Any message" + }, "object": { "type": "object", "additionalProperties": true }, + "status": { + "type": "integer", + "example": 200 + }, "success": { "type": "boolean", "example": true - }, - "text": { - "type": "string", - "example": "Any text" } } }, @@ -12771,6 +12777,17 @@ } } }, + "model.RestPostVpnRequest": { + "type": "object", + "properties": { + "site1": { + "$ref": "#/definitions/model.SiteDetail" + }, + "site2": { + "$ref": "#/definitions/model.SiteDetail" + } + } + }, "model.SiteDetail": { "type": "object", "properties": { @@ -12820,13 +12837,7 @@ "example": "ns-01" }, "sites": { - "type": "object", - "additionalProperties": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/model.SiteDetail" - } - } + "$ref": "#/definitions/model.sites" } } }, @@ -12869,6 +12880,29 @@ } } }, + "model.sites": { + "type": "object", + "properties": { + "aws": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SiteDetail" + } + }, + "azure": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SiteDetail" + } + }, + "gcp": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SiteDetail" + } + } + } + }, "netutil.Network": { "type": "object", "properties": { diff --git a/src/api/rest/docs/swagger.yaml b/src/api/rest/docs/swagger.yaml index 279a4ccd..5f64399a 100644 --- a/src/api/rest/docs/swagger.yaml +++ b/src/api/rest/docs/swagger.yaml @@ -2783,21 +2783,31 @@ definitions: list: items: {} type: array + message: + example: Any message + type: string object: additionalProperties: true type: object + status: + example: 200 + type: integer success: example: true type: boolean - text: - example: Any text - type: string type: object model.RestPostVpnGcpToAwsRequest: properties: tfVars: $ref: '#/definitions/model.TfVarsGcpAwsVpnTunnel' type: object + model.RestPostVpnRequest: + properties: + site1: + $ref: '#/definitions/model.SiteDetail' + site2: + $ref: '#/definitions/model.SiteDetail' + type: object model.SiteDetail: properties: csp: @@ -2834,11 +2844,7 @@ definitions: example: ns-01 type: string sites: - additionalProperties: - additionalProperties: - $ref: '#/definitions/model.SiteDetail' - type: object - type: object + $ref: '#/definitions/model.sites' type: object model.TfVarsGcpAwsVpnTunnel: properties: @@ -2870,6 +2876,21 @@ definitions: - gcp-region - gcp-vpc-network-name type: object + model.sites: + properties: + aws: + items: + $ref: '#/definitions/model.SiteDetail' + type: array + azure: + items: + $ref: '#/definitions/model.SiteDetail' + type: array + gcp: + items: + $ref: '#/definitions/model.SiteDetail' + type: array + type: object netutil.Network: properties: cidrBlock: @@ -5906,57 +5927,12 @@ paths: summary: Create VM Dynamically and add it to MCIS tags: - '[Infra service] MCIS Provisioning management' - /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws: - delete: - consumes: - - application/json - description: Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response) - operationId: DeleteVpnGcpToAws - parameters: - - default: ns01 - description: Namespace ID - in: path - name: nsId - required: true - type: string - - default: mcis01 - description: MCIS ID - in: path - name: mcisId - required: true - type: string - - default: vpn01 - description: VPN ID - in: path - name: vpnId - required: true - type: string - produces: - - application/x-json-stream - responses: - "200": - description: OK - schema: - $ref: '#/definitions/common.SimpleMsg' - "400": - description: Bad Request - schema: - $ref: '#/definitions/common.SimpleMsg' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/common.SimpleMsg' - "503": - description: Service Unavailable - schema: - $ref: '#/definitions/common.SimpleMsg' - summary: Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response) - tags: - - '[VPN] GCP-AWS VPN tunnel (under development)' + /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}: get: consumes: - application/json - description: Update VPN tunnels between GCP and AWS + description: Get resource info of a site-to-site VPN (Currently, GCP-AWS is + supported) operationId: GetVpnGcpToAws parameters: - default: ns01 @@ -5983,7 +5959,7 @@ paths: name: detail type: string produces: - - application/x-json-stream + - application/json responses: "200": description: OK @@ -6001,114 +5977,10 @@ paths: description: Service Unavailable schema: $ref: '#/definitions/model.Response' - summary: Get resource info of VPN tunnels between GCP and AWS - tags: - - '[VPN] GCP-AWS VPN tunnel (under development)' - post: - consumes: - - application/json - description: Create VPN tunnels between GCP and AWS (Note - Streaming JSON response) - operationId: PostVpnGcpToAws - parameters: - - default: ns01 - description: Namespace ID - in: path - name: nsId - required: true - type: string - - default: mcis01 - description: MCIS ID - in: path - name: mcisId - required: true - type: string - - default: vpn01 - description: VPN ID - in: path - name: vpnId - required: true - type: string - - description: Resources info for VPN tunnel configuration between GCP and AWS - in: body - name: vpnReq - required: true - schema: - $ref: '#/definitions/model.RestPostVpnGcpToAwsRequest' - produces: - - application/x-json-stream - responses: - "200": - description: OK - schema: - $ref: '#/definitions/common.SimpleMsg' - "400": - description: Bad Request - schema: - $ref: '#/definitions/common.SimpleMsg' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/common.SimpleMsg' - "503": - description: Service Unavailable - schema: - $ref: '#/definitions/common.SimpleMsg' - summary: Create VPN tunnels between GCP and AWS (Note - Streaming JSON response) + summary: Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported) tags: - - '[VPN] GCP-AWS VPN tunnel (under development)' - put: - consumes: - - application/json - description: Update VPN tunnels between GCP and AWS - operationId: PutVpnGcpToAws - parameters: - - default: ns01 - description: Namespace ID - in: path - name: nsId - required: true - type: string - - default: mcis01 - description: MCIS ID - in: path - name: mcisId - required: true - type: string - - default: vpn01 - description: VPN ID - in: path - name: vpnId - required: true - type: string - - description: Resources info for VPN tunnel configuration between GCP and AWS - in: body - name: vpnReq - required: true - schema: - $ref: '#/definitions/model.RestPostVpnGcpToAwsRequest' - produces: - - application/x-json-stream - responses: - "200": - description: OK - schema: - $ref: '#/definitions/common.SimpleMsg' - "400": - description: Bad Request - schema: - $ref: '#/definitions/common.SimpleMsg' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/common.SimpleMsg' - "503": - description: Service Unavailable - schema: - $ref: '#/definitions/common.SimpleMsg' - summary: (To be provided) Update VPN tunnels between GCP and AWS - tags: - - '[VPN] GCP-AWS VPN tunnel (under development)' - /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws/request/{requestId}: + - '[VPN] Site-to-site VPN (under development)' + /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/request/{requestId}: get: consumes: - application/json @@ -6139,7 +6011,7 @@ paths: required: true type: string produces: - - application/x-json-stream + - application/json responses: "200": description: OK @@ -6159,7 +6031,7 @@ paths: $ref: '#/definitions/model.Response' summary: Check the status of a specific request by its ID tags: - - '[VPN] GCP-AWS VPN tunnel (under development)' + - '[VPN] Site-to-site VPN (under development)' /ns/{nsId}/mcisDynamic: post: consumes: @@ -8783,6 +8655,157 @@ paths: summary: Get all requests tags: - '[Admin] Request tracking' + /stream-response/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}: + delete: + consumes: + - application/json + description: Delete a site-to-site VPN (Currently, GCP-AWS is supported) + operationId: DeleteVpnGcpToAws + parameters: + - default: ns01 + description: Namespace ID + in: path + name: nsId + required: true + type: string + - default: mcis01 + description: MCIS ID + in: path + name: mcisId + required: true + type: string + - default: vpn01 + description: VPN ID + in: path + name: vpnId + required: true + type: string + produces: + - application/x-json-stream + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.SimpleMsg' + "400": + description: Bad Request + schema: + $ref: '#/definitions/common.SimpleMsg' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/common.SimpleMsg' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/common.SimpleMsg' + summary: Delete a site-to-site VPN (Currently, GCP-AWS is supported) + tags: + - '[VPN] Site-to-site VPN (under development)' + post: + consumes: + - application/json + description: Create a site-to-site VPN (Currently, GCP-AWS is supported) + operationId: PostVpnGcpToAws + parameters: + - default: ns01 + description: Namespace ID + in: path + name: nsId + required: true + type: string + - default: mcis01 + description: MCIS ID + in: path + name: mcisId + required: true + type: string + - default: vpn01 + description: VPN ID + in: path + name: vpnId + required: true + type: string + - description: Sites info for VPN configuration + in: body + name: vpnReq + required: true + schema: + $ref: '#/definitions/model.RestPostVpnRequest' + produces: + - application/x-json-stream + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.SimpleMsg' + "400": + description: Bad Request + schema: + $ref: '#/definitions/common.SimpleMsg' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/common.SimpleMsg' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/common.SimpleMsg' + summary: Create a site-to-site VPN (Currently, GCP-AWS is supported) + tags: + - '[VPN] Site-to-site VPN (under development)' + put: + consumes: + - application/json + description: (To be provided) Update a site-to-site VPN + operationId: PutVpnGcpToAws + parameters: + - default: ns01 + description: Namespace ID + in: path + name: nsId + required: true + type: string + - default: mcis01 + description: MCIS ID + in: path + name: mcisId + required: true + type: string + - default: vpn01 + description: VPN ID + in: path + name: vpnId + required: true + type: string + - description: Resources info for VPN tunnel configuration between GCP and AWS + in: body + name: vpnReq + required: true + schema: + $ref: '#/definitions/model.RestPostVpnGcpToAwsRequest' + produces: + - application/x-json-stream + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.SimpleMsg' + "400": + description: Bad Request + schema: + $ref: '#/definitions/common.SimpleMsg' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/common.SimpleMsg' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/common.SimpleMsg' + summary: (To be provided) Update a site-to-site VPN + tags: + - '[VPN] Site-to-site VPN (under development)' /systemMcis: post: consumes: diff --git a/src/api/rest/server/mcis/network.go b/src/api/rest/server/mcis/network.go index 72e7fdc6..e4accafa 100644 --- a/src/api/rest/server/mcis/network.go +++ b/src/api/rest/server/mcis/network.go @@ -26,6 +26,7 @@ import ( "github.com/cloud-barista/cb-tumblebug/src/core/common/netutil" "github.com/cloud-barista/cb-tumblebug/src/core/mcir" "github.com/cloud-barista/cb-tumblebug/src/core/mcis" + terrariumModel "github.com/cloud-barista/mc-terrarium/pkg/api/rest/model" "github.com/go-resty/resty/v2" "github.com/labstack/echo/v4" "github.com/rs/zerolog/log" @@ -88,15 +89,17 @@ func ExtractSitesInfoFromMcisInfo(nsId, mcisId string) (*model.SitesInfo, error) return nil, err } + // A map to check if the VPC (site) is already extracted and added or not. + checkedVpcs := make(map[string]bool) + // Newly create the SitesInfo structure sitesInfo := model.NewSiteInfo(nsId, mcisId) + sitesInAws := []model.SiteDetail{} + sitesInAzure := []model.SiteDetail{} + sitesInGcp := []model.SiteDetail{} + for _, vm := range mcisInfo.Vm { - providerName := vm.ConnectionConfig.ProviderName - if providerName == "" { - log.Warn().Msgf("Provider name is empty for VM ID: %s", vm.Id) - continue - } vNetId := vm.VNetId if vNetId == "" { @@ -104,106 +107,122 @@ func ExtractSitesInfoFromMcisInfo(nsId, mcisId string) (*model.SitesInfo, error) continue } - // Add or update the site detail in the map based on the provider + if _, exists := checkedVpcs[vNetId]; exists { + continue + } + checkedVpcs[vNetId] = true + + providerName := vm.ConnectionConfig.ProviderName + if providerName == "" { + log.Warn().Msgf("Provider name is empty for VM ID: %s", vm.Id) + continue + } + + // Create and set a site details + var site = model.SiteDetail{} + site.CSP = vm.ConnectionConfig.ProviderName + site.Region = vm.CspViewVmDetail.Region.Region + + // Lowercase the provider name providerName = strings.ToLower(providerName) - // Use vNetId as the site ID - if _, exists := sitesInfo.Sites[providerName][vm.VNetId]; !exists { - - var site = model.SiteDetail{} - site.CSP = vm.ConnectionConfig.ProviderName - site.Region = vm.CspViewVmDetail.Region.Region - - switch providerName { - case "aws": - // Get vNet info - resourceType := "vNet" - resourceId := vm.VNetId - result, err := mcir.GetResource(nsId, resourceType, resourceId) - if err != nil { - log.Warn().Msgf("Failed to get the VNet info for ID: %s", resourceId) - continue - } - vNetInfo := result.(mcir.TbVNetInfo) - - // Get the last subnet - subnetCount := len(vNetInfo.SubnetInfoList) - lastSubnet := vNetInfo.SubnetInfoList[subnetCount-1] - lastSubnetIdFromCSP := lastSubnet.IdFromCsp - - // Set VNet and the last subnet IDs - site.VNet = vm.CspViewVmDetail.VpcIID.SystemId - site.Subnet = lastSubnetIdFromCSP - - case "azure": - // Parse vNet and resource group names - parts := strings.Split(vm.CspViewVmDetail.VpcIID.SystemId, "/") - log.Debug().Msgf("parts: %+v", parts) - parsedResourceGroupName := parts[4] - parsedVirtualNetworkName := parts[8] - - // Set VNet and resource group names - site.VNet = parsedVirtualNetworkName - site.ResourceGroup = parsedResourceGroupName - - // Get vNet info - resourceType := "vNet" - resourceId := vm.VNetId - result, err := mcir.GetResource(nsId, resourceType, resourceId) - if err != nil { - log.Warn().Msgf("Failed to get the VNet info for ID: %s", resourceId) - continue - } - vNetInfo := result.(mcir.TbVNetInfo) - - // Get the last subnet CIDR block - subnetCount := len(vNetInfo.SubnetInfoList) - lastSubnet := vNetInfo.SubnetInfoList[subnetCount-1] - lastSubnetCidr := lastSubnet.IPv4_CIDR - - // (Currently unsafe) Calculate the next subnet CIDR block - nextCidr, err := netutil.NextSubnet(lastSubnetCidr, vNetInfo.CidrBlock) - if err != nil { - log.Warn().Msgf("Failed to get the next subnet CIDR") - } - - // Set the site detail - site.GatewaySubnetCidr = nextCidr - - case "gcp": - // Set vNet ID - site.VNet = vm.CspViewVmDetail.VpcIID.SystemId - - default: - log.Warn().Msgf("Unsupported provider name: %s", providerName) + switch providerName { + case "aws": + + // Get vNet info + resourceType := "vNet" + resourceId := vm.VNetId + result, err := mcir.GetResource(nsId, resourceType, resourceId) + if err != nil { + log.Warn().Msgf("Failed to get the VNet info for ID: %s", resourceId) + continue } + vNetInfo := result.(mcir.TbVNetInfo) + + // Get the last subnet + subnetCount := len(vNetInfo.SubnetInfoList) + lastSubnet := vNetInfo.SubnetInfoList[subnetCount-1] + lastSubnetIdFromCSP := lastSubnet.IdFromCsp + + // Set VNet and the last subnet IDs + site.VNet = vm.CspViewVmDetail.VpcIID.SystemId + site.Subnet = lastSubnetIdFromCSP + + sitesInAws = append(sitesInAws, site) + + case "azure": + // Parse vNet and resource group names + parts := strings.Split(vm.CspViewVmDetail.VpcIID.SystemId, "/") + log.Debug().Msgf("parts: %+v", parts) + parsedResourceGroupName := parts[4] + parsedVirtualNetworkName := parts[8] + + // Set VNet and resource group names + site.VNet = parsedVirtualNetworkName + site.ResourceGroup = parsedResourceGroupName + + // Get vNet info + resourceType := "vNet" + resourceId := vm.VNetId + result, err := mcir.GetResource(nsId, resourceType, resourceId) + if err != nil { + log.Warn().Msgf("Failed to get the VNet info for ID: %s", resourceId) + continue + } + vNetInfo := result.(mcir.TbVNetInfo) + + // Get the last subnet CIDR block + subnetCount := len(vNetInfo.SubnetInfoList) + lastSubnet := vNetInfo.SubnetInfoList[subnetCount-1] + lastSubnetCidr := lastSubnet.IPv4_CIDR - if site != (model.SiteDetail{}) { - sitesInfo.Sites[providerName][vm.VNetId] = site - sitesInfo.Count++ + // (Currently unsafe) Calculate the next subnet CIDR block + nextCidr, err := netutil.NextSubnet(lastSubnetCidr, vNetInfo.CidrBlock) + if err != nil { + log.Warn().Msgf("Failed to get the next subnet CIDR") } + + // Set the site detail + site.GatewaySubnetCidr = nextCidr + + sitesInAzure = append(sitesInAzure, site) + + case "gcp": + // Set vNet ID + site.VNet = vm.CspViewVmDetail.VpcIID.SystemId + + sitesInGcp = append(sitesInGcp, site) + + default: + log.Warn().Msgf("Unsupported provider name: %s", providerName) } + + sitesInfo.Count++ } + sitesInfo.Sites.Aws = sitesInAws + sitesInfo.Sites.Azure = sitesInAzure + sitesInfo.Sites.Gcp = sitesInGcp + return sitesInfo, nil } // RestPostVpnGcpToAws godoc // @ID PostVpnGcpToAws -// @Summary Create VPN tunnels between GCP and AWS (Note - Streaming JSON response) -// @Description Create VPN tunnels between GCP and AWS (Note - Streaming JSON response) -// @Tags [VPN] GCP-AWS VPN tunnel (under development) +// @Summary Create a site-to-site VPN (Currently, GCP-AWS is supported) +// @Description Create a site-to-site VPN (Currently, GCP-AWS is supported) +// @Tags [VPN] Site-to-site VPN (under development) // @Accept json // @Produce json-stream // @Param nsId path string true "Namespace ID" default(ns01) // @Param mcisId path string true "MCIS ID" default(mcis01) // @Param vpnId path string true "VPN ID" default(vpn01) -// @Param vpnReq body model.RestPostVpnGcpToAwsRequest true "Resources info for VPN tunnel configuration between GCP and AWS" +// @Param vpnReq body model.RestPostVpnRequest true "Sites info for VPN configuration" // @Success 200 {object} common.SimpleMsg "OK" // @Failure 400 {object} common.SimpleMsg "Bad Request" // @Failure 500 {object} common.SimpleMsg "Internal Server Error" // @Failure 503 {object} common.SimpleMsg "Service Unavailable" -// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws [post] +// @Router /stream-response/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId} [post] func RestPostVpnGcpToAws(c echo.Context) error { nsId := c.Param("nsId") @@ -237,7 +256,7 @@ func RestPostVpnGcpToAws(c echo.Context) error { } // Bind the request body to RestPostVpnGcpToAwsRequest struct - vpnReq := new(model.RestPostVpnGcpToAwsRequest) + vpnReq := new(model.RestPostVpnRequest) if err := c.Bind(vpnReq); err != nil { err2 := fmt.Errorf("invalid request format, %v", err) log.Warn().Err(err).Msg("invalid request format") @@ -247,6 +266,16 @@ func RestPostVpnGcpToAws(c echo.Context) error { return c.JSON(http.StatusBadRequest, res) } + // Validate the VPN sites + err := validateVPNSites(vpnReq.Site1, vpnReq.Site2) + if err != nil { + log.Warn().Err(err).Msg("") + res := common.SimpleMsg{ + Message: err.Error(), + } + return c.JSON(http.StatusBadRequest, res) + } + // Prepare for streaming response c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON) c.Response().WriteHeader(http.StatusOK) @@ -258,7 +287,7 @@ func RestPostVpnGcpToAws(c echo.Context) error { apiPass := os.Getenv("API_PASSWORD") client.SetBasicAuth(apiUser, apiPass) - rgId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) + trId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) // set endpoint epTerrarium := common.TerrariumRestUrl @@ -269,7 +298,7 @@ func RestPostVpnGcpToAws(c echo.Context) error { requestBody := common.NoBody resReadyz := new(model.Response) - err := common.ExecuteHttpRequest( + err = common.ExecuteHttpRequest( client, method, url, @@ -287,168 +316,237 @@ func RestPostVpnGcpToAws(c echo.Context) error { } return c.JSON(http.StatusServiceUnavailable, res) } - log.Debug().Msgf("resReadyz: %+v", resReadyz.Text) + log.Debug().Msgf("resReadyz: %+v", resReadyz.Message) // Flush a response res := common.SimpleMsg{ - Message: resReadyz.Text, + Message: resReadyz.Message, } if err := enc.Encode(res); err != nil { return err } c.Response().Flush() - // init terrarium - method = "POST" - url = fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/terrarium", epTerrarium, rgId) - requestBody = common.NoBody - resInitTerrarium := new(model.Response) - - err = common.ExecuteHttpRequest( - client, - method, - url, - nil, - common.SetUseBody(requestBody), - &requestBody, - resInitTerrarium, - common.VeryShortDuration, - ) - - if err != nil { - log.Err(err).Msg("") - res := common.SimpleMsg{Message: err.Error()} - return c.JSON(http.StatusInternalServerError, res) - } - - log.Debug().Msgf("resInit: %+v", resInitTerrarium.Text) - log.Trace().Msgf("resInit: %+v", resInitTerrarium.Detail) - - // Flush a response - res = common.SimpleMsg{ - Message: resInitTerrarium.Text, - } - if err := enc.Encode(res); err != nil { - return err - } - c.Response().Flush() - - // infracode - method = "POST" - url = fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/infracode", epTerrarium, rgId) - reqInfracode := *vpnReq - resInfracode := new(model.Response) + // Check the CSPs of the sites + if (vpnReq.Site1.CSP == "aws" && vpnReq.Site2.CSP == "gcp") || (vpnReq.Site1.CSP == "gcp" && vpnReq.Site2.CSP == "aws") { + + // issue a terrarium + method = "POST" + url = fmt.Sprintf("%s/tr", epTerrarium) + reqTr := new(terrariumModel.TerrariumInfo) + reqTr.Id = trId + reqTr.Description = "VPN between GCP and AWS" + + resTrInfo := new(terrariumModel.TerrariumInfo) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(*reqTr), + reqTr, + resTrInfo, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } - err = common.ExecuteHttpRequest( - client, - method, - url, - nil, - common.SetUseBody(reqInfracode), - &reqInfracode, - resInfracode, - common.VeryShortDuration, - ) + log.Debug().Msgf("resTrInfo.Id: %s", resTrInfo.Id) + log.Trace().Msgf("resTrInfo: %+v", resTrInfo) - if err != nil { - log.Err(err).Msg("") - res := common.SimpleMsg{Message: err.Error()} - return c.JSON(http.StatusInternalServerError, res) - } + // Flush a response + res = common.SimpleMsg{ + Message: "successully created a terrarium (trId: " + resTrInfo.Id + ")", + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // init env + method = "POST" + url = fmt.Sprintf("%s/tr/%s/vpn/gcp-aws/env", epTerrarium, trId) + requestBody = common.NoBody + resTerrariumEnv := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resTerrariumEnv, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } - log.Debug().Msgf("resInfracode: %+v", resInfracode.Text) - log.Trace().Msgf("resInfracode: %+v", resInfracode.Detail) + log.Debug().Msgf("resInit: %+v", resTerrariumEnv.Message) + log.Trace().Msgf("resInit: %+v", resTerrariumEnv.Detail) - // Flush a response - res = common.SimpleMsg{ - Message: resInfracode.Text, - } - if err := enc.Encode(res); err != nil { - return err - } - c.Response().Flush() + // flush a response + res = common.SimpleMsg{ + Message: resTerrariumEnv.Message, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // generate infracode + method = "POST" + url = fmt.Sprintf("%s/tr/%s/vpn/gcp-aws/infracode", epTerrarium, trId) + reqInfracode := new(terrariumModel.CreateInfracodeOfGcpAwsVpnRequest) + + if vpnReq.Site1.CSP == "aws" { + reqInfracode.TfVars.AwsRegion = vpnReq.Site1.Region + reqInfracode.TfVars.AwsVpcId = vpnReq.Site1.VNet + reqInfracode.TfVars.AwsSubnetId = vpnReq.Site1.Subnet + reqInfracode.TfVars.GcpRegion = vpnReq.Site2.Region + reqInfracode.TfVars.GcpVpcNetworkName = vpnReq.Site2.VNet + } else { + reqInfracode.TfVars.AwsRegion = vpnReq.Site2.Region + reqInfracode.TfVars.AwsVpcId = vpnReq.Site2.VNet + reqInfracode.TfVars.AwsSubnetId = vpnReq.Site2.Subnet + reqInfracode.TfVars.GcpRegion = vpnReq.Site1.Region + reqInfracode.TfVars.GcpVpcNetworkName = vpnReq.Site1.VNet + } - // plan - method = "POST" - url = fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/plan", epTerrarium, rgId) - requestBody = common.NoBody - resPlan := new(model.Response) + resInfracode := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(*reqInfracode), + reqInfracode, + resInfracode, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } - err = common.ExecuteHttpRequest( - client, - method, - url, - nil, - common.SetUseBody(requestBody), - &requestBody, - resPlan, - common.VeryShortDuration, - ) + log.Debug().Msgf("resInfracode: %+v", resInfracode.Message) + log.Trace().Msgf("resInfracode: %+v", resInfracode.Detail) - if err != nil { - log.Err(err).Msg("") - res := common.SimpleMsg{Message: err.Error()} - return c.JSON(http.StatusInternalServerError, res) - } + // Flush a response + res = common.SimpleMsg{ + Message: resInfracode.Message, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // check the infracode by plan + method = "POST" + url = fmt.Sprintf("%s/tr/%s/vpn/gcp-aws/plan", epTerrarium, trId) + requestBody = common.NoBody + resPlan := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resPlan, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } - log.Debug().Msgf("resPlan: %+v", resPlan.Text) - log.Trace().Msgf("resPlan: %+v", resPlan.Detail) + log.Debug().Msgf("resPlan: %+v", resPlan.Message) + log.Trace().Msgf("resPlan: %+v", resPlan.Detail) - // Flush a response - res = common.SimpleMsg{ - Message: resPlan.Text, - } - if err := enc.Encode(res); err != nil { - return err - } - c.Response().Flush() + // Flush a response + res = common.SimpleMsg{ + Message: resPlan.Message, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // apply + // wait until the task is completed + // or response immediately with requestId as it is a time-consuming task + // and provide seperate api to check the status + method = "POST" + url = fmt.Sprintf("%s/tr/%s/vpn/gcp-aws", epTerrarium, trId) + requestBody = common.NoBody + resApply := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resApply, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } - // apply - // wait until the task is completed - // or response immediately with requestId as it is a time-consuming task - // and provide seperate api to check the status - method = "POST" - url = fmt.Sprintf("%s/rg/%s/vpn/gcp-aws", epTerrarium, rgId) - requestBody = common.NoBody - resApply := new(model.Response) + log.Debug().Msgf("resApply: %+v", resApply.Message) + log.Trace().Msgf("resApply: %+v", resApply.Detail) - err = common.ExecuteHttpRequest( - client, - method, - url, - nil, - common.SetUseBody(requestBody), - &requestBody, - resApply, - common.VeryShortDuration, - ) + // Flush a response + res = common.SimpleMsg{ + Message: resApply.Message, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() - if err != nil { - log.Err(err).Msg("") - res := common.SimpleMsg{Message: err.Error()} - return c.JSON(http.StatusInternalServerError, res) + } else if (vpnReq.Site1.CSP == "gcp" && vpnReq.Site2.CSP == "azure") || (vpnReq.Site1.CSP == "azure" && vpnReq.Site2.CSP == "gcp") { + // TBD } - log.Debug().Msgf("resApply: %+v", resApply.Text) - log.Trace().Msgf("resApply: %+v", resApply.Detail) + return nil +} - // Flush a response - res = common.SimpleMsg{ - Message: resApply.Text, - } - if err := enc.Encode(res); err != nil { - return err +func validateVPNSites(site1, site2 model.SiteDetail) error { + if (site1.CSP == "gcp" && (site2.CSP == "aws" || site2.CSP == "azure")) || + (site1.CSP == "aws" && site2.CSP == "gcp") || + (site1.CSP == "azure" && site2.CSP == "gcp") { + return nil } - c.Response().Flush() - - return nil + return fmt.Errorf("VPN between %s and %s is not supported yet", site1.CSP, site2.CSP) } // RestDeleteVpnGcpToAws godoc // @ID DeleteVpnGcpToAws -// @Summary Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response) -// @Description Delete VPN tunnels between GCP and AWS (Note - Streaming JSON response) -// @Tags [VPN] GCP-AWS VPN tunnel (under development) +// @Summary Delete a site-to-site VPN (Currently, GCP-AWS is supported) +// @Description Delete a site-to-site VPN (Currently, GCP-AWS is supported) +// @Tags [VPN] Site-to-site VPN (under development) // @Accept json // @Produce json-stream // @Param nsId path string true "Namespace ID" default(ns01) @@ -458,7 +556,7 @@ func RestPostVpnGcpToAws(c echo.Context) error { // @Failure 400 {object} common.SimpleMsg "Bad Request" // @Failure 500 {object} common.SimpleMsg "Internal Server Error" // @Failure 503 {object} common.SimpleMsg "Service Unavailable" -// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws [delete] +// @Router /stream-response/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId} [delete] func RestDeleteVpnGcpToAws(c echo.Context) error { nsId := c.Param("nsId") @@ -502,7 +600,7 @@ func RestDeleteVpnGcpToAws(c echo.Context) error { apiPass := os.Getenv("API_PASSWORD") client.SetBasicAuth(apiUser, apiPass) - rgId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) + trId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) // set endpoint epTerrarium := common.TerrariumRestUrl @@ -531,23 +629,130 @@ func RestDeleteVpnGcpToAws(c echo.Context) error { } return c.JSON(http.StatusServiceUnavailable, res) } - log.Debug().Msgf("resReadyz: %+v", resReadyz.Text) + log.Debug().Msgf("resReadyz: %+v", resReadyz.Message) log.Trace().Msgf("resReadyz: %+v", resReadyz.Detail) // Flush a response res := common.SimpleMsg{ - Message: resReadyz.Text, + Message: resReadyz.Message, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // Get the terrarium info + method = "GET" + url = fmt.Sprintf("%s/tr/%s", epTerrarium, trId) + requestBody = common.NoBody + resTrInfo := new(terrariumModel.TerrariumInfo) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resTrInfo, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + log.Debug().Msgf("resTrInfo.Id: %s", resTrInfo.Id) + log.Trace().Msgf("resTrInfo: %+v", resTrInfo) + enrichments := resTrInfo.Enrichments + + // Flush a response + msg := fmt.Sprintf("successully got the terrarium (trId: %s) for the enrichment (%s)", resTrInfo.Id, enrichments) + res = common.SimpleMsg{ + Message: msg, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // delete enrichments + method = "DELETE" + url = fmt.Sprintf("%s/tr/%s/%s", epTerrarium, trId, enrichments) + requestBody = common.NoBody + resDeleteEnrichments := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resDeleteEnrichments, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + log.Debug().Msgf("resDeleteEnrichments: %+v", resDeleteEnrichments.Message) + log.Trace().Msgf("resDeleteEnrichments: %+v", resDeleteEnrichments.Detail) + + // Flush a response + res = common.SimpleMsg{ + Message: resDeleteEnrichments.Message, + } + if err := enc.Encode(res); err != nil { + return err + } + c.Response().Flush() + + // delete env + method = "DELETE" + url = fmt.Sprintf("%s/tr/%s/%s/env", epTerrarium, trId, enrichments) + requestBody = common.NoBody + resDeleteEnv := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resDeleteEnv, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + log.Debug().Msgf("resDeleteEnv: %+v", resDeleteEnv.Message) + log.Trace().Msgf("resDeleteEnv: %+v", resDeleteEnv.Detail) + + // Flush a response + res = common.SimpleMsg{ + Message: resDeleteEnrichments.Message, } if err := enc.Encode(res); err != nil { return err } c.Response().Flush() - // delete + // delete terrarium method = "DELETE" - url = fmt.Sprintf("%s/rg/%s/vpn/gcp-aws", epTerrarium, rgId) + url = fmt.Sprintf("%s/tr/%s", epTerrarium, trId) requestBody = common.NoBody - resDelete := new(model.Response) + resDeleteTr := new(model.Response) err = common.ExecuteHttpRequest( client, @@ -556,7 +761,7 @@ func RestDeleteVpnGcpToAws(c echo.Context) error { nil, common.SetUseBody(requestBody), &requestBody, - resDelete, + resDeleteTr, common.VeryShortDuration, ) @@ -566,12 +771,12 @@ func RestDeleteVpnGcpToAws(c echo.Context) error { return c.JSON(http.StatusInternalServerError, res) } - log.Debug().Msgf("resDelete: %+v", resDelete.Text) - log.Trace().Msgf("resDelete: %+v", resDelete.Detail) + log.Debug().Msgf("resDeleteTr: %+v", resDeleteTr.Message) + log.Trace().Msgf("resDeleteTr: %+v", resDeleteTr.Detail) // Flush a response res = common.SimpleMsg{ - Message: resDelete.Text, + Message: resDeleteEnrichments.Message, } if err := enc.Encode(res); err != nil { return err @@ -583,9 +788,9 @@ func RestDeleteVpnGcpToAws(c echo.Context) error { // RestPutVpnGcpToAws godoc // @ID PutVpnGcpToAws -// @Summary (To be provided) Update VPN tunnels between GCP and AWS -// @Description Update VPN tunnels between GCP and AWS -// @Tags [VPN] GCP-AWS VPN tunnel (under development) +// @Summary (To be provided) Update a site-to-site VPN +// @Description (To be provided) Update a site-to-site VPN +// @Tags [VPN] Site-to-site VPN (under development) // @Accept json // @Produce json-stream // @Param nsId path string true "Namespace ID" default(ns01) @@ -596,7 +801,7 @@ func RestDeleteVpnGcpToAws(c echo.Context) error { // @Failure 400 {object} common.SimpleMsg "Bad Request" // @Failure 500 {object} common.SimpleMsg "Internal Server Error" // @Failure 503 {object} common.SimpleMsg "Service Unavailable" -// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws [put] +// @Router /stream-response/ns/{nsId}/mcis/{mcisId}/vpn/{vpnId} [put] func RestPutVpnGcpToAws(c echo.Context) error { nsId := c.Param("nsId") @@ -652,13 +857,13 @@ func RestPutVpnGcpToAws(c echo.Context) error { // client.SetBasicAuth(apiUser, apiPass) // epTerrarium := "http://localhost:8888/terrarium" - // rgId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) + // trId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) // // check readyz // method := "GET" // url := fmt.Sprintf("%s/readyz", epTerrarium) // requestBody := common.NoBody - // resReadyz := new(model.ResponseText) + // resReadyz := new(model.Response) // err := common.ExecuteHttpRequest( // client, @@ -682,7 +887,7 @@ func RestPutVpnGcpToAws(c echo.Context) error { // // Flush a response // res := common.SimpleMsg{ - // Message: resReadyz.Text, + // Message: resReadyz.Message, // } // if err := enc.Encode(res); err != nil { // return err @@ -694,11 +899,11 @@ func RestPutVpnGcpToAws(c echo.Context) error { // RestGetVpnGcpToAws godoc // @ID GetVpnGcpToAws -// @Summary Get resource info of VPN tunnels between GCP and AWS -// @Description Update VPN tunnels between GCP and AWS -// @Tags [VPN] GCP-AWS VPN tunnel (under development) +// @Summary Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported) +// @Description Get resource info of a site-to-site VPN (Currently, GCP-AWS is supported) +// @Tags [VPN] Site-to-site VPN (under development) // @Accept json -// @Produce json-stream +// @Produce json // @Param nsId path string true "Namespace ID" default(ns01) // @Param mcisId path string true "MCIS ID" default(mcis01) // @Param vpnId path string true "VPN ID" default(vpn01) @@ -707,7 +912,7 @@ func RestPutVpnGcpToAws(c echo.Context) error { // @Failure 400 {object} model.Response "Bad Request" // @Failure 500 {object} model.Response "Internal Server Error" // @Failure 503 {object} model.Response "Service Unavailable" -// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws [get] +// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId} [get] func RestGetVpnGcpToAws(c echo.Context) error { nsId := c.Param("nsId") @@ -716,7 +921,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -727,7 +932,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -738,7 +943,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -773,7 +978,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { apiPass := os.Getenv("API_PASSWORD") client.SetBasicAuth(apiUser, apiPass) - rgId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) + trId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) // set endpoint epTerrarium := common.TerrariumRestUrl @@ -799,15 +1004,42 @@ func RestGetVpnGcpToAws(c echo.Context) error { log.Err(err).Msg("") res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusServiceUnavailable, res) } - log.Debug().Msgf("resReadyz: %+v", resReadyz.Text) + log.Debug().Msgf("resReadyz: %+v", resReadyz.Message) + + // Get the terrarium info + method = "GET" + url = fmt.Sprintf("%s/tr/%s", epTerrarium, trId) + requestBody = common.NoBody + resTrInfo := new(terrariumModel.TerrariumInfo) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(requestBody), + &requestBody, + resTrInfo, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + log.Debug().Msgf("resTrInfo.Id: %s", resTrInfo.Id) + log.Trace().Msgf("resTrInfo: %+v", resTrInfo) + enrichments := resTrInfo.Enrichments // Get resource info method = "GET" - url = fmt.Sprintf("%s/rg/%s/vpn/gcp-aws?detail=%s", epTerrarium, rgId, detail) + url = fmt.Sprintf("%s/tr/%s/%s?detail=%s", epTerrarium, trId, enrichments, detail) requestBody = common.NoBody resResourceInfo := new(model.Response) @@ -826,7 +1058,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { log.Err(err).Msg("") res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusInternalServerError, res) } @@ -850,7 +1082,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { log.Warn().Msgf("invalid detail option (%s)", detail) res := model.Response{ Success: false, - Text: fmt.Sprintf("invalid detail option (%s)", detail), + Message: fmt.Sprintf("invalid detail option (%s)", detail), } return c.JSON(http.StatusBadRequest, res) } @@ -860,9 +1092,9 @@ func RestGetVpnGcpToAws(c echo.Context) error { // @ID GetRequestStatusOfGcpAwsVpn // @Summary Check the status of a specific request by its ID // @Description Check the status of a specific request by its ID -// @Tags [VPN] GCP-AWS VPN tunnel (under development) +// @Tags [VPN] Site-to-site VPN (under development) // @Accept json -// @Produce json-stream +// @Produce json // @Param nsId path string true "Namespace ID" default(ns01) // @Param mcisId path string true "MCIS ID" default(mcis01) // @Param vpnId path string true "VPN ID" default(vpn01) @@ -871,7 +1103,7 @@ func RestGetVpnGcpToAws(c echo.Context) error { // @Failure 400 {object} model.Response "Bad Request" // @Failure 500 {object} model.Response "Internal Server Error" // @Failure 503 {object} model.Response "Service Unavailable" -// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/gcp-aws/request/{requestId} [get] +// @Router /ns/{nsId}/mcis/{mcisId}/vpn/{vpnId}/request/{requestId} [get] func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { nsId := c.Param("nsId") @@ -880,7 +1112,7 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -891,7 +1123,7 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -902,7 +1134,7 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -913,7 +1145,7 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { log.Warn().Msg(err.Error()) res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusBadRequest, res) } @@ -924,16 +1156,16 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { apiPass := os.Getenv("API_PASSWORD") client.SetBasicAuth(apiUser, apiPass) - rgId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) + trId := fmt.Sprintf("%s-%s-%s", nsId, mcisId, vpnId) // set endpoint epTerrarium := common.TerrariumRestUrl - // Get resource info + // Get the terrarium info method := "GET" - url := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/request/%s", epTerrarium, rgId, reqId) + url := fmt.Sprintf("%s/tr/%s", epTerrarium, trId) requestBody := common.NoBody - resReqStatus := new(model.Response) + resTrInfo := new(terrariumModel.TerrariumInfo) err := common.ExecuteHttpRequest( client, @@ -942,6 +1174,33 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { nil, common.SetUseBody(requestBody), &requestBody, + resTrInfo, + common.VeryShortDuration, + ) + + if err != nil { + log.Err(err).Msg("") + res := common.SimpleMsg{Message: err.Error()} + return c.JSON(http.StatusInternalServerError, res) + } + + log.Debug().Msgf("resTrInfo.Id: %s", resTrInfo.Id) + log.Trace().Msgf("resTrInfo: %+v", resTrInfo) + enrichments := resTrInfo.Enrichments + + // Get resource info + method = "GET" + url = fmt.Sprintf("%s/tr/%s/%s/request/%s", epTerrarium, trId, enrichments, reqId) + reqReqStatus := common.NoBody + resReqStatus := new(model.Response) + + err = common.ExecuteHttpRequest( + client, + method, + url, + nil, + common.SetUseBody(reqReqStatus), + &reqReqStatus, resReqStatus, common.VeryShortDuration, ) @@ -950,7 +1209,7 @@ func RestGetRequestStatusOfGcpAwsVpn(c echo.Context) error { log.Err(err).Msg("") res := model.Response{ Success: false, - Text: err.Error(), + Message: err.Error(), } return c.JSON(http.StatusInternalServerError, res) } diff --git a/src/api/rest/server/model/network.go b/src/api/rest/server/model/network.go index 454b50a8..5f8d258c 100644 --- a/src/api/rest/server/model/network.go +++ b/src/api/rest/server/model/network.go @@ -31,12 +31,19 @@ type SiteDetail struct { ResourceGroup string `json:"resourceGroup,omitempty" example:"rg-xxxxx"` } +// Sites struct represents the overall site information +type sites struct { + Aws []SiteDetail `json:"aws"` + Azure []SiteDetail `json:"azure"` + Gcp []SiteDetail `json:"gcp"` +} + // SitesInfo struct represents the overall site information including namespace and MCIS ID type SitesInfo struct { - NsId string `json:"nsId" example:"ns-01"` - McisId string `json:"mcisId" example:"mcis-01"` - Count int `json:"count" example:"3"` - Sites map[string]map[string]SiteDetail `json:"sites"` + NsId string `json:"nsId" example:"ns-01"` + McisId string `json:"mcisId" example:"mcis-01"` + Count int `json:"count" example:"3"` + Sites sites `json:"sites"` } func NewSiteInfo(nsId, mcisId string) *SitesInfo { @@ -44,24 +51,34 @@ func NewSiteInfo(nsId, mcisId string) *SitesInfo { NsId: nsId, McisId: mcisId, Count: 0, - Sites: make(map[string]map[string]SiteDetail), - } - - for _, providerName := range ProviderNames { - siteInfo.Sites[providerName] = make(map[string]SiteDetail) + Sites: sites{ + Aws: []SiteDetail{}, + Azure: []SiteDetail{}, + Gcp: []SiteDetail{}, + }, } return siteInfo } +type RestPostVpnRequest struct { + Site1 SiteDetail `json:"site1"` + Site2 SiteDetail `json:"site2"` +} + type Response struct { Success bool `json:"success" example:"true"` - Text string `json:"text" example:"Any text"` + Status int `json:"status,omitempty" example:"200"` + Message string `json:"message" example:"Any message"` Detail string `json:"details,omitempty" example:"Any details"` Object map[string]interface{} `json:"object,omitempty"` List []interface{} `json:"list,omitempty"` } +type RestPostVpnGcpToAwsRequest struct { + TfVars TfVarsGcpAwsVpnTunnel `json:"tfVars"` +} + type TfVarsGcpAwsVpnTunnel struct { ResourceGroupId string `json:"resource-group-id,omitempty" default:"" example:""` AwsRegion string `json:"aws-region" validate:"required" default:"ap-northeast-2" example:"ap-northeast-2"` @@ -72,10 +89,6 @@ type TfVarsGcpAwsVpnTunnel struct { // GcpBgpAsn string `json:"gcp-bgp-asn" default:"65530"` } -type RestPostVpnGcpToAwsRequest struct { - TfVars TfVarsGcpAwsVpnTunnel `json:"tfVars"` -} - // type TfVarsGcpAzureVpnTunnel struct { // ResourceGroupId string `json:"resource-group-id,omitempty" default:"" example:""` // AzureRegion string `json:"azure-region" default:"koreacentral" example:"koreacentral"` diff --git a/src/api/rest/server/server.go b/src/api/rest/server/server.go index 86976040..ca9bc679 100644 --- a/src/api/rest/server/server.go +++ b/src/api/rest/server/server.go @@ -216,6 +216,9 @@ func RunServer(port string) { // Route for NameSpace subgroup g := e.Group("/tumblebug/ns", common.NsValidation()) + // Route for stream response subgroup + streamResponseGroup := e.Group("/tumblebug/stream-response/ns", common.NsValidation()) + //Namespace Management g.POST("", rest_common.RestPostNs) g.GET("/:nsId", rest_common.RestGetNs) @@ -284,11 +287,15 @@ func RunServer(port string) { g.GET("/:nsId/mcis/:mcisId/site", rest_mcis.RestGetSitesInMcis) // VPN Management - g.POST("/:nsId/mcis/:mcisId/vpn/:vpnId/gcp-aws", rest_mcis.RestPostVpnGcpToAws) - g.GET("/:nsId/mcis/:mcisId/vpn/:vpnId/gcp-aws", rest_mcis.RestGetVpnGcpToAws) - g.PUT("/:nsId/mcis/:mcisId/vpn/:vpnId/gcp-aws", rest_mcis.RestPutVpnGcpToAws) - g.DELETE("/:nsId/mcis/:mcisId/vpn/:vpnId/gcp-aws", rest_mcis.RestDeleteVpnGcpToAws) - g.GET("/:nsId/mcis/:mcisId/vpn/:vpnId/gcp-aws/request/:requestId", rest_mcis.RestGetRequestStatusOfGcpAwsVpn) + streamResponseGroup.POST("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestPostVpnGcpToAws) + g.GET("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestGetVpnGcpToAws) + streamResponseGroup.PUT("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestPutVpnGcpToAws) + streamResponseGroup.DELETE("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestDeleteVpnGcpToAws) + g.GET("/:nsId/mcis/:mcisId/vpn/:vpnId/request/:requestId", rest_mcis.RestGetRequestStatusOfGcpAwsVpn) + // TBD + // g.POST("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestPostVpnGcpToAws) + // g.PUT("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestPutVpnGcpToAws) + // g.DELETE("/:nsId/mcis/:mcisId/vpn/:vpnId", rest_mcis.RestDeleteVpnGcpToAws) //MCIS AUTO Policy g.POST("/:nsId/policy/mcis/:mcisId", rest_mcis.RestPostMcisPolicy) diff --git a/src/testclient/test-clis/vpn-tunnel/gcp-aws/app.go b/src/testclient/test-clis/vpn-tunnel/gcp-aws/app.go index fef6d2dd..86102399 100644 --- a/src/testclient/test-clis/vpn-tunnel/gcp-aws/app.go +++ b/src/testclient/test-clis/vpn-tunnel/gcp-aws/app.go @@ -87,7 +87,7 @@ func main() { // Command-line flags with shorthand createVpnCmd.Flags().StringP("nsId", "n", "", "Namespace ID") createVpnCmd.Flags().StringP("mcisId", "m", "", "MCIS ID") - createVpnCmd.Flags().StringP("rgId", "r", "", "ResourceGroup ID") + createVpnCmd.Flags().StringP("trId", "t", "", "Terrarium ID") createCmd.AddCommand( createMcisDynamicCmd, @@ -113,7 +113,7 @@ func main() { Run: destroyVpnTunnel, } // Command-line flags with shorthand - destroyVpnCmd.Flags().StringP("rgId", "r", "", "ResourceGroup ID") + destroyVpnCmd.Flags().StringP("trId", "t", "", "Terrarium ID") deleteCmd.AddCommand( terminateMcisCmd, @@ -281,15 +281,15 @@ func createMcis(cmd *cobra.Command, args []string) { func createVpnTunnel(cmd *cobra.Command, args []string) { - // Set namespace ID, MCIS ID, and resource group ID + // Set namespace ID, MCIS ID, and terrarium ID nsId, _ := cmd.Flags().GetString("namespaceId") mcisId, _ := cmd.Flags().GetString("mcisId") - rgId, _ := cmd.Flags().GetString("rgId") + trId, _ := cmd.Flags().GetString("trId") log.Debug(). Str("Namespace ID", nsId). Str("MCIS ID", mcisId). - Str("Resource group ID", rgId). + Str("Terrarium ID", trId). Msg("[args]") if nsId == "" { @@ -300,22 +300,22 @@ func createVpnTunnel(cmd *cobra.Command, args []string) { mcisId = viper.GetString("tumblebug.demo.mcisId") } - if rgId == "" { - rgId = viper.GetString("terrarium.demo.resourceGroupId") + if trId == "" { + trId = viper.GetString("terrarium.demo.terrariumId") } log.Debug(). Str("Namespace ID", nsId). Str("MCIS ID", mcisId). - Str("Resource group ID", rgId). + Str("Terrarium ID", trId). Msg("[config.yaml]") - if nsId == "" || mcisId == "" || rgId == "" { + if nsId == "" || mcisId == "" || trId == "" { err := fmt.Errorf("bad request: nsId, mcisId, or rgId is not set") log.Fatal().Err(err). Str("Namespace ID", nsId). Str("MCIS ID", mcisId). - Str("Resource group ID", rgId). + Str("Terrarium ID", trId). Msg("Please set the values in the config file or pass them as arguments") return } @@ -555,12 +555,12 @@ func createVpnTunnel(cmd *cobra.Command, args []string) { } log.Debug().Msgf("[Response] %+v", string(prettyResTerrariumReadiness)) - log.Info().Msg(resTerrariumReadiness.Text) + log.Info().Msg(resTerrariumReadiness.Message) /////////////////////////////////////////////////////////////////////////////////////////////////// // mc-terrarium: Initialize a multi-cloud terrarium for GCP to AWS VPN tunnel - urlInitTerrarium := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/terrarium", epTerrarium, rgId) + urlInitTerrarium := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/env", epTerrarium, trId) // Request init respBytes, err = callApi("POST", urlInitTerrarium, authTerrarium, nil) @@ -576,15 +576,15 @@ func createVpnTunnel(cmd *cobra.Command, args []string) { return } - log.Trace().Msgf("[Response] %+v", initRes.Text) + log.Trace().Msgf("[Response] %+v", initRes.Message) /////////////////////////////////////////////////////////////////////////////////////////////////// // mc-terrarium: Create blueprints of GCP-AWS VPN tunnel - urlInfracode := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/infracode", epTerrarium, rgId) + urlInfracode := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws/infracode", epTerrarium, trId) reqBody := terrariumModel.CreateInfracodeOfGcpAwsVpnRequest{ TfVars: terrariumModel.TfVarsGcpAwsVpnTunnel{ - ResourceGroupId: rgId, + TerrariumId: trId, AwsRegion: awsRegion, AwsVpcId: awsVpcId, AwsSubnetId: awsSubnetId, @@ -611,7 +611,7 @@ func createVpnTunnel(cmd *cobra.Command, args []string) { /////////////////////////////////////////////////////////////////////////////////////////////////// // mc-terrarium: Create GCP-AWS VPN tunnel - urlCreateGcpToAwsVpnTunnel := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws", epTerrarium, rgId) + urlCreateGcpToAwsVpnTunnel := fmt.Sprintf("%s/rg/%s/vpn/gcp-aws", epTerrarium, trId) respBytes, err = callApi("POST", urlCreateGcpToAwsVpnTunnel, authTerrarium, nil) if err != nil { @@ -646,25 +646,25 @@ func createVpnTunnel(cmd *cobra.Command, args []string) { func destroyVpnTunnel(cmd *cobra.Command, args []string) { - // Set resource group ID - rgId, _ := cmd.Flags().GetString("rgId") + // Set Terrarium ID + rgId, _ := cmd.Flags().GetString("trId") log.Debug(). - Str("Resource group ID", rgId). + Str("Terrarium ID", rgId). Msg("[args]") if rgId == "" { - rgId = viper.GetString("terrarium.demo.resourceGroupId") + rgId = viper.GetString("terrarium.demo.terrariumId") } log.Debug(). - Str("Resource group ID", rgId). + Str("Terrarium ID", rgId). Msg("[config.yaml]") if rgId == "" { err := fmt.Errorf("bad request: nsId, mcisId, or rgId is not set") log.Fatal().Err(err). - Str("Resource group ID", rgId). + Str("Terrarium ID", rgId). Msg("Please set the values in the config file or pass them as arguments") return } diff --git a/src/testclient/test-clis/vpn-tunnel/gcp-aws/config.yaml b/src/testclient/test-clis/vpn-tunnel/gcp-aws/config.yaml index 87c7b9e2..ea39ca31 100644 --- a/src/testclient/test-clis/vpn-tunnel/gcp-aws/config.yaml +++ b/src/testclient/test-clis/vpn-tunnel/gcp-aws/config.yaml @@ -14,4 +14,4 @@ terrarium: auth: info: auth.json demo: - resourceGroupId: kdemo-rg01 + terrariumId: kdemo-rg01