diff --git a/api/swagger/docs.go b/api/swagger/docs.go index fbfc0d1a..4c143e62 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -497,6 +497,37 @@ const docTemplate = `{ } } }, + "/auth/ping": { + "post": { + "description": "ping with token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Auth" + ], + "summary": "ping with token", + "parameters": [ + { + "description": "token info", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.PingTokenRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/clusters": { "get": { "security": [ @@ -675,6 +706,131 @@ const docTemplate = `{ } } }, + "/clusters/{clusterId}/bootstrap-kubeconfig": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get bootstrap kubeconfig for BYOH", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Get bootstrap kubeconfig for BYOH", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetBootstrapKubeconfigResponse" + } + } + } + }, + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Create bootstrap kubeconfig for BYOH", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Create bootstrap kubeconfig for BYOH", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CreateBootstrapKubeconfigResponse" + } + } + } + } + }, + "/clusters/{clusterId}/install": { + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Install cluster on tks cluster", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Install cluster on tks cluster", + "parameters": [ + { + "type": "string", + "description": "clusterId", + "name": "clusterId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/clusters/{clusterId}/nodes": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get nodes information for BYOH", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Get nodes information for BYOH", + "parameters": [ + { + "type": "string", + "description": "clusterId", + "name": "clusterId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetClusterNodesResponse" + } + } + } + } + }, "/clusters/{clusterId}/site-values": { "get": { "security": [ @@ -2114,6 +2270,50 @@ const docTemplate = `{ } } }, + "/organizations/{organizationId}/cloud-accounts/{cloudAccountId}/quota": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get resource quota by cloudAccount", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "CloudAccounts" + ], + "summary": "Get resource quota by cloudAccount", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "cloudAccountId", + "name": "cloudAccountId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetCloudAccountResourceQuotaResponse" + } + } + } + } + }, "/organizations/{organizationId}/dashboard/charts": { "get": { "security": [ @@ -2835,6 +3035,86 @@ const docTemplate = `{ } } }, + "/organizations/{organizationId}/stacks/{stackId}/favorite": { + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Set favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Set favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "security": [ + { + "JWT": [] + } + ], + "description": "Delete favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Delete favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/organizations/{organizationId}/stacks/{stackId}/kube-config": { "get": { "security": [ @@ -3725,6 +4005,10 @@ const docTemplate = `{ "description": "endpoint URL of deployed app", "type": "string" }, + "grafanaUrl": { + "description": "grafana dashboard URL for deployed app", + "type": "string" + }, "id": { "type": "string" }, @@ -3902,6 +4186,14 @@ const docTemplate = `{ } } }, + "domain.BootstrapKubeconfig": { + "type": "object", + "properties": { + "expiration": { + "type": "integer" + } + } + }, "domain.ChartData": { "type": "object", "properties": { @@ -4064,12 +4356,24 @@ const docTemplate = `{ "domain.Cluster": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.CloudAccount" }, "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "integer" + }, "conf": { "$ref": "#/definitions/domain.ClusterConf" }, @@ -4085,9 +4389,15 @@ const docTemplate = `{ "description": { "type": "string" }, + "favorited": { + "type": "boolean" + }, "id": { "type": "string" }, + "isStack": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -4120,22 +4430,31 @@ const docTemplate = `{ "domain.ClusterConf": { "type": "object", "properties": { - "cpNodeCnt": { + "tksCpNode": { "type": "integer" }, - "cpNodeMachineType": { + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { "type": "string" }, - "tksNodeCnt": { + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { "type": "integer" }, - "tksNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "userNodeCnt": { + "tksUserNode": { "type": "integer" }, - "userNodeMachineType": { + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { "type": "string" } } @@ -4143,13 +4462,74 @@ const docTemplate = `{ "domain.ClusterConfResponse": { "type": "object", "properties": { - "cpNodeCnt": { + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { + "type": "integer" + }, + "tksInfraNodeType": { + "type": "string" + }, + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { + "type": "string" + } + } + }, + "domain.ClusterHost": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.ClusterNode": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ClusterHost" + } + }, + "registered": { "type": "integer" }, - "tksNodeCnt": { + "registering": { "type": "integer" }, - "userpNodeCnt": { + "status": { + "type": "string" + }, + "targeted": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "validity": { "type": "integer" } } @@ -4157,9 +4537,21 @@ const docTemplate = `{ "domain.ClusterResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.SimpleCloudAccountResponse" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "string" + }, "conf": { "$ref": "#/definitions/domain.ClusterConfResponse" }, @@ -4175,6 +4567,9 @@ const docTemplate = `{ "id": { "type": "string" }, + "isStack": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -4201,34 +4596,43 @@ const docTemplate = `{ "domain.ClusterSiteValuesResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "clusterRegion": { "type": "string" }, - "cpNodeMachineType": { + "sshKeyName": { "type": "string" }, - "cpReplicas": { + "tksCpNode": { "type": "integer" }, - "mdMachineType": { - "type": "string" - }, - "mdMaxSizePerAz": { + "tksCpNodeMax": { "type": "integer" }, - "mdMinSizePerAz": { + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { "type": "integer" }, - "mdNumOfAz": { + "tksInfraNodeMax": { "type": "integer" }, - "mpNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "mpReplicas": { + "tksUserNode": { "type": "integer" }, - "sshKeyName": { + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { "type": "string" } } @@ -4358,6 +4762,14 @@ const docTemplate = `{ } } }, + "domain.CreateBootstrapKubeconfigResponse": { + "type": "object", + "properties": { + "kubeconfig": { + "$ref": "#/definitions/domain.BootstrapKubeconfig" + } + } + }, "domain.CreateCloudAccountRequest": { "type": "object", "required": [ @@ -4413,24 +4825,37 @@ const docTemplate = `{ "domain.CreateClusterRequest": { "type": "object", "required": [ - "cloudAccountId", + "cloudService", "name", "organizationId", "stackTemplateId" ], "properties": { - "cloudAccountId": { + "byoClusterEndpointHost": { "type": "string" }, - "cpNodeCnt": { + "byoClusterEndpointPort": { "type": "integer" }, - "cpNodeMachineType": { + "cloudAccountId": { + "type": "string" + }, + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] + }, + "clusterType": { "type": "string" }, "description": { "type": "string" }, + "isStack": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -4440,16 +4865,31 @@ const docTemplate = `{ "stackTemplateId": { "type": "string" }, - "tksNodeCnt": { + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { "type": "integer" }, - "tksNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "userNodeCnt": { + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { "type": "integer" }, - "userNodeMachineType": { + "tksUserNodeType": { "type": "string" } } @@ -4488,20 +4928,22 @@ const docTemplate = `{ "domain.CreateStackRequest": { "type": "object", "required": [ - "cloudAccountId", + "cloudService", "name", - "stackTemplateId", - "tksNodeCnt", - "userNodeCnt" + "stackTemplateId" ], "properties": { "cloudAccountId": { "type": "string" }, - "cpNodeCnt": { - "type": "integer" + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] }, - "cpNodeMachineType": { + "clusterId": { "type": "string" }, "description": { @@ -4513,20 +4955,34 @@ const docTemplate = `{ "stackTemplateId": { "type": "string" }, - "tksNodeCnt": { - "type": "integer", - "maximum": 6, - "minimum": 3 + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" }, - "tksNodeMachineType": { + "tksCpNodeType": { "type": "string" }, - "userNodeCnt": { - "type": "integer", - "maximum": 100, - "minimum": 0 + "tksInfraNode": { + "type": "integer" }, - "userNodeMachineType": { + "tksInfraNodeMax": { + "type": "integer" + }, + "tksInfraNodeType": { + "type": "string" + }, + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { + "type": "string" + }, + "userClusterEndpoint": { "type": "string" } } @@ -4568,6 +5024,13 @@ const docTemplate = `{ "template": { "type": "string" }, + "templateType": { + "type": "string", + "enum": [ + "STANDARD", + "MSA" + ] + }, "version": { "type": "string" } @@ -4914,6 +5377,25 @@ const docTemplate = `{ } } }, + "domain.GetBootstrapKubeconfigResponse": { + "type": "object", + "properties": { + "kubeconfig": { + "$ref": "#/definitions/domain.BootstrapKubeconfig" + } + } + }, + "domain.GetCloudAccountResourceQuotaResponse": { + "type": "object", + "properties": { + "available": { + "type": "boolean" + }, + "resourceQuota": { + "$ref": "#/definitions/domain.ResourceQuota" + } + } + }, "domain.GetCloudAccountResponse": { "type": "object", "properties": { @@ -4936,6 +5418,17 @@ const docTemplate = `{ } } }, + "domain.GetClusterNodesResponse": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ClusterNode" + } + } + } + }, "domain.GetClustersResponse": { "type": "object", "properties": { @@ -5363,6 +5856,21 @@ const docTemplate = `{ } } }, + "domain.PingTokenRequest": { + "type": "object", + "required": [ + "organizationId", + "token" + ], + "properties": { + "organizationId": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, "domain.PodCount": { "type": "object", "properties": { @@ -5374,6 +5882,34 @@ const docTemplate = `{ } } }, + "domain.ResourceQuota": { + "type": "object", + "properties": { + "quotas": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ResourceQuotaAttr" + } + } + } + }, + "domain.ResourceQuotaAttr": { + "type": "object", + "properties": { + "quota": { + "type": "integer" + }, + "required": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "usage": { + "type": "integer" + } + } + }, "domain.Role": { "type": "object", "properties": { @@ -5463,6 +5999,12 @@ const docTemplate = `{ "name": { "type": "string" }, + "services": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.StackTemplateServiceResponse" + } + }, "template": { "type": "string" } @@ -5484,23 +6026,40 @@ const docTemplate = `{ }, "domain.StackConfResponse": { "type": "object", + "required": [ + "tksInfraNode", + "tksUserNode" + ], "properties": { - "cpNodeCnt": { + "tksCpNode": { "type": "integer" }, - "cpNodeMachineType": { + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { "type": "string" }, - "tksNodeCnt": { + "tksInfraNode": { + "type": "integer", + "maximum": 3, + "minimum": 1 + }, + "tksInfraNodeMax": { "type": "integer" }, - "tksNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "userNodeCnt": { + "tksUserNode": { + "type": "integer", + "maximum": 100, + "minimum": 0 + }, + "tksUserNodeMax": { "type": "integer" }, - "userNodeMachineType": { + "tksUserNodeType": { "type": "string" } } @@ -5523,6 +6082,9 @@ const docTemplate = `{ "description": { "type": "string" }, + "favorited": { + "type": "boolean" + }, "grafanaUrl": { "type": "string" }, @@ -5538,6 +6100,9 @@ const docTemplate = `{ "primaryCluster": { "type": "boolean" }, + "resource": { + "$ref": "#/definitions/domain.DashboardStackResponse" + }, "stackTemplate": { "$ref": "#/definitions/domain.SimpleStackTemplateResponse" }, @@ -5552,6 +6117,9 @@ const docTemplate = `{ }, "updator": { "$ref": "#/definitions/domain.SimpleUserResponse" + }, + "userClusterEndpoint": { + "type": "string" } } }, @@ -5617,6 +6185,9 @@ const docTemplate = `{ "template": { "type": "string" }, + "templateType": { + "type": "string" + }, "updatedAt": { "type": "string" }, @@ -5670,6 +6241,9 @@ const docTemplate = `{ "template": { "type": "string" }, + "templateType": { + "type": "string" + }, "updatedAt": { "type": "string" }, diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 7682a695..40239746 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -490,6 +490,37 @@ } } }, + "/auth/ping": { + "post": { + "description": "ping with token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Auth" + ], + "summary": "ping with token", + "parameters": [ + { + "description": "token info", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.PingTokenRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/clusters": { "get": { "security": [ @@ -668,6 +699,131 @@ } } }, + "/clusters/{clusterId}/bootstrap-kubeconfig": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get bootstrap kubeconfig for BYOH", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Get bootstrap kubeconfig for BYOH", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetBootstrapKubeconfigResponse" + } + } + } + }, + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Create bootstrap kubeconfig for BYOH", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Create bootstrap kubeconfig for BYOH", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CreateBootstrapKubeconfigResponse" + } + } + } + } + }, + "/clusters/{clusterId}/install": { + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Install cluster on tks cluster", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Install cluster on tks cluster", + "parameters": [ + { + "type": "string", + "description": "clusterId", + "name": "clusterId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/clusters/{clusterId}/nodes": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get nodes information for BYOH", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Clusters" + ], + "summary": "Get nodes information for BYOH", + "parameters": [ + { + "type": "string", + "description": "clusterId", + "name": "clusterId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetClusterNodesResponse" + } + } + } + } + }, "/clusters/{clusterId}/site-values": { "get": { "security": [ @@ -2107,6 +2263,50 @@ } } }, + "/organizations/{organizationId}/cloud-accounts/{cloudAccountId}/quota": { + "get": { + "security": [ + { + "JWT": [] + } + ], + "description": "Get resource quota by cloudAccount", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "CloudAccounts" + ], + "summary": "Get resource quota by cloudAccount", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "cloudAccountId", + "name": "cloudAccountId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.GetCloudAccountResourceQuotaResponse" + } + } + } + } + }, "/organizations/{organizationId}/dashboard/charts": { "get": { "security": [ @@ -2828,6 +3028,86 @@ } } }, + "/organizations/{organizationId}/stacks/{stackId}/favorite": { + "post": { + "security": [ + { + "JWT": [] + } + ], + "description": "Set favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Set favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "security": [ + { + "JWT": [] + } + ], + "description": "Delete favorite stack", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Stacks" + ], + "summary": "Delete favorite stack", + "parameters": [ + { + "type": "string", + "description": "organizationId", + "name": "organizationId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "stackId", + "name": "stackId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/organizations/{organizationId}/stacks/{stackId}/kube-config": { "get": { "security": [ @@ -3718,6 +3998,10 @@ "description": "endpoint URL of deployed app", "type": "string" }, + "grafanaUrl": { + "description": "grafana dashboard URL for deployed app", + "type": "string" + }, "id": { "type": "string" }, @@ -3895,6 +4179,14 @@ } } }, + "domain.BootstrapKubeconfig": { + "type": "object", + "properties": { + "expiration": { + "type": "integer" + } + } + }, "domain.ChartData": { "type": "object", "properties": { @@ -4057,12 +4349,24 @@ "domain.Cluster": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.CloudAccount" }, "cloudAccountId": { "type": "string" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "integer" + }, "conf": { "$ref": "#/definitions/domain.ClusterConf" }, @@ -4078,9 +4382,15 @@ "description": { "type": "string" }, + "favorited": { + "type": "boolean" + }, "id": { "type": "string" }, + "isStack": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -4113,22 +4423,31 @@ "domain.ClusterConf": { "type": "object", "properties": { - "cpNodeCnt": { + "tksCpNode": { "type": "integer" }, - "cpNodeMachineType": { + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { "type": "string" }, - "tksNodeCnt": { + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { "type": "integer" }, - "tksNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "userNodeCnt": { + "tksUserNode": { "type": "integer" }, - "userNodeMachineType": { + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { "type": "string" } } @@ -4136,13 +4455,74 @@ "domain.ClusterConfResponse": { "type": "object", "properties": { - "cpNodeCnt": { + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { + "type": "integer" + }, + "tksInfraNodeType": { + "type": "string" + }, + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { + "type": "string" + } + } + }, + "domain.ClusterHost": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.ClusterNode": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ClusterHost" + } + }, + "registered": { "type": "integer" }, - "tksNodeCnt": { + "registering": { "type": "integer" }, - "userpNodeCnt": { + "status": { + "type": "string" + }, + "targeted": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "validity": { "type": "integer" } } @@ -4150,9 +4530,21 @@ "domain.ClusterResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "cloudAccount": { "$ref": "#/definitions/domain.SimpleCloudAccountResponse" }, + "cloudService": { + "type": "string" + }, + "clusterType": { + "type": "string" + }, "conf": { "$ref": "#/definitions/domain.ClusterConfResponse" }, @@ -4168,6 +4560,9 @@ "id": { "type": "string" }, + "isStack": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -4194,34 +4589,43 @@ "domain.ClusterSiteValuesResponse": { "type": "object", "properties": { + "byoClusterEndpointHost": { + "type": "string" + }, + "byoClusterEndpointPort": { + "type": "integer" + }, "clusterRegion": { "type": "string" }, - "cpNodeMachineType": { + "sshKeyName": { "type": "string" }, - "cpReplicas": { + "tksCpNode": { "type": "integer" }, - "mdMachineType": { - "type": "string" - }, - "mdMaxSizePerAz": { + "tksCpNodeMax": { "type": "integer" }, - "mdMinSizePerAz": { + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { "type": "integer" }, - "mdNumOfAz": { + "tksInfraNodeMax": { "type": "integer" }, - "mpNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "mpReplicas": { + "tksUserNode": { "type": "integer" }, - "sshKeyName": { + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { "type": "string" } } @@ -4351,6 +4755,14 @@ } } }, + "domain.CreateBootstrapKubeconfigResponse": { + "type": "object", + "properties": { + "kubeconfig": { + "$ref": "#/definitions/domain.BootstrapKubeconfig" + } + } + }, "domain.CreateCloudAccountRequest": { "type": "object", "required": [ @@ -4406,24 +4818,37 @@ "domain.CreateClusterRequest": { "type": "object", "required": [ - "cloudAccountId", + "cloudService", "name", "organizationId", "stackTemplateId" ], "properties": { - "cloudAccountId": { + "byoClusterEndpointHost": { "type": "string" }, - "cpNodeCnt": { + "byoClusterEndpointPort": { "type": "integer" }, - "cpNodeMachineType": { + "cloudAccountId": { + "type": "string" + }, + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] + }, + "clusterType": { "type": "string" }, "description": { "type": "string" }, + "isStack": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -4433,16 +4858,31 @@ "stackTemplateId": { "type": "string" }, - "tksNodeCnt": { + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { + "type": "string" + }, + "tksInfraNode": { + "type": "integer" + }, + "tksInfraNodeMax": { "type": "integer" }, - "tksNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "userNodeCnt": { + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { "type": "integer" }, - "userNodeMachineType": { + "tksUserNodeType": { "type": "string" } } @@ -4481,20 +4921,22 @@ "domain.CreateStackRequest": { "type": "object", "required": [ - "cloudAccountId", + "cloudService", "name", - "stackTemplateId", - "tksNodeCnt", - "userNodeCnt" + "stackTemplateId" ], "properties": { "cloudAccountId": { "type": "string" }, - "cpNodeCnt": { - "type": "integer" + "cloudService": { + "type": "string", + "enum": [ + "AWS", + "BYOH" + ] }, - "cpNodeMachineType": { + "clusterId": { "type": "string" }, "description": { @@ -4506,20 +4948,34 @@ "stackTemplateId": { "type": "string" }, - "tksNodeCnt": { - "type": "integer", - "maximum": 6, - "minimum": 3 + "tksCpNode": { + "type": "integer" + }, + "tksCpNodeMax": { + "type": "integer" }, - "tksNodeMachineType": { + "tksCpNodeType": { "type": "string" }, - "userNodeCnt": { - "type": "integer", - "maximum": 100, - "minimum": 0 + "tksInfraNode": { + "type": "integer" }, - "userNodeMachineType": { + "tksInfraNodeMax": { + "type": "integer" + }, + "tksInfraNodeType": { + "type": "string" + }, + "tksUserNode": { + "type": "integer" + }, + "tksUserNodeMax": { + "type": "integer" + }, + "tksUserNodeType": { + "type": "string" + }, + "userClusterEndpoint": { "type": "string" } } @@ -4561,6 +5017,13 @@ "template": { "type": "string" }, + "templateType": { + "type": "string", + "enum": [ + "STANDARD", + "MSA" + ] + }, "version": { "type": "string" } @@ -4907,6 +5370,25 @@ } } }, + "domain.GetBootstrapKubeconfigResponse": { + "type": "object", + "properties": { + "kubeconfig": { + "$ref": "#/definitions/domain.BootstrapKubeconfig" + } + } + }, + "domain.GetCloudAccountResourceQuotaResponse": { + "type": "object", + "properties": { + "available": { + "type": "boolean" + }, + "resourceQuota": { + "$ref": "#/definitions/domain.ResourceQuota" + } + } + }, "domain.GetCloudAccountResponse": { "type": "object", "properties": { @@ -4929,6 +5411,17 @@ } } }, + "domain.GetClusterNodesResponse": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ClusterNode" + } + } + } + }, "domain.GetClustersResponse": { "type": "object", "properties": { @@ -5356,6 +5849,21 @@ } } }, + "domain.PingTokenRequest": { + "type": "object", + "required": [ + "organizationId", + "token" + ], + "properties": { + "organizationId": { + "type": "string" + }, + "token": { + "type": "string" + } + } + }, "domain.PodCount": { "type": "object", "properties": { @@ -5367,6 +5875,34 @@ } } }, + "domain.ResourceQuota": { + "type": "object", + "properties": { + "quotas": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ResourceQuotaAttr" + } + } + } + }, + "domain.ResourceQuotaAttr": { + "type": "object", + "properties": { + "quota": { + "type": "integer" + }, + "required": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "usage": { + "type": "integer" + } + } + }, "domain.Role": { "type": "object", "properties": { @@ -5456,6 +5992,12 @@ "name": { "type": "string" }, + "services": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.StackTemplateServiceResponse" + } + }, "template": { "type": "string" } @@ -5477,23 +6019,40 @@ }, "domain.StackConfResponse": { "type": "object", + "required": [ + "tksInfraNode", + "tksUserNode" + ], "properties": { - "cpNodeCnt": { + "tksCpNode": { "type": "integer" }, - "cpNodeMachineType": { + "tksCpNodeMax": { + "type": "integer" + }, + "tksCpNodeType": { "type": "string" }, - "tksNodeCnt": { + "tksInfraNode": { + "type": "integer", + "maximum": 3, + "minimum": 1 + }, + "tksInfraNodeMax": { "type": "integer" }, - "tksNodeMachineType": { + "tksInfraNodeType": { "type": "string" }, - "userNodeCnt": { + "tksUserNode": { + "type": "integer", + "maximum": 100, + "minimum": 0 + }, + "tksUserNodeMax": { "type": "integer" }, - "userNodeMachineType": { + "tksUserNodeType": { "type": "string" } } @@ -5516,6 +6075,9 @@ "description": { "type": "string" }, + "favorited": { + "type": "boolean" + }, "grafanaUrl": { "type": "string" }, @@ -5531,6 +6093,9 @@ "primaryCluster": { "type": "boolean" }, + "resource": { + "$ref": "#/definitions/domain.DashboardStackResponse" + }, "stackTemplate": { "$ref": "#/definitions/domain.SimpleStackTemplateResponse" }, @@ -5545,6 +6110,9 @@ }, "updator": { "$ref": "#/definitions/domain.SimpleUserResponse" + }, + "userClusterEndpoint": { + "type": "string" } } }, @@ -5610,6 +6178,9 @@ "template": { "type": "string" }, + "templateType": { + "type": "string" + }, "updatedAt": { "type": "string" }, @@ -5663,6 +6234,9 @@ "template": { "type": "string" }, + "templateType": { + "type": "string" + }, "updatedAt": { "type": "string" }, diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 5f015d41..69c95af2 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -124,6 +124,9 @@ definitions: endpointUrl: description: endpoint URL of deployed app type: string + grafanaUrl: + description: grafana dashboard URL for deployed app + type: string id: type: string name: @@ -249,6 +252,11 @@ definitions: type: string type: array type: object + domain.BootstrapKubeconfig: + properties: + expiration: + type: integer + type: object domain.ChartData: properties: podCounts: @@ -355,10 +363,18 @@ definitions: type: object domain.Cluster: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer cloudAccount: $ref: '#/definitions/domain.CloudAccount' cloudAccountId: type: string + cloudService: + type: string + clusterType: + type: integer conf: $ref: '#/definitions/domain.ClusterConf' createdAt: @@ -369,8 +385,12 @@ definitions: type: string description: type: string + favorited: + type: boolean id: type: string + isStack: + type: boolean name: type: string organizationId: @@ -392,32 +412,86 @@ definitions: type: object domain.ClusterConf: properties: - cpNodeCnt: + tksCpNode: type: integer - cpNodeMachineType: + tksCpNodeMax: + type: integer + tksCpNodeType: type: string - tksNodeCnt: + tksInfraNode: + type: integer + tksInfraNodeMax: type: integer - tksNodeMachineType: + tksInfraNodeType: type: string - userNodeCnt: + tksUserNode: type: integer - userNodeMachineType: + tksUserNodeMax: + type: integer + tksUserNodeType: type: string type: object domain.ClusterConfResponse: properties: - cpNodeCnt: + tksCpNode: + type: integer + tksCpNodeMax: type: integer - tksNodeCnt: + tksCpNodeType: + type: string + tksInfraNode: type: integer - userpNodeCnt: + tksInfraNodeMax: + type: integer + tksInfraNodeType: + type: string + tksUserNode: + type: integer + tksUserNodeMax: + type: integer + tksUserNodeType: + type: string + type: object + domain.ClusterHost: + properties: + name: + type: string + status: + type: string + type: object + domain.ClusterNode: + properties: + command: + type: string + hosts: + items: + $ref: '#/definitions/domain.ClusterHost' + type: array + registered: + type: integer + registering: + type: integer + status: + type: string + targeted: + type: integer + type: + type: string + validity: type: integer type: object domain.ClusterResponse: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer cloudAccount: $ref: '#/definitions/domain.SimpleCloudAccountResponse' + cloudService: + type: string + clusterType: + type: string conf: $ref: '#/definitions/domain.ClusterConfResponse' createdAt: @@ -428,6 +502,8 @@ definitions: type: string id: type: string + isStack: + type: boolean name: type: string organizationId: @@ -445,25 +521,31 @@ definitions: type: object domain.ClusterSiteValuesResponse: properties: + byoClusterEndpointHost: + type: string + byoClusterEndpointPort: + type: integer clusterRegion: type: string - cpNodeMachineType: + sshKeyName: type: string - cpReplicas: + tksCpNode: type: integer - mdMachineType: - type: string - mdMaxSizePerAz: + tksCpNodeMax: type: integer - mdMinSizePerAz: + tksCpNodeType: + type: string + tksInfraNode: type: integer - mdNumOfAz: + tksInfraNodeMax: type: integer - mpNodeMachineType: + tksInfraNodeType: type: string - mpReplicas: + tksUserNode: type: integer - sshKeyName: + tksUserNodeMax: + type: integer + tksUserNodeType: type: string type: object domain.CreateAppGroupRequest: @@ -551,6 +633,11 @@ definitions: metadata: type: string type: object + domain.CreateBootstrapKubeconfigResponse: + properties: + kubeconfig: + $ref: '#/definitions/domain.BootstrapKubeconfig' + type: object domain.CreateCloudAccountRequest: properties: accessKeyId: @@ -591,30 +678,49 @@ definitions: type: object domain.CreateClusterRequest: properties: - cloudAccountId: + byoClusterEndpointHost: type: string - cpNodeCnt: + byoClusterEndpointPort: type: integer - cpNodeMachineType: + cloudAccountId: + type: string + cloudService: + enum: + - AWS + - BYOH + type: string + clusterType: type: string description: type: string + isStack: + type: boolean name: type: string organizationId: type: string stackTemplateId: type: string - tksNodeCnt: + tksCpNode: + type: integer + tksCpNodeMax: + type: integer + tksCpNodeType: + type: string + tksInfraNode: + type: integer + tksInfraNodeMax: type: integer - tksNodeMachineType: + tksInfraNodeType: type: string - userNodeCnt: + tksUserNode: type: integer - userNodeMachineType: + tksUserNodeMax: + type: integer + tksUserNodeType: type: string required: - - cloudAccountId + - cloudService - name - organizationId - stackTemplateId @@ -644,9 +750,12 @@ definitions: properties: cloudAccountId: type: string - cpNodeCnt: - type: integer - cpNodeMachineType: + cloudService: + enum: + - AWS + - BYOH + type: string + clusterId: type: string description: type: string @@ -654,24 +763,30 @@ definitions: type: string stackTemplateId: type: string - tksNodeCnt: - maximum: 6 - minimum: 3 + tksCpNode: type: integer - tksNodeMachineType: + tksCpNodeMax: + type: integer + tksCpNodeType: type: string - userNodeCnt: - maximum: 100 - minimum: 0 + tksInfraNode: + type: integer + tksInfraNodeMax: type: integer - userNodeMachineType: + tksInfraNodeType: + type: string + tksUserNode: + type: integer + tksUserNodeMax: + type: integer + tksUserNodeType: + type: string + userClusterEndpoint: type: string required: - - cloudAccountId + - cloudService - name - stackTemplateId - - tksNodeCnt - - userNodeCnt type: object domain.CreateStackResponse: properties: @@ -694,6 +809,11 @@ definitions: type: string template: type: string + templateType: + enum: + - STANDARD + - MSA + type: string version: type: string required: @@ -930,6 +1050,18 @@ definitions: $ref: '#/definitions/domain.ApplicationResponse' type: array type: object + domain.GetBootstrapKubeconfigResponse: + properties: + kubeconfig: + $ref: '#/definitions/domain.BootstrapKubeconfig' + type: object + domain.GetCloudAccountResourceQuotaResponse: + properties: + available: + type: boolean + resourceQuota: + $ref: '#/definitions/domain.ResourceQuota' + type: object domain.GetCloudAccountResponse: properties: cloudAccount: @@ -944,6 +1076,13 @@ definitions: pagination: $ref: '#/definitions/domain.PaginationResponse' type: object + domain.GetClusterNodesResponse: + properties: + nodes: + items: + $ref: '#/definitions/domain.ClusterNode' + type: array + type: object domain.GetClustersResponse: properties: clusters: @@ -1221,6 +1360,16 @@ definitions: totalRows: type: integer type: object + domain.PingTokenRequest: + properties: + organizationId: + type: string + token: + type: string + required: + - organizationId + - token + type: object domain.PodCount: properties: day: @@ -1228,6 +1377,24 @@ definitions: value: type: integer type: object + domain.ResourceQuota: + properties: + quotas: + items: + $ref: '#/definitions/domain.ResourceQuotaAttr' + type: array + type: object + domain.ResourceQuotaAttr: + properties: + quota: + type: integer + required: + type: integer + type: + type: string + usage: + type: integer + type: object domain.Role: properties: createdAt: @@ -1286,6 +1453,10 @@ definitions: type: string name: type: string + services: + items: + $ref: '#/definitions/domain.StackTemplateServiceResponse' + type: array template: type: string type: object @@ -1300,18 +1471,31 @@ definitions: type: object domain.StackConfResponse: properties: - cpNodeCnt: + tksCpNode: + type: integer + tksCpNodeMax: type: integer - cpNodeMachineType: + tksCpNodeType: type: string - tksNodeCnt: + tksInfraNode: + maximum: 3 + minimum: 1 type: integer - tksNodeMachineType: + tksInfraNodeMax: + type: integer + tksInfraNodeType: type: string - userNodeCnt: + tksUserNode: + maximum: 100 + minimum: 0 + type: integer + tksUserNodeMax: type: integer - userNodeMachineType: + tksUserNodeType: type: string + required: + - tksInfraNode + - tksUserNode type: object domain.StackResponse: properties: @@ -1325,6 +1509,8 @@ definitions: $ref: '#/definitions/domain.SimpleUserResponse' description: type: string + favorited: + type: boolean grafanaUrl: type: string id: @@ -1335,6 +1521,8 @@ definitions: type: string primaryCluster: type: boolean + resource: + $ref: '#/definitions/domain.DashboardStackResponse' stackTemplate: $ref: '#/definitions/domain.SimpleStackTemplateResponse' status: @@ -1345,6 +1533,8 @@ definitions: type: string updator: $ref: '#/definitions/domain.SimpleUserResponse' + userClusterEndpoint: + type: string type: object domain.StackStepStatus: properties: @@ -1387,6 +1577,8 @@ definitions: type: array template: type: string + templateType: + type: string updatedAt: type: string updator: @@ -1422,6 +1614,8 @@ definitions: type: array template: type: string + templateType: + type: string updatedAt: type: string updator: @@ -2076,6 +2270,26 @@ paths: summary: logout tags: - Auth + /auth/ping: + post: + consumes: + - application/json + description: ping with token + parameters: + - description: token info + in: body + name: body + required: true + schema: + $ref: '#/definitions/domain.PingTokenRequest' + produces: + - application/json + responses: + "200": + description: OK + summary: ping with token + tags: + - Auth /clusters: get: consumes: @@ -2188,6 +2402,83 @@ paths: summary: Get cluster tags: - Clusters + /clusters/{clusterId}/bootstrap-kubeconfig: + get: + consumes: + - application/json + description: Get bootstrap kubeconfig for BYOH + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.GetBootstrapKubeconfigResponse' + security: + - JWT: [] + summary: Get bootstrap kubeconfig for BYOH + tags: + - Clusters + post: + consumes: + - application/json + description: Create bootstrap kubeconfig for BYOH + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.CreateBootstrapKubeconfigResponse' + security: + - JWT: [] + summary: Create bootstrap kubeconfig for BYOH + tags: + - Clusters + /clusters/{clusterId}/install: + post: + consumes: + - application/json + description: Install cluster on tks cluster + parameters: + - description: clusterId + in: path + name: clusterId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + security: + - JWT: [] + summary: Install cluster on tks cluster + tags: + - Clusters + /clusters/{clusterId}/nodes: + get: + consumes: + - application/json + description: Get nodes information for BYOH + parameters: + - description: clusterId + in: path + name: clusterId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.GetClusterNodesResponse' + security: + - JWT: [] + summary: Get nodes information for BYOH + tags: + - Clusters /clusters/{clusterId}/site-values: get: consumes: @@ -3048,6 +3339,34 @@ paths: summary: Delete Force CloudAccount tags: - CloudAccounts + /organizations/{organizationId}/cloud-accounts/{cloudAccountId}/quota: + get: + consumes: + - application/json + description: Get resource quota by cloudAccount + parameters: + - description: organizationId + in: path + name: organizationId + required: true + type: string + - description: cloudAccountId + in: path + name: cloudAccountId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.GetCloudAccountResourceQuotaResponse' + security: + - JWT: [] + summary: Get resource quota by cloudAccount + tags: + - CloudAccounts /organizations/{organizationId}/cloud-accounts/aws-account-id/{awsAccountId}/existence: get: consumes: @@ -3532,6 +3851,57 @@ paths: summary: Update Stack tags: - Stacks + /organizations/{organizationId}/stacks/{stackId}/favorite: + delete: + consumes: + - application/json + description: Delete favorite stack + parameters: + - description: organizationId + in: path + name: organizationId + required: true + type: string + - description: stackId + in: path + name: stackId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + security: + - JWT: [] + summary: Delete favorite stack + tags: + - Stacks + post: + consumes: + - application/json + description: Set favorite stack + parameters: + - description: organizationId + in: path + name: organizationId + required: true + type: string + - description: stackId + in: path + name: stackId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + security: + - JWT: [] + summary: Set favorite stack + tags: + - Stacks /organizations/{organizationId}/stacks/{stackId}/kube-config: get: consumes: diff --git a/cmd/server/main.go b/cmd/server/main.go index 854f4b34..9c0d298d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -6,14 +6,13 @@ import ( "net/http" "strconv" - "github.com/openinfradev/tks-api/internal/aws/ses" - "github.com/spf13/pflag" "github.com/spf13/viper" _ "github.com/openinfradev/tks-api/api/swagger" "github.com/openinfradev/tks-api/internal/database" "github.com/openinfradev/tks-api/internal/keycloak" + "github.com/openinfradev/tks-api/internal/mail" "github.com/openinfradev/tks-api/internal/route" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/log" @@ -34,6 +33,7 @@ func init() { flag.String("jwt-secret", "tks-api-secret", "secret value of jwt") flag.String("git-base-url", "https://github.com", "git base url") flag.String("git-account", "decapod10", "git account of admin cluster") + flag.String("external-gitea-url", "http://ip-10-0-76-86.ap-northeast-2.compute.internal:30303", "gitea url for byoh agent download") flag.String("revision", "main", "revision") flag.String("aws-secret", "awsconfig-secret", "aws secret") flag.Int("migrate-db", 1, "If the values is true, enable db migration. recommend only development") @@ -52,7 +52,14 @@ func init() { flag.String("keycloak-password", "admin", "password of keycloak") flag.String("keycloak-client-secret", keycloak.DefaultClientSecret, "realm of keycloak") - // aws ses + flag.String("mail-provider", "aws", "mail provider") + // mail (smtp) + flag.String("smtp-host", "", "smtp hosts") + flag.Int("smtp-port", 0, "smtp port") + flag.String("smtp-username", "", "smtp username") + flag.String("smtp-password", "", "smtp password") + flag.String("smtp-from-email", "", "smtp from email") + // mail (aws ses) flag.String("aws-region", "ap-northeast-2", "region of aws ses") flag.String("aws-access-key-id", "", "access key id of aws ses") flag.String("aws-secret-access-key", "", "access key of aws ses") @@ -127,7 +134,7 @@ func main() { if err != nil { log.Fatal("failed to initialize keycloak : ", err) } - err = ses.Initialize() + err = mail.Initialize() if err != nil { log.Fatal("failed to initialize ses : ", err) } diff --git a/go.mod b/go.mod index f09c8032..ff813bc2 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,14 @@ require ( github.com/Nerzal/gocloak/v13 v13.1.0 github.com/aws/aws-sdk-go-v2 v1.20.1 github.com/aws/aws-sdk-go-v2/config v1.18.32 + github.com/aws/aws-sdk-go-v2/credentials v1.13.31 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.110.1 + github.com/aws/aws-sdk-go-v2/service/eks v1.29.2 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.16.2 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.20.2 + github.com/aws/aws-sdk-go-v2/service/servicequotas v1.15.1 github.com/aws/aws-sdk-go-v2/service/ses v1.15.7 + github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/go-playground/locales v0.14.1 github.com/go-playground/universal-translator v0.18.1 @@ -17,6 +24,7 @@ require ( github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 + github.com/opentracing/opentracing-go v1.2.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.0 @@ -25,44 +33,39 @@ require ( github.com/swaggo/http-swagger v1.3.3 github.com/swaggo/swag v1.8.5 github.com/thoas/go-funk v0.9.3 + github.com/vmware-tanzu/cluster-api-provider-bringyourownhost v0.4.0 golang.org/x/crypto v0.7.0 + golang.org/x/net v0.8.0 + golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/yaml.v3 v3.0.1 gorm.io/datatypes v1.1.1 gorm.io/driver/postgres v1.4.5 gorm.io/gorm v1.25.0 - k8s.io/apimachinery v0.24.4 - k8s.io/client-go v0.24.4 - k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 + k8s.io/apimachinery v0.25.4 + k8s.io/client-go v0.25.2 + k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed ) require ( github.com/KyleBanks/depth v1.2.1 // indirect - github.com/aws/aws-sdk-go v1.44.317 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.31 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.110.1 // indirect - github.com/aws/aws-sdk-go-v2/service/eks v1.29.2 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.16.2 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.20.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2 // indirect - github.com/aws/aws-sdk-go-v2/service/servicequotas v1.15.1 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 // indirect github.com/aws/smithy-go v1.14.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful v2.9.5+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/spec v0.20.6 // indirect @@ -71,9 +74,11 @@ require ( github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/go-cmp v0.5.8 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -93,40 +98,46 @@ require ( github.com/lib/pq v1.10.4 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mailru/easyjson v0.7.6 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect github.com/segmentio/ksuid v1.0.4 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.3.0 // indirect github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.6.0 // indirect - golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.4.7 // indirect - k8s.io/api v0.24.4 // indirect - k8s.io/klog/v2 v2.60.1 // indirect - k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect - sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + k8s.io/api v0.25.4 // indirect + k8s.io/apiextensions-apiserver v0.23.5 // indirect + k8s.io/component-base v0.25.2 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect + sigs.k8s.io/cluster-api v1.1.3 // indirect + sigs.k8s.io/controller-runtime v0.11.2 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace github.com/openinfradev/tks-api => ./ diff --git a/go.sum b/go.sum index 316d72c9..4150f430 100644 --- a/go.sum +++ b/go.sum @@ -28,6 +28,7 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -39,6 +40,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= @@ -53,52 +56,43 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Nerzal/gocloak/v13 v13.1.0 h1:ret4pZTIsSQGZHURDMJ4jXnUmHyEoRykBqDTsAKoj8c= github.com/Nerzal/gocloak/v13 v13.1.0/go.mod h1:rRBtEdh5N0+JlZZEsrfZcB2sRMZWbgSxI2EIv9jpJp4= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.317 h1:+8XWrLmGMwPPXSRSLPzhgcGnzJ2mYkgkrcB9C/GnSOU= -github.com/aws/aws-sdk-go v1.44.317/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8= github.com/aws/aws-sdk-go-v2 v1.20.0/go.mod h1:uWOr0m0jDsiWw8nnXiqZ+YG6LdvAlGYDLLf2NmHZoy4= github.com/aws/aws-sdk-go-v2 v1.20.1 h1:rZBf5DWr7YGrnlTK4kgDQGn1ltqOg5orCYb/UhOFZkg= github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 h1:lN6L3LrYHeZ6xCxaIYtoWCx4GMLk4nRknsh29OMSqHY= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12/go.mod h1:TDCkEAkMTXxTs0oLBGBKpBZbk3NLh8EvAfF0Q3x8/0c= -github.com/aws/aws-sdk-go-v2/config v1.18.21 h1:ENTXWKwE8b9YXgQCsruGLhvA9bhg+RqAsL9XEMEsa2c= -github.com/aws/aws-sdk-go-v2/config v1.18.21/go.mod h1:+jPQiVPz1diRnjj6VGqWcLK6EzNmQ42l7J3OqGTLsSY= github.com/aws/aws-sdk-go-v2/config v1.18.32 h1:tqEOvkbTxwEV7hToRcJ1xZRjcATqwDVsWbAscgRKyNI= github.com/aws/aws-sdk-go-v2/config v1.18.32/go.mod h1:U3ZF0fQRRA4gnbn9GGvOWLoT2EzzZfAWeKwnVrm1rDc= -github.com/aws/aws-sdk-go-v2/credentials v1.13.20 h1:oZCEFcrMppP/CNiS8myzv9JgOzq2s0d3v3MXYil/mxQ= -github.com/aws/aws-sdk-go-v2/credentials v1.13.20/go.mod h1:xtZnXErtbZ8YGXC3+8WfajpMBn5Ga/3ojZdxHq6iI8o= github.com/aws/aws-sdk-go-v2/credentials v1.13.31 h1:vJyON3lG7R8VOErpJJBclBADiWTwzcwdkQpTKx8D2sk= github.com/aws/aws-sdk-go-v2/credentials v1.13.31/go.mod h1:T4sESjBtY2lNxLgkIASmeP57b5j7hTQqCbqG0tWnxC4= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 h1:jOzQAesnBFDmz93feqKnsTHsXrlwWORNZMFHMV+WLFU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2/go.mod h1:cDh1p6XkSGSwSRIArWRc6+UqAQ7x4alQ0QfpVR6f+co= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 h1:X3H6+SU21x+76LRglk21dFRgMTJMa5QcpW+SqUf5BBg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7/go.mod h1:3we0V09SwcJBzNlnyovrR2wWJhWmVdqAsmVs4uronv8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 h1:zr/gxAZkMcvP71ZhQOcvdm8ReLjFgIXnIn0fw5AM7mo= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37/go.mod h1:Pdn4j43v49Kk6+82spO3Tu5gSeQXRsxo56ePPQAvFiA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 h1:c8ed/T9T2K5I+h/JzmF5tpI46+OODQ74dzmdo+QnaMg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 h1:0HCMIkAkVY9KMgueD8tf4bRTUanzEYvhw7KkPXIMpO0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31/go.mod h1:fTJDMe8LOFYtqiFFFeHA+SVMAwqLhoq0kcInYoLa9Js= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 h1:hNeAAymUY5gu11WrrmFb3CVIp9Dar9hbo44yzzcQpzA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 h1:HbH1VjUgrCdLJ+4lnnuLI4iVNRvBbBELGaJ5f69ClA8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33/go.mod h1:zG2FcwjQarWaqXSCGpgcr3RSjZ6dHGguZSppUL0XR7Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 h1:+i1DOFrW3YZ3apE45tCal9+aDKK6kNEbW6Ib7e1nFxE= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38/go.mod h1:1/jLp0OgOaWIetycOmycW+vYTYgTZFPttJQRgsI1PoU= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1 h1:vUh7dBFNS3oFCtVv6CiYKh5hP9ls8+kIpKLeFruIBLk= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1/go.mod h1:sFMeinkhj/SZKQM8BxtvNtSPjJEo0Xrz+w3g2e4FSKI= github.com/aws/aws-sdk-go-v2/service/ec2 v1.110.1 h1:OaDeV+sdve2NV+kUheZX5bToHFmfIkflgOlZTKij0Bo= github.com/aws/aws-sdk-go-v2/service/ec2 v1.110.1/go.mod h1:Ie0Kp61cLk223argiS+t8vO29SpbFIphzlPflIvYcv0= github.com/aws/aws-sdk-go-v2/service/eks v1.29.2 h1:ZwK94/wSfjVrsp9UucUZOb3QCn6zL9Wru5KauaYQCBg= @@ -107,43 +101,41 @@ github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.16.2 h1:AnXbttLaoY2 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.16.2/go.mod h1:DYqqNwjoFTL0URDn5odwM4Pq455DHNlBmQXSAI2DbWs= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.20.2 h1:8TXQKxY0UjNAt/9nkDtfGechuri15a+yw9QtsEuOLtE= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.20.2/go.mod h1:AZv/T0/2rhNBLiY2k109TT6HJ7Z0P8Z+SYvs0jqVkXE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 h1:iV/W5OMBys+66OeXJi/7xIRrKZNsu0ylsLGu+6nbmQE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13/go.mod h1:ReJb6xYmtGyu9KoFtRreWegbN9dZqvZIIv4vWnhcsyI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33 h1:QviNkc+vGSuEHx8P+pVNKOdWLXBPIwMFv7p0fphgE4U= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33/go.mod h1:fABTUmOrAgAalG2i9WJpjBvlnk7UK8YmnYaxN+Q2CwE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 h1:uUt4XctZLhl9wBE1L8lobU3bVN8SNUP7T+olb0bWBO4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26/go.mod h1:Bd4C/4PkVGubtNe5iMXu5BNnaBi/9t/UsFspPt4ram8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 h1:auGDJ0aLZahF5SPvkJ6WcUuX7iQ7kyl2MamV7Tm8QBk= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31/go.mod h1:3+lloe3sZuBQw1aBc5MyndvodzQlyqCZ7x1QPDHaWP4= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 h1:dGAseBFEYxth10V23b5e2mAS+tX7oVbfYHD6dnDdAsg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1 h1:PT6PBCycRwhpEW5hJnRiceCeoWJ+r3bdgXtV+VKG7Pk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1/go.mod h1:TqoxCLwT2nrxrBGA+z7t6OWM7LBkgRckK3gOjYE+7JA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2 h1:v346f1h8sUBKXnEbrv43L37MTBlFHyKXQPIZHNAaghA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2/go.mod h1:cwCATiyNrXK9P2FsWdZ89g9mpsYv2rhk0UA/KByl5fY= github.com/aws/aws-sdk-go-v2/service/servicequotas v1.15.1 h1:ZL1ul+QW+JGT7my64SG8cPTudyLXRZXifPgJrpIA8qI= github.com/aws/aws-sdk-go-v2/service/servicequotas v1.15.1/go.mod h1:2rmOo0RfixF8lcXxkquMIb1SY9oPY0iY/Mau8w8nFNs= github.com/aws/aws-sdk-go-v2/service/ses v1.15.7 h1:eS3hpWtxVYnrysF+NEcjZo5zVvmgNTk22zRwJbtmCZY= github.com/aws/aws-sdk-go-v2/service/ses v1.15.7/go.mod h1:sDSPw06IV4uB+RByvHkqDZKfP7SgIataOehYkchSups= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 h1:5cb3D6xb006bPTqEfCNaEA6PPEfBXxxy4NNeX/44kGk= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.8/go.mod h1:GNIveDnP+aE3jujyUSH5aZ/rktsTM5EvtKnCqBZawdw= github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 h1:DSNpSbfEgFXRV+IfEcKE5kTbqxm+MeF5WgyeRlsLnHY= github.com/aws/aws-sdk-go-v2/service/sso v1.13.1/go.mod h1:TC9BubuFMVScIU+TLKamO6VZiYTkYoEHqlSQwAe2omw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 h1:NZaj0ngZMzsubWZbrEFSB4rgSQRbFq38Sd6KBxHuOIU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8/go.mod h1:44qFP1g7pfd+U+sQHLPalAPKnyfTZjJsYR4xIwsJy5o= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 h1:hd0SKLMdOL/Sl6Z0np1PX9LeH2gqNtBe0MhTedA8MGI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1/go.mod h1:XO/VcyoQ8nKyKfFW/3DMsRQXsfh/052tHTWmg3xBXRg= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 h1:Qf1aWwnsNkyAoqDqmdM3nHwN78XQjec27LjM6b9vyfI= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.9/go.mod h1:yyW88BEPXA2fGFyI2KCcZC3dNpiT0CZAHaF+i656/tQ= github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 h1:pAOJj+80tC8sPVgSDHzMYD6KLWsaLQ1kZw31PTeORbs= github.com/aws/aws-sdk-go-v2/service/sts v1.21.1/go.mod h1:G8SbvL0rFk4WOJroU8tKBczhsbhj2p/YY7qeJezJ3CI= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io= github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs= github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -151,29 +143,49 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -184,16 +196,24 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -219,8 +239,13 @@ github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSM github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/flect v0.2.4 h1:BSYA8+T60cdyq+vynaSUjqSVI9mDEg9ZfQUXKmfjo4I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -230,9 +255,12 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -265,6 +293,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -281,8 +311,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -304,7 +335,10 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -312,16 +346,39 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -369,6 +426,7 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -378,18 +436,30 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -406,86 +476,169 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -504,6 +657,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc= @@ -514,13 +668,27 @@ github.com/swaggo/swag v1.8.5 h1:7NgtfXsXE+jrcOwRyiftGKW7Ppydj7tZiVenuRf1fE4= github.com/swaggo/swag v1.8.5/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/vmware-tanzu/cluster-api-provider-bringyourownhost v0.4.0 h1:sP0eIUypeNWLgUXhkko79xEnfuhBjURyPxef7+4SjjE= +github.com/vmware-tanzu/cluster-api-provider-bringyourownhost v0.4.0/go.mod h1:qpFFjYuV3ATwNkHuUIWXePY/DcNUXFGlNXy0lDqoVlo= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -528,17 +696,40 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -551,9 +742,8 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= @@ -580,6 +770,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -591,11 +782,14 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -603,6 +797,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -626,18 +821,20 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -651,7 +848,9 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -665,10 +864,13 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -688,6 +890,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -702,36 +905,43 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -743,26 +953,31 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -770,6 +985,8 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -807,8 +1024,9 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -817,8 +1035,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -840,6 +1058,7 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -869,8 +1088,10 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -879,6 +1100,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -890,6 +1112,8 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -903,11 +1127,15 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -923,6 +1151,9 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -930,16 +1161,26 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -961,6 +1202,8 @@ gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -968,29 +1211,51 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.24.4 h1:I5Y645gJ8zWKawyr78lVfDQkZrAViSbeRXsPZWTxmXk= -k8s.io/api v0.24.4/go.mod h1:42pVfA0NRxrtJhZQOvRSyZcJihzAdU59WBtTjYcB0/M= -k8s.io/apimachinery v0.24.4 h1:S0Ur3J/PbivTcL43EdSdPhqCqKla2NIuneNwZcTDeGQ= -k8s.io/apimachinery v0.24.4/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/client-go v0.24.4 h1:hIAIJZIPyaw46AkxwyR0FRfM/pRxpUNTd3ysYu9vyRg= -k8s.io/client-go v0.24.4/go.mod h1:+AxlPWw/H6f+EJhRSjIeALaJT4tbeB/8g9BNvXGPd0Y= +k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= +k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs= +k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ= +k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI= +k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc= +k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= +k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw= +k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= +k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo= +k8s.io/client-go v0.25.2/go.mod h1:i7cNU7N+yGQmJkewcRD2+Vuj4iz7b30kI8OcL3horQ4= +k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0= +k8s.io/component-base v0.25.2 h1:Nve/ZyHLUBHz1rqwkjXm/Re6IniNa5k7KgzxZpTfSQY= +k8s.io/component-base v0.25.2/go.mod h1:90W21YMr+Yjg7MX+DohmZLzjsBtaxQDDwaX4YxDkl60= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kubectl v0.25.2 h1:2993lTeVimxKSWx/7z2PiJxUILygRa3tmC4QhFaeioA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= +sigs.k8s.io/cluster-api v1.1.3 h1:t682KcIPFeKGwe2SlxGvZa/HVmLA80XJ45KHBhzUETM= +sigs.k8s.io/cluster-api v1.1.3/go.mod h1:XqFZ0s9+KKjI/K39/EzHyAb4Sljprqvnm/XKWPgPp3Y= +sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA= +sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8MRFsn4dWF7O4= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/go.work.sum b/go.work.sum index 56897095..06c1ca6b 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,2 +1,118 @@ +cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y= +cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA= +cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc= +cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= +cloud.google.com/go/firestore v1.6.1 h1:8rBq3zRjnHx8UtBvaOWqBB1xq9jH6/wltfQLlTMh2Fw= +cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU= +cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad h1:EmNYJhPYy0pOFjCx2PrgtaBXmee0iUX9hLlxE1xHOJE= +github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/getkin/kin-openapi v0.76.0 h1:j77zg3Ec+k+r+GA3d8hBoXpAc6KX9TbBPrwQGBIy2sY= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= +github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= +github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/hashicorp/consul/api v1.12.0 h1:k3y1FYv6nuKyNTqj6w9gXOx5r5CfLj/k/euUeBXj1OY= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/serf v0.9.7 h1:hkdgbqizGQHuU5IPqYM1JdSMV8nKfpuOnZYXssk9muY= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= +github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= +github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/sagikazarmark/crypt v0.6.0 h1:REOEXCs/NFY/1jOCEouMuT4zEniE5YoXbvpC5X/TLF8= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ= +go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc= +go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7HqOg= +go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao= +go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +google.golang.org/api v0.81.0 h1:o8WF5AvfidafWbFjsRyupxyEQJNUWxLZJCK5NXrxZZ8= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= +google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= diff --git a/internal/aws/ses/ses.go b/internal/aws/ses/ses.go deleted file mode 100644 index f99bdc42..00000000 --- a/internal/aws/ses/ses.go +++ /dev/null @@ -1,189 +0,0 @@ -package ses - -import ( - "bytes" - "context" - "embed" - "fmt" - "html/template" - "os" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - awsSes "github.com/aws/aws-sdk-go-v2/service/ses" - "github.com/aws/aws-sdk-go-v2/service/ses/types" - "github.com/openinfradev/tks-api/pkg/log" - "github.com/spf13/viper" -) - -//go:embed contents/*.html -var templateFS embed.FS - -var Client *awsSes.Client - -const ( - senderEmailAddress = "tks-dev@sktelecom.com" -) - -func Initialize() error { - if viper.GetString("aws-access-key-id") != "" || viper.GetString("aws-secret-access-key") != "" { - log.Warn("aws access key information is used on env. Be aware of security") - } - if viper.GetString("aws-access-key-id") != "" { - err := os.Setenv("AWS_ACCESS_KEY_ID", viper.GetString("aws-access-key-id")) - if err != nil { - return err - } - } - if viper.GetString("aws-secret-access-key") != "" { - err := os.Setenv("AWS_SECRET_ACCESS_KEY", viper.GetString("aws-secret-access-key")) - if err != nil { - return err - } - } - if viper.GetString("aws-region") != "" { - err := os.Setenv("AWS_REGION", viper.GetString("aws-region")) - if err != nil { - return err - } - } else { - return fmt.Errorf("aws region is not set") - } - - cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("ap-northeast-2")) - if err != nil { - return err - } - - Client = awsSes.NewFromConfig(cfg) - return nil -} -func SendEmailForVerityIdentity(client *awsSes.Client, targetEmailAddress string, code string) error { - subject := "[TKS] [인증번호:" + code + "] 인증번호가 발급되었습니다." - - tmpl, err := template.ParseFS(templateFS, "contents/authcode.html") - if err != nil { - log.Errorf("failed to parse template, %v", err) - return err - } - - type TemplateData struct { - AuthCode string - } - - data := TemplateData{ - AuthCode: code, - } - - var tpl bytes.Buffer - if err := tmpl.Execute(&tpl, data); err != nil { - log.Errorf("failed to execute template, %v", err) - return err - } - - body := tpl.String() - - err = sendEmail(client, targetEmailAddress, subject, body) - if err != nil { - return err - } - return nil -} - -func SendEmailForTemporaryPassword(client *awsSes.Client, targetEmailAddress string, randomPassword string) error { - subject := "[TKS] 임시 비밀번호가 발급되었습니다." - - tmpl, err := template.ParseFS(templateFS, "contents/temporary_password.html") - if err != nil { - log.Errorf("failed to parse template, %v", err) - return err - } - - type TemplateData struct { - TemporaryPassword string - } - - data := TemplateData{ - TemporaryPassword: randomPassword, - } - - var tpl bytes.Buffer - if err := tmpl.Execute(&tpl, data); err != nil { - log.Errorf("failed to execute template, %v", err) - return err - } - - body := tpl.String() - - err = sendEmail(client, targetEmailAddress, subject, body) - if err != nil { - return err - } - return nil -} - -func SendEmailForGeneratingOrganization(client *awsSes.Client, organizationId string, organizationName string, - targetEmailAddress string, userAccountId string, randomPassword string) error { - subject := "[TKS] 조직이 생성되었습니다." - - tmpl, err := template.ParseFS(templateFS, "contents/organization_creation.html") - if err != nil { - log.Errorf("failed to parse template, %v", err) - return err - } - - type TemplateData struct { - OrganizationId string - Id string - Password string - OrganizationName string - AdminName string - } - - data := TemplateData{ - OrganizationId: organizationId, - Id: userAccountId, - Password: randomPassword, - OrganizationName: organizationName, - AdminName: userAccountId, - } - - var tpl bytes.Buffer - if err := tmpl.Execute(&tpl, data); err != nil { - log.Errorf("failed to execute template, %v", err) - return err - } - body := tpl.String() - - err = sendEmail(client, targetEmailAddress, subject, body) - if err != nil { - return err - } - return nil -} - -func sendEmail(client *awsSes.Client, targetEmailAddress string, subject string, htmlBody string) error { - input := &awsSes.SendEmailInput{ - Destination: &types.Destination{ - ToAddresses: []string{targetEmailAddress}, - }, - Message: &types.Message{ - Body: &types.Body{ - Html: &types.Content{ - Data: aws.String(htmlBody), - }, - }, - Subject: &types.Content{ - Data: aws.String(subject), - }, - }, - Source: aws.String(senderEmailAddress), - } - - if _, err := client.SendEmail(context.Background(), input); err != nil { - log.Errorf("failed to send email, %v", err) - return err - } - - return nil -} diff --git a/internal/database/database.go b/internal/database/database.go index 1442427d..7d7ff222 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -86,6 +86,9 @@ func migrateSchema(db *gorm.DB) error { if err := db.AutoMigrate(&repository.Cluster{}); err != nil { return err } + if err := db.AutoMigrate(&repository.ClusterFavorite{}); err != nil { + return err + } // Services if err := db.AutoMigrate(&repository.AppGroup{}); err != nil { diff --git a/internal/delivery/http/alert.go b/internal/delivery/http/alert.go index 70b2208a..5568af51 100644 --- a/internal/delivery/http/alert.go +++ b/internal/delivery/http/alert.go @@ -9,6 +9,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -126,13 +127,13 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { var out domain.GetAlertsResponse out.Alerts = make([]domain.AlertResponse, len(alerts)) for i, alert := range alerts { - if err := domain.Map(alert, &out.Alerts[i]); err != nil { + if err := serializer.Map(alert, &out.Alerts[i]); err != nil { log.InfoWithContext(r.Context(), err) } outAlertActions := make([]domain.AlertActionResponse, len(alert.AlertActions)) for j, alertAction := range alert.AlertActions { - if err := domain.Map(alertAction, &outAlertActions[j]); err != nil { + if err := serializer.Map(alertAction, &outAlertActions[j]); err != nil { log.InfoWithContext(r.Context(), err) } } @@ -142,13 +143,13 @@ func (h *AlertHandler) GetAlerts(w http.ResponseWriter, r *http.Request) { } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } /* outFilters := make([]domain.FilterResponse, len(pg.Filters)) for j, filter := range pg.Filters { - if err := domain.Map(filter, &outFilters[j]); err != nil { + if err := serializer.Map(filter, &outFilters[j]); err != nil { log.InfoWithContext(r.Context(), err) } } @@ -190,12 +191,12 @@ func (h *AlertHandler) GetAlert(w http.ResponseWriter, r *http.Request) { } var out domain.GetAlertResponse - if err := domain.Map(alert, &out.Alert); err != nil { + if err := serializer.Map(alert, &out.Alert); err != nil { log.InfoWithContext(r.Context(), err) } outAlertActions := make([]domain.AlertActionResponse, len(alert.AlertActions)) for j, alertAction := range alert.AlertActions { - if err := domain.Map(alertAction, &outAlertActions[j]); err != nil { + if err := serializer.Map(alertAction, &outAlertActions[j]); err != nil { log.InfoWithContext(r.Context(), err) continue } @@ -279,7 +280,7 @@ func (h *AlertHandler) CreateAlertAction(w http.ResponseWriter, r *http.Request) log.InfoWithContext(r.Context(), "alert : ", helper.ModelToJson(input)) var dto domain.AlertAction - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } dto.AlertId = alertId diff --git a/internal/delivery/http/app-group.go b/internal/delivery/http/app-group.go index 84667143..510e0d71 100644 --- a/internal/delivery/http/app-group.go +++ b/internal/delivery/http/app-group.go @@ -7,6 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -42,7 +43,7 @@ func (h *AppGroupHandler) CreateAppGroup(w http.ResponseWriter, r *http.Request) } var dto domain.AppGroup - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } @@ -96,13 +97,13 @@ func (h *AppGroupHandler) GetAppGroups(w http.ResponseWriter, r *http.Request) { var out domain.GetAppGroupsResponse out.AppGroups = make([]domain.AppGroupResponse, len(appGroups)) for i, appGroup := range appGroups { - if err := domain.Map(appGroup, &out.AppGroups[i]); err != nil { + if err := serializer.Map(appGroup, &out.AppGroups[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -138,7 +139,7 @@ func (h *AppGroupHandler) GetAppGroup(w http.ResponseWriter, r *http.Request) { } var out domain.GetAppGroupResponse - if err := domain.Map(appGroup, &out.AppGroup); err != nil { + if err := serializer.Map(appGroup, &out.AppGroup); err != nil { log.InfoWithContext(r.Context(), err) } @@ -222,7 +223,7 @@ func (h *AppGroupHandler) GetApplications(w http.ResponseWriter, r *http.Request var out domain.GetApplicationsResponse out.Applications = make([]domain.ApplicationResponse, len(applications)) for i, application := range applications { - if err := domain.Map(application, &out.Applications[i]); err != nil { + if err := serializer.Map(application, &out.Applications[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } @@ -262,7 +263,7 @@ func (h *AppGroupHandler) CreateApplication(w http.ResponseWriter, r *http.Reque } var dto domain.Application - if err := domain.Map(input, &dto); err != nil { + if err := serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } dto.AppGroupId = appGroupId diff --git a/internal/delivery/http/app-serve-app.go b/internal/delivery/http/app-serve-app.go index fc1601b0..9705d218 100644 --- a/internal/delivery/http/app-serve-app.go +++ b/internal/delivery/http/app-serve-app.go @@ -13,6 +13,7 @@ import ( "github.com/openinfradev/tks-api/internal" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -106,7 +107,7 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re (appReq).SetDefaultValue() var app domain.AppServeApp - if err = domain.Map(appReq, &app); err != nil { + if err = serializer.Map(appReq, &app); err != nil { ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) return } @@ -121,7 +122,7 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re app.CreatedAt = now var task domain.AppServeAppTask - if err = domain.Map(appReq, &task); err != nil { + if err = serializer.Map(appReq, &task); err != nil { ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) return } @@ -191,7 +192,7 @@ func (h *AppServeAppHandler) CreateAppServeApp(w http.ResponseWriter, r *http.Re } var out domain.CreateAppServeAppResponse - if err = domain.Map(app, &out); err != nil { + if err = serializer.Map(app, &out); err != nil { ErrorJSON(w, r, err) return } @@ -253,7 +254,7 @@ func (h *AppServeAppHandler) GetAppServeApps(w http.ResponseWriter, r *http.Requ var out domain.GetAppServeAppsResponse out.AppServeApps = apps - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -634,18 +635,18 @@ func (h *AppServeAppHandler) UpdateAppServeApp(w http.ResponseWriter, r *http.Re // break // } //} - //if err = domain.Map(latestTask, &task); err != nil { + //if err = serializer.Map(latestTask, &task); err != nil { // ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) // return //} var latestTask = app.AppServeAppTasks[0] - if err = domain.Map(latestTask, &task); err != nil { + if err = serializer.Map(latestTask, &task); err != nil { //ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) return } - if err = domain.Map(appReq, &task); err != nil { + if err = serializer.Map(appReq, &task); err != nil { //ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) return } diff --git a/internal/delivery/http/auth.go b/internal/delivery/http/auth.go index 24b5c894..2c5fcd4d 100644 --- a/internal/delivery/http/auth.go +++ b/internal/delivery/http/auth.go @@ -6,6 +6,7 @@ import ( "github.com/openinfradev/tks-api/internal" "github.com/openinfradev/tks-api/internal/middleware/auth/request" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -15,6 +16,7 @@ import ( type IAuthHandler interface { Login(w http.ResponseWriter, r *http.Request) Logout(w http.ResponseWriter, r *http.Request) + PingToken(w http.ResponseWriter, r *http.Request) RefreshToken(w http.ResponseWriter, r *http.Request) FindId(w http.ResponseWriter, r *http.Request) FindPassword(w http.ResponseWriter, r *http.Request) @@ -71,7 +73,7 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { } var out domain.LoginResponse - if err = domain.Map(user, &out.User); err != nil { + if err = serializer.Map(user, &out.User); err != nil { log.ErrorWithContext(r.Context(), err) } @@ -255,3 +257,30 @@ func (h *AuthHandler) VerifyIdentityForLostPassword(w http.ResponseWriter, r *ht ResponseJSON(w, r, http.StatusOK, out) } + +// Login godoc +// @Tags Auth +// @Summary ping with token +// @Description ping with token +// @Accept json +// @Produce json +// @Param body body domain.PingTokenRequest true "token info" +// @Success 200 {object} nil +// @Router /auth/ping [post] +func (h *AuthHandler) PingToken(w http.ResponseWriter, r *http.Request) { + input := domain.PingTokenRequest{} + err := UnmarshalRequestInput(r, &input) + if err != nil { + ErrorJSON(w, r, err) + return + } + + err = h.usecase.PingToken(input.Token, input.OrganizationId) + if err != nil { + log.ErrorfWithContext(r.Context(), "error is :%s(%T)", err.Error(), err) + ErrorJSON(w, r, err) + return + } + + ResponseJSON(w, r, http.StatusOK, nil) +} diff --git a/internal/delivery/http/cloud-account.go b/internal/delivery/http/cloud-account.go index 33c71eea..02809f30 100644 --- a/internal/delivery/http/cloud-account.go +++ b/internal/delivery/http/cloud-account.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -52,7 +53,7 @@ func (h *CloudAccountHandler) CreateCloudAccount(w http.ResponseWriter, r *http. } var dto domain.CloudAccount - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } dto.OrganizationId = organizationId @@ -107,13 +108,13 @@ func (h *CloudAccountHandler) GetCloudAccounts(w http.ResponseWriter, r *http.Re var out domain.GetCloudAccountsResponse out.CloudAccounts = make([]domain.CloudAccountResponse, len(cloudAccounts)) for i, cloudAccount := range cloudAccounts { - if err := domain.Map(cloudAccount, &out.CloudAccounts[i]); err != nil { + if err := serializer.Map(cloudAccount, &out.CloudAccounts[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -152,7 +153,7 @@ func (h *CloudAccountHandler) GetCloudAccount(w http.ResponseWriter, r *http.Req } var out domain.GetCloudAccountResponse - if err := domain.Map(cloudAccount, &out.CloudAccount); err != nil { + if err := serializer.Map(cloudAccount, &out.CloudAccount); err != nil { log.InfoWithContext(r.Context(), err) } @@ -198,7 +199,7 @@ func (h *CloudAccountHandler) UpdateCloudAccount(w http.ResponseWriter, r *http. } var dto domain.CloudAccount - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } dto.ID = cloudAccountId @@ -247,7 +248,7 @@ func (h *CloudAccountHandler) DeleteCloudAccount(w http.ResponseWriter, r *http. } var dto domain.CloudAccount - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } dto.ID = parsedId @@ -372,3 +373,43 @@ func (h *CloudAccountHandler) CheckAwsAccountId(w http.ResponseWriter, r *http.R ResponseJSON(w, r, http.StatusOK, out) } + +// GetResourceQuota godoc +// @Tags CloudAccounts +// @Summary Get resource quota by cloudAccount +// @Description Get resource quota by cloudAccount +// @Accept json +// @Produce json +// @Param organizationId path string true "organizationId" +// @Param cloudAccountId path string true "cloudAccountId" +// @Success 200 {object} domain.GetCloudAccountResourceQuotaResponse +// @Router /organizations/{organizationId}/cloud-accounts/{cloudAccountId}/quota [GET] +// @Security JWT +func (h *CloudAccountHandler) GetResourceQuota(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strId, ok := vars["cloudAccountId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloudAccountId"), "C_INVALID_CLOUD_ACCOUNT_ID", "")) + return + } + + cloudAccountId, err := uuid.Parse(strId) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(errors.Wrap(err, "Failed to parse uuid %s"), "C_INVALID_CLOUD_ACCOUNT_ID", "")) + return + } + + available, resourceQuota, err := h.usecase.GetResourceQuota(r.Context(), cloudAccountId) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.GetCloudAccountResourceQuotaResponse + if err := serializer.Map(resourceQuota, &out.ResourceQuota); err != nil { + log.InfoWithContext(r.Context(), err) + } + out.Available = available + + ResponseJSON(w, r, http.StatusOK, out) +} diff --git a/internal/delivery/http/cluster.go b/internal/delivery/http/cluster.go index 6b0613d9..cb8b8f6e 100644 --- a/internal/delivery/http/cluster.go +++ b/internal/delivery/http/cluster.go @@ -6,6 +6,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -55,13 +56,13 @@ func (h *ClusterHandler) GetClusters(w http.ResponseWriter, r *http.Request) { var out domain.GetClustersResponse out.Clusters = make([]domain.ClusterResponse, len(clusters)) for i, cluster := range clusters { - if err := domain.Map(cluster, &out.Clusters[i]); err != nil { + if err := serializer.Map(cluster, &out.Clusters[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -93,7 +94,7 @@ func (h *ClusterHandler) GetCluster(w http.ResponseWriter, r *http.Request) { } var out domain.GetClusterResponse - if err := domain.Map(cluster, &out.Cluster); err != nil { + if err := serializer.Map(cluster, &out.Cluster); err != nil { log.InfoWithContext(r.Context(), err) } @@ -130,7 +131,7 @@ func (h *ClusterHandler) GetClusterSiteValues(w http.ResponseWriter, r *http.Req ResponseJSON(w, r, http.StatusOK, out) } -// GetCluster godoc +// CreateCluster godoc // @Tags Clusters // @Summary Create cluster // @Description Create cluster @@ -149,23 +150,38 @@ func (h *ClusterHandler) CreateCluster(w http.ResponseWriter, r *http.Request) { } var dto domain.Cluster - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } - if err = domain.Map(input, &dto.Conf); err != nil { + if err = serializer.Map(input, &dto.Conf); err != nil { log.InfoWithContext(r.Context(), err) } // [TODO] set default value + dto.ClusterType = domain.ClusterType_USER dto.Conf.SetDefault() log.InfoWithContext(r.Context(), dto.Conf) //txHandle := r.Context().Value("txHandle").(*gorm.DB) - clusterId, err := h.usecase.Create(r.Context(), dto) - if err != nil { - ErrorJSON(w, r, err) - return + clusterId := domain.ClusterId("") + if input.CloudService == domain.CloudService_BYOH { + if dto.ByoClusterEndpointHost == "" || dto.ByoClusterEndpointPort == 0 { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid byoh cluster endpoint"), "CL_INVALID_BYOH_CLUSTER_ENDPOINT", "")) + return + } + clusterId, err = h.usecase.Bootstrap(r.Context(), dto) + if err != nil { + ErrorJSON(w, r, err) + return + } + } else { + clusterId, err = h.usecase.Create(r.Context(), dto) + if err != nil { + ErrorJSON(w, r, err) + return + } + } var out domain.CreateClusterResponse @@ -174,6 +190,33 @@ func (h *ClusterHandler) CreateCluster(w http.ResponseWriter, r *http.Request) { ResponseJSON(w, r, http.StatusOK, out) } +// InstallCluster godoc +// @Tags Clusters +// @Summary Install cluster on tks cluster +// @Description Install cluster on tks cluster +// @Accept json +// @Produce json +// @Param clusterId path string true "clusterId" +// @Success 200 {object} nil +// @Router /clusters/{clusterId}/install [post] +// @Security JWT +func (h *ClusterHandler) InstallCluster(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clusterId, ok := vars["clusterId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterId"), "C_INVALID_CLUSTER_ID", "")) + return + } + + err := h.usecase.Install(r.Context(), domain.ClusterId(clusterId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + + ResponseJSON(w, r, http.StatusOK, nil) +} + // DeleteCluster godoc // @Tags Clusters // @Summary Delete cluster @@ -201,6 +244,98 @@ func (h *ClusterHandler) DeleteCluster(w http.ResponseWriter, r *http.Request) { ResponseJSON(w, r, http.StatusOK, nil) } +// CreateBootstrapKubeconfig godoc +// @Tags Clusters +// @Summary Create bootstrap kubeconfig for BYOH +// @Description Create bootstrap kubeconfig for BYOH +// @Accept json +// @Produce json +// @Success 200 {object} domain.CreateBootstrapKubeconfigResponse +// @Router /clusters/{clusterId}/bootstrap-kubeconfig [post] +// @Security JWT +func (h *ClusterHandler) CreateBootstrapKubeconfig(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clusterId, ok := vars["clusterId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterId"), "C_INVALID_CLUSTER_ID", "")) + return + } + + kubeconfig, err := h.usecase.CreateBootstrapKubeconfig(r.Context(), domain.ClusterId(clusterId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.CreateBootstrapKubeconfigResponse + out.Data = kubeconfig + ResponseJSON(w, r, http.StatusOK, out) +} + +// GetBootstrapKubeconfig godoc +// @Tags Clusters +// @Summary Get bootstrap kubeconfig for BYOH +// @Description Get bootstrap kubeconfig for BYOH +// @Accept json +// @Produce json +// @Success 200 {object} domain.GetBootstrapKubeconfigResponse +// @Router /clusters/{clusterId}/bootstrap-kubeconfig [get] +// @Security JWT +func (h *ClusterHandler) GetBootstrapKubeconfig(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + clusterId, ok := vars["clusterId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterId"), "C_INVALID_CLUSTER_ID", "")) + return + } + + bootstrapKubeconfig, err := h.usecase.GetBootstrapKubeconfig(r.Context(), domain.ClusterId(clusterId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.GetBootstrapKubeconfigResponse + out.Data = bootstrapKubeconfig + + ResponseJSON(w, r, http.StatusOK, out) +} + +// GetNodes godoc +// @Tags Clusters +// @Summary Get nodes information for BYOH +// @Description Get nodes information for BYOH +// @Accept json +// @Produce json +// @Param clusterId path string true "clusterId" +// @Success 200 {object} domain.GetClusterNodesResponse +// @Router /clusters/{clusterId}/nodes [get] +// @Security JWT +func (h *ClusterHandler) GetNodes(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strId, ok := vars["clusterId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "")) + return + } + clusterId := domain.ClusterId(strId) + if !clusterId.Validate() { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "C_INVALID_STACK_ID", "")) + return + } + + nodes, err := h.usecase.GetNodes(r.Context(), domain.ClusterId(strId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.GetClusterNodesResponse + out.Nodes = nodes + + ResponseJSON(w, r, http.StatusOK, out) +} + func (h *ClusterHandler) GetKubernetesInfo(w http.ResponseWriter, r *http.Request) { // GetKubernetesInfo godoc // @Tags Clusters diff --git a/internal/delivery/http/dashboard.go b/internal/delivery/http/dashboard.go index d6f9c9e8..8a5ae87b 100644 --- a/internal/delivery/http/dashboard.go +++ b/internal/delivery/http/dashboard.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/gorilla/mux" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -72,7 +73,7 @@ func (h *DashboardHandler) GetCharts(w http.ResponseWriter, r *http.Request) { var out domain.GetDashboardChartsResponse out.Charts = make([]domain.DashboardChartResponse, len(charts)) for i, chart := range charts { - if err := domain.Map(chart, &out.Charts[i]); err != nil { + if err := serializer.Map(chart, &out.Charts[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } @@ -150,7 +151,7 @@ func (h *DashboardHandler) GetChart(w http.ResponseWriter, r *http.Request) { } var out domain.DashboardChartResponse - if err := domain.Map(charts[0], &out); err != nil { + if err := serializer.Map(charts[0], &out); err != nil { log.InfoWithContext(r.Context(), err) } @@ -189,7 +190,7 @@ func (h *DashboardHandler) GetStacks(w http.ResponseWriter, r *http.Request) { var out domain.GetDashboardStacksResponse out.Stacks = make([]domain.DashboardStackResponse, len(stacks)) for i, stack := range stacks { - if err := domain.Map(stack, &out.Stacks[i]); err != nil { + if err := serializer.Map(stack, &out.Stacks[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } @@ -226,7 +227,7 @@ func (h *DashboardHandler) GetResources(w http.ResponseWriter, r *http.Request) return } var out domain.GetDashboardResourcesResponse - if err := domain.Map(resources, &out.Resources); err != nil { + if err := serializer.Map(resources, &out.Resources); err != nil { log.InfoWithContext(r.Context(), err) } diff --git a/internal/delivery/http/organization.go b/internal/delivery/http/organization.go index 12e420fb..4489fa9c 100644 --- a/internal/delivery/http/organization.go +++ b/internal/delivery/http/organization.go @@ -7,6 +7,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -47,7 +48,7 @@ func (h *OrganizationHandler) CreateOrganization(w http.ResponseWriter, r *http. ctx := r.Context() var organization domain.Organization - if err = domain.Map(input, &organization); err != nil { + if err = serializer.Map(input, &organization); err != nil { log.ErrorWithContext(r.Context(), err) } @@ -67,7 +68,7 @@ func (h *OrganizationHandler) CreateOrganization(w http.ResponseWriter, r *http. } var out domain.CreateOrganizationResponse - if err = domain.Map(organization, &out); err != nil { + if err = serializer.Map(organization, &out); err != nil { log.ErrorWithContext(r.Context(), err) } @@ -108,14 +109,14 @@ func (h *OrganizationHandler) GetOrganizations(w http.ResponseWriter, r *http.Re out.Organizations = make([]domain.ListOrganizationBody, len(*organizations)) for i, organization := range *organizations { - if err = domain.Map(organization, &out.Organizations[i]); err != nil { + if err = serializer.Map(organization, &out.Organizations[i]); err != nil { log.ErrorWithContext(r.Context(), err) } log.InfoWithContext(r.Context(), organization) } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -152,7 +153,7 @@ func (h *OrganizationHandler) GetOrganization(w http.ResponseWriter, r *http.Req return } var out domain.GetOrganizationResponse - if err = domain.Map(organization, &out.Organization); err != nil { + if err = serializer.Map(organization, &out.Organization); err != nil { log.ErrorWithContext(r.Context(), err) } @@ -244,7 +245,7 @@ func (h *OrganizationHandler) UpdateOrganization(w http.ResponseWriter, r *http. } var out domain.UpdateOrganizationResponse - if err = domain.Map(organization, &out); err != nil { + if err = serializer.Map(organization, &out); err != nil { log.ErrorWithContext(r.Context(), err) } diff --git a/internal/delivery/http/stack-template.go b/internal/delivery/http/stack-template.go index 56ebb222..29b4af18 100644 --- a/internal/delivery/http/stack-template.go +++ b/internal/delivery/http/stack-template.go @@ -8,6 +8,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -70,7 +71,7 @@ func (h *StackTemplateHandler) GetStackTemplates(w http.ResponseWriter, r *http. var out domain.GetStackTemplatesResponse out.StackTemplates = make([]domain.StackTemplateResponse, len(stackTemplates)) for i, stackTemplate := range stackTemplates { - if err := domain.Map(stackTemplate, &out.StackTemplates[i]); err != nil { + if err := serializer.Map(stackTemplate, &out.StackTemplates[i]); err != nil { log.InfoWithContext(r.Context(), err) } @@ -80,7 +81,7 @@ func (h *StackTemplateHandler) GetStackTemplates(w http.ResponseWriter, r *http. } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -118,7 +119,7 @@ func (h *StackTemplateHandler) GetStackTemplate(w http.ResponseWriter, r *http.R } var out domain.GetStackTemplateResponse - if err := domain.Map(stackTemplate, &out.StackTemplate); err != nil { + if err := serializer.Map(stackTemplate, &out.StackTemplate); err != nil { log.InfoWithContext(r.Context(), err) } @@ -156,7 +157,7 @@ func (h *StackTemplateHandler) UpdateStackTemplate(w http.ResponseWriter, r *htt } var dto domain.StackTemplate - if err := domain.Map(r, &dto); err != nil { + if err := serializer.Map(r, &dto); err != nil { log.InfoWithContext(r.Context(),err) } dto.ID = stackTemplateId diff --git a/internal/delivery/http/stack.go b/internal/delivery/http/stack.go index a85c52ed..661e38d5 100644 --- a/internal/delivery/http/stack.go +++ b/internal/delivery/http/stack.go @@ -1,11 +1,13 @@ package http import ( + "encoding/json" "fmt" "net/http" "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -49,14 +51,13 @@ func (h *StackHandler) CreateStack(w http.ResponseWriter, r *http.Request) { } var dto domain.Stack - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } - if err = domain.Map(input, &dto.Conf); err != nil { + if err = serializer.Map(input, &dto.Conf); err != nil { log.InfoWithContext(r.Context(), err) } dto.OrganizationId = organizationId - stackId, err := h.usecase.Create(r.Context(), dto) if err != nil { ErrorJSON(w, r, err) @@ -70,6 +71,23 @@ func (h *StackHandler) CreateStack(w http.ResponseWriter, r *http.Request) { ResponseJSON(w, r, http.StatusOK, out) } +func (h *StackHandler) InstallStack(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + stackId, ok := vars["stackId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "S_INVALID_STACK_ID", "")) + return + } + + err := h.usecase.Install(r.Context(), domain.StackId(stackId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + + ResponseJSON(w, r, http.StatusOK, nil) +} + // GetStack godoc // @Tags Stacks // @Summary Get Stacks @@ -108,13 +126,18 @@ func (h *StackHandler) GetStacks(w http.ResponseWriter, r *http.Request) { var out domain.GetStacksResponse out.Stacks = make([]domain.StackResponse, len(stacks)) for i, stack := range stacks { - if err := domain.Map(stack, &out.Stacks[i]); err != nil { + if err := serializer.Map(stack, &out.Stacks[i]); err != nil { log.InfoWithContext(r.Context(), err) continue } + + err = json.Unmarshal(stack.StackTemplate.Services, &out.Stacks[i].StackTemplate.Services) + if err != nil { + log.InfoWithContext(r.Context(), err) + } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -147,7 +170,12 @@ func (h *StackHandler) GetStack(w http.ResponseWriter, r *http.Request) { } var out domain.GetStackResponse - if err := domain.Map(stack, &out.Stack); err != nil { + if err := serializer.Map(stack, &out.Stack); err != nil { + log.InfoWithContext(r.Context(), err) + } + + err = json.Unmarshal(stack.StackTemplate.Services, &out.Stack.StackTemplate.Services) + if err != nil { log.InfoWithContext(r.Context(), err) } @@ -183,7 +211,7 @@ func (h *StackHandler) GetStackStatus(w http.ResponseWriter, r *http.Request) { var out domain.GetStackStatusResponse out.StepStatus = make([]domain.StackStepStatus, len(steps)) for i, step := range steps { - if err := domain.Map(step, &out.StepStatus[i]); err != nil { + if err := serializer.Map(step, &out.StepStatus[i]); err != nil { log.InfoWithContext(r.Context(), err) } } @@ -231,7 +259,7 @@ func (h *StackHandler) UpdateStack(w http.ResponseWriter, r *http.Request) { } var dto domain.Stack - if err = domain.Map(input, &dto); err != nil { + if err = serializer.Map(input, &dto); err != nil { log.InfoWithContext(r.Context(), err) } dto.ID = stackId @@ -370,3 +398,57 @@ func (h *StackHandler) GetStackKubeConfig(w http.ResponseWriter, r *http.Request ResponseJSON(w, r, http.StatusOK, out) } + +// SetFavorite godoc +// @Tags Stacks +// @Summary Set favorite stack +// @Description Set favorite stack +// @Accept json +// @Produce json +// @Param organizationId path string true "organizationId" +// @Param stackId path string true "stackId" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/stacks/{stackId}/favorite [post] +// @Security JWT +func (h *StackHandler) SetFavorite(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strId, ok := vars["stackId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "C_INVALID_STACK_ID", "")) + return + } + + err := h.usecase.SetFavorite(r.Context(), domain.StackId(strId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + ResponseJSON(w, r, http.StatusOK, nil) +} + +// DeleteFavorite godoc +// @Tags Stacks +// @Summary Delete favorite stack +// @Description Delete favorite stack +// @Accept json +// @Produce json +// @Param organizationId path string true "organizationId" +// @Param stackId path string true "stackId" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/stacks/{stackId}/favorite [delete] +// @Security JWT +func (h *StackHandler) DeleteFavorite(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strId, ok := vars["stackId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "C_INVALID_STACK_ID", "")) + return + } + + err := h.usecase.DeleteFavorite(r.Context(), domain.StackId(strId)) + if err != nil { + ErrorJSON(w, r, err) + return + } + ResponseJSON(w, r, http.StatusOK, nil) +} diff --git a/internal/delivery/http/user.go b/internal/delivery/http/user.go index 53797942..50a7ea11 100644 --- a/internal/delivery/http/user.go +++ b/internal/delivery/http/user.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -78,7 +79,7 @@ func (u UserHandler) Create(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var user domain.User - if err = domain.Map(input, &user); err != nil { + if err = serializer.Map(input, &user); err != nil { log.ErrorWithContext(r.Context(), err) } user.Organization = domain.Organization{ @@ -98,7 +99,7 @@ func (u UserHandler) Create(w http.ResponseWriter, r *http.Request) { } var out domain.CreateUserResponse - if err = domain.Map(*resUser, &out.User); err != nil { + if err = serializer.Map(*resUser, &out.User); err != nil { log.ErrorWithContext(r.Context(), err) } @@ -144,7 +145,7 @@ func (u UserHandler) Get(w http.ResponseWriter, r *http.Request) { } var out domain.GetUserResponse - if err = domain.Map(*user, &out.User); err != nil { + if err = serializer.Map(*user, &out.User); err != nil { log.ErrorWithContext(r.Context(), err) } @@ -190,12 +191,12 @@ func (u UserHandler) List(w http.ResponseWriter, r *http.Request) { var out domain.ListUserResponse out.Users = make([]domain.ListUserBody, len(*users)) for i, user := range *users { - if err = domain.Map(user, &out.Users[i]); err != nil { + if err = serializer.Map(user, &out.Users[i]); err != nil { log.ErrorWithContext(r.Context(), err) } } - if err := domain.Map(*pg, &out.Pagination); err != nil { + if err := serializer.Map(*pg, &out.Pagination); err != nil { log.InfoWithContext(r.Context(), err) } @@ -277,7 +278,7 @@ func (u UserHandler) Update(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var user domain.User - if err = domain.Map(input, &user); err != nil { + if err = serializer.Map(input, &user); err != nil { ErrorJSON(w, r, err) return } @@ -299,7 +300,7 @@ func (u UserHandler) Update(w http.ResponseWriter, r *http.Request) { } var out domain.UpdateUserResponse - if err = domain.Map(*resUser, &out.User); err != nil { + if err = serializer.Map(*resUser, &out.User); err != nil { log.ErrorWithContext(r.Context(), err) ErrorJSON(w, r, err) return @@ -364,7 +365,7 @@ func (u UserHandler) GetMyProfile(w http.ResponseWriter, r *http.Request) { } var out domain.GetMyProfileResponse - if err = domain.Map(*user, &out.User); err != nil { + if err = serializer.Map(*user, &out.User); err != nil { log.ErrorWithContext(r.Context(), err) ErrorJSON(w, r, err) return @@ -409,7 +410,7 @@ func (u UserHandler) UpdateMyProfile(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var user domain.User - if err = domain.Map(input, &user); err != nil { + if err = serializer.Map(input, &user); err != nil { log.ErrorWithContext(r.Context(), err) ErrorJSON(w, r, err) return @@ -429,7 +430,7 @@ func (u UserHandler) UpdateMyProfile(w http.ResponseWriter, r *http.Request) { } var out domain.UpdateMyProfileResponse - if err = domain.Map(*resUser, &out.User); err != nil { + if err = serializer.Map(*resUser, &out.User); err != nil { log.ErrorWithContext(r.Context(), err) ErrorJSON(w, r, err) return diff --git a/internal/helper/util.go b/internal/helper/util.go index c6e92f2a..bc26422f 100644 --- a/internal/helper/util.go +++ b/internal/helper/util.go @@ -65,10 +65,13 @@ func IsDurationExpired(targetTime time.Time, duration time.Duration) bool { } func SplitAddress(url string) (address string, port int) { + url = strings.TrimSuffix(url, "\n") arr := strings.Split(url, ":") address = arr[0] + ":" + arr[1] - port, _ = strconv.Atoi(arr[2]) - + port, err := strconv.Atoi(arr[2]) + if err != nil { + log.Error(err) + } return } diff --git a/internal/mail/content.go b/internal/mail/content.go new file mode 100644 index 00000000..39957716 --- /dev/null +++ b/internal/mail/content.go @@ -0,0 +1,97 @@ +package mail + +import ( + "bytes" + "html/template" + + "github.com/openinfradev/tks-api/pkg/log" +) + +func MakeVerityIdentityMessage(to, code string) (*MessageInfo, error) { + subject := "[TKS] [인증번호:" + code + "] 인증번호가 발급되었습니다." + + tmpl, err := template.ParseFS(templateFS, "contents/authcode.html") + if err != nil { + log.Errorf("failed to parse template, %v", err) + return nil, err + } + + data := map[string]string{"AuthCode": code} + + var tpl bytes.Buffer + if err := tmpl.Execute(&tpl, data); err != nil { + log.Errorf("failed to execute template, %v", err) + return nil, err + } + + m := &MessageInfo{ + From: from, + To: to, + Subject: subject, + Body: tpl.String(), + } + + return m, nil +} + +func MakeTemporaryPasswordMessage(to, randomPassword string) (*MessageInfo, error) { + subject := "[TKS] 임시 비밀번호가 발급되었습니다." + + tmpl, err := template.ParseFS(templateFS, "contents/temporary_password.html") + if err != nil { + log.Errorf("failed to parse template, %v", err) + return nil, err + } + + data := map[string]string{"TemporaryPassword": randomPassword} + + var tpl bytes.Buffer + if err := tmpl.Execute(&tpl, data); err != nil { + log.Errorf("failed to execute template, %v", err) + return nil, err + } + + m := &MessageInfo{ + From: from, + To: to, + Subject: subject, + Body: tpl.String(), + } + + return m, nil +} + +func MakeGeneratingOrganizationMessage( + organizationId string, organizationName string, + to string, userAccountId string, randomPassword string) (*MessageInfo, error) { + subject := "[TKS] 조직이 생성되었습니다." + + tmpl, err := template.ParseFS(templateFS, "contents/organization_creation.html") + if err != nil { + log.Errorf("failed to parse template, %v", err) + return nil, err + } + + data := map[string]string{ + "OrganizationId": organizationId, + "Id": userAccountId, + "Password": randomPassword, + "OrganizationName": organizationName, + "AdminName": userAccountId, + } + + var tpl bytes.Buffer + if err := tmpl.Execute(&tpl, data); err != nil { + log.Errorf("failed to execute template, %v", err) + return nil, err + } + + m := &MessageInfo{ + From: from, + To: to, + Subject: subject, + Body: tpl.String(), + } + + return m, nil +} diff --git a/internal/aws/ses/contents/authcode.html b/internal/mail/contents/authcode.html similarity index 100% rename from internal/aws/ses/contents/authcode.html rename to internal/mail/contents/authcode.html diff --git a/internal/aws/ses/contents/organization_creation.html b/internal/mail/contents/organization_creation.html similarity index 100% rename from internal/aws/ses/contents/organization_creation.html rename to internal/mail/contents/organization_creation.html diff --git a/internal/aws/ses/contents/temporary_password.html b/internal/mail/contents/temporary_password.html similarity index 100% rename from internal/aws/ses/contents/temporary_password.html rename to internal/mail/contents/temporary_password.html diff --git a/internal/mail/ses.go b/internal/mail/ses.go new file mode 100644 index 00000000..98e9a429 --- /dev/null +++ b/internal/mail/ses.go @@ -0,0 +1,90 @@ +package mail + +import ( + "context" + "fmt" + "os" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + awsSes "github.com/aws/aws-sdk-go-v2/service/ses" + "github.com/aws/aws-sdk-go-v2/service/ses/types" + "github.com/openinfradev/tks-api/pkg/log" + "github.com/spf13/viper" +) + +var awsClient *awsSes.Client + +type AwsMailer struct { + client *awsSes.Client + message *MessageInfo +} + +func (a *AwsMailer) SendMail() error { + input := &awsSes.SendEmailInput{ + Destination: &types.Destination{ + ToAddresses: []string{a.message.To}, + }, + Message: &types.Message{ + Subject: &types.Content{ + Data: aws.String(a.message.Subject), + }, + Body: &types.Body{ + Html: &types.Content{ + Data: aws.String(a.message.Body), + }, + }, + }, + Source: aws.String(a.message.From), + } + + if _, err := a.client.SendEmail(context.Background(), input); err != nil { + log.Errorf("failed to send email, %v", err) + return err + } + + return nil +} + +func initialize() error { + if viper.GetString("aws-access-key-id") != "" || viper.GetString("aws-secret-access-key") != "" { + log.Warn("aws access key information is used on env. Be aware of security") + } + if viper.GetString("aws-access-key-id") != "" { + err := os.Setenv("AWS_ACCESS_KEY_ID", viper.GetString("aws-access-key-id")) + if err != nil { + return err + } + } + if viper.GetString("aws-secret-access-key") != "" { + err := os.Setenv("AWS_SECRET_ACCESS_KEY", viper.GetString("aws-secret-access-key")) + if err != nil { + return err + } + } + if viper.GetString("aws-region") != "" { + err := os.Setenv("AWS_REGION", viper.GetString("aws-region")) + if err != nil { + return err + } + } else { + return fmt.Errorf("aws region is not set") + } + + cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("ap-northeast-2")) + if err != nil { + return err + } + + awsClient = awsSes.NewFromConfig(cfg) + return nil +} + +func NewAwsMailer(m *MessageInfo) *AwsMailer { + mailer := &AwsMailer{ + client: awsClient, + message: m, + } + + return mailer +} diff --git a/internal/mail/smtp.go b/internal/mail/smtp.go new file mode 100644 index 00000000..5a549dc2 --- /dev/null +++ b/internal/mail/smtp.go @@ -0,0 +1,131 @@ +package mail + +import ( + "embed" + "fmt" + "github.com/openinfradev/tks-api/pkg/log" + "github.com/spf13/viper" + "gopkg.in/gomail.v2" +) + +var ( + //go:embed contents/*.html + templateFS embed.FS + goClient *gomail.Message + mailProvider string + host, username, password, from string + port int +) + +type Mailer interface { + SendMail() error +} + +type MessageInfo struct { + From string + To string + Subject string + Body string +} + +type SmtpMailer struct { + client *gomail.Message + Host string + Port int + Username string + Password string + + message *MessageInfo +} + +func (s *SmtpMailer) SendMail() error { + s.client.SetHeader("From", s.message.From) + s.client.SetHeader("To", s.message.To) + s.client.SetHeader("Subject", s.message.Subject) + s.client.SetBody("text/html", s.message.Body) + + d := gomail.NewDialer(s.Host, s.Port, s.Username, s.Password) + + if err := d.DialAndSend(s.client); err != nil { + log.Errorf("failed to send email, %v", err) + return err + } + + return nil +} + +func Initialize() error { + mailProvider = viper.GetString("mail-provider") + if mailProvider != "smtp" { + mailProvider = "aws" + } + + switch mailProvider { + case "aws": + if err := initialize(); err != nil { + log.Errorf("aws config initialize error, %v", err) + return err + } + from = "tks-dev@sktelecom.com" + case "smtp": + host = viper.GetString("smtp-host") + port = viper.GetInt("smtp-port") + username = viper.GetString("smtp-username") + password = viper.GetString("smtp-password") + from = viper.GetString("smtp-from-email") + + if host == "" { + log.Error("smtp-host is not set") + return fmt.Errorf("smtp-host is not set") + } + if port == 0 { + log.Error("smtp-port is not set") + return fmt.Errorf("smtp-port is not set") + } + if username == "" { + log.Error("smtp-username is not set") + return fmt.Errorf("smtp-username is not set") + } + if password == "" { + log.Error("smtp-password is not set") + return fmt.Errorf("smtp-password is not set") + } + if from == "" { + log.Error("smtp-from-email is not set") + return fmt.Errorf("smtp-from-email is not set") + } + + goClient = gomail.NewMessage() + } + + return nil +} + +func New(m *MessageInfo) Mailer { + var mailer Mailer + + switch mailProvider { + case "aws": + mailer = NewAwsMailer(m) + log.Infof("aws ses mailer, %v", mailer) + + case "smtp": + mailer = NewSmtpMailer(m) + log.Infof("smtp mailer, %v", mailer) + } + + return mailer +} + +func NewSmtpMailer(m *MessageInfo) *SmtpMailer { + mailer := &SmtpMailer{ + client: goClient, + Host: host, + Port: port, + Username: username, + Password: password, + message: m, + } + + return mailer +} diff --git a/internal/repository/alert.go b/internal/repository/alert.go index e82e1999..f1ffd971 100644 --- a/internal/repository/alert.go +++ b/internal/repository/alert.go @@ -11,7 +11,9 @@ import ( "gorm.io/gorm/clause" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/log" ) // Interfaces @@ -55,7 +57,7 @@ type Alert struct { CheckPoint string GrafanaUrl string Summary string - AlertActions []AlertAction `gorm:"foreignKey:AlertId"` + AlertActions []AlertAction RawData datatypes.JSON Status domain.AlertActionStatus `gorm:"index"` } @@ -211,43 +213,24 @@ func (r *AlertRepository) CreateAlertAction(dto domain.AlertAction) (alertAction return alert.ID, nil } -func reflectAlert(alert Alert) domain.Alert { - outAlertActions := make([]domain.AlertAction, len(alert.AlertActions)) +func reflectAlert(alert Alert) (out domain.Alert) { + if err := serializer.Map(alert.Model, &out); err != nil { + log.Error(err) + } + if err := serializer.Map(alert, &out); err != nil { + log.Error(err) + } + + out.AlertActions = make([]domain.AlertAction, len(alert.AlertActions)) for i, alertAction := range alert.AlertActions { - outAlertActions[i] = reflectAlertAction(alertAction) - } - - return domain.Alert{ - ID: alert.ID, - OrganizationId: alert.OrganizationId, - Name: alert.Name, - Description: alert.Description, - Message: alert.Message, - Code: alert.Code, - Grade: alert.Grade, - ClusterId: alert.ClusterId, - Cluster: reflectSimpleCluster(alert.Cluster), - GrafanaUrl: alert.GrafanaUrl, - Node: alert.Node, - CheckPoint: alert.CheckPoint, - Summary: alert.Summary, - AlertActions: outAlertActions, - RawData: alert.RawData, - Status: alert.Status, - CreatedAt: alert.CreatedAt, - UpdatedAt: alert.UpdatedAt, - } -} - -func reflectAlertAction(alertAction AlertAction) domain.AlertAction { - return domain.AlertAction{ - ID: alertAction.ID, - AlertId: alertAction.AlertId, - Content: alertAction.Content, - Status: alertAction.Status, - TakerId: alertAction.TakerId, - Taker: reflectSimpleUser(alertAction.Taker), - CreatedAt: alertAction.CreatedAt, - UpdatedAt: alertAction.UpdatedAt, + if err := serializer.Map(alertAction.Model, &out.AlertActions[i]); err != nil { + log.Error(err) + continue + } + if err := serializer.Map(alertAction, &out.AlertActions[i]); err != nil { + log.Error(err) + continue + } } + return } diff --git a/internal/repository/app-group.go b/internal/repository/app-group.go index 46f63d9a..e999ae99 100644 --- a/internal/repository/app-group.go +++ b/internal/repository/app-group.go @@ -10,6 +10,7 @@ import ( "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" ) @@ -210,32 +211,21 @@ func (r *AppGroupRepository) InitWorkflowDescription(clusterId domain.ClusterId) return nil } -func reflectAppGroup(appGroup AppGroup) domain.AppGroup { - return domain.AppGroup{ - ID: appGroup.ID, - ClusterId: appGroup.ClusterId, - AppGroupType: appGroup.AppGroupType, - Name: appGroup.Name, - Description: appGroup.Description, - Status: appGroup.Status, - StatusDesc: appGroup.StatusDesc, - CreatedAt: appGroup.CreatedAt, - UpdatedAt: appGroup.UpdatedAt, - CreatorId: appGroup.CreatorId, - Creator: reflectSimpleUser(appGroup.Creator), - UpdatorId: appGroup.UpdatorId, - Updator: reflectSimpleUser(appGroup.Updator), - } -} - -func reflectApplication(application Application) domain.Application { - return domain.Application{ - ID: application.ID, - AppGroupId: application.AppGroupId, - ApplicationType: application.Type, - Endpoint: application.Endpoint, - Metadata: application.Metadata.String(), - CreatedAt: application.CreatedAt, - UpdatedAt: application.UpdatedAt, +func reflectAppGroup(appGroup AppGroup) (out domain.AppGroup) { + if err := serializer.Map(appGroup.Model, &out); err != nil { + log.Error(err) } + if err := serializer.Map(appGroup, &out); err != nil { + log.Error(err) + } + return +} + +func reflectApplication(application Application) (out domain.Application) { + if err := serializer.Map(application, &out); err != nil { + log.Error(err) + } + out.Metadata = application.Metadata.String() + return + } diff --git a/internal/repository/cloud-account.go b/internal/repository/cloud-account.go index 95e4b89c..786e9f53 100644 --- a/internal/repository/cloud-account.go +++ b/internal/repository/cloud-account.go @@ -9,7 +9,9 @@ import ( "gorm.io/gorm/clause" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/log" ) // Interfaces @@ -166,21 +168,12 @@ func (r *CloudAccountRepository) InitWorkflow(cloudAccountId uuid.UUID, workflow return nil } -func reflectCloudAccount(cloudAccount CloudAccount) domain.CloudAccount { - return domain.CloudAccount{ - ID: cloudAccount.ID, - OrganizationId: cloudAccount.OrganizationId, - Name: cloudAccount.Name, - Description: cloudAccount.Description, - Resource: cloudAccount.Resource, - CloudService: cloudAccount.CloudService, - Status: cloudAccount.Status, - StatusDesc: cloudAccount.StatusDesc, - AwsAccountId: cloudAccount.AwsAccountId, - CreatedIAM: cloudAccount.CreatedIAM, - Creator: reflectSimpleUser(cloudAccount.Creator), - Updator: reflectSimpleUser(cloudAccount.Updator), - CreatedAt: cloudAccount.CreatedAt, - UpdatedAt: cloudAccount.UpdatedAt, +func reflectCloudAccount(cloudAccount CloudAccount) (out domain.CloudAccount) { + if err := serializer.Map(cloudAccount.Model, &out); err != nil { + log.Error(err) } + if err := serializer.Map(cloudAccount, &out); err != nil { + log.Error(err) + } + return } diff --git a/internal/repository/cluster.go b/internal/repository/cluster.go index 153b2c4a..570bc795 100644 --- a/internal/repository/cluster.go +++ b/internal/repository/cluster.go @@ -10,6 +10,7 @@ import ( "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" ) @@ -19,14 +20,18 @@ type IClusterRepository interface { WithTrx(*gorm.DB) IClusterRepository Fetch(pg *pagination.Pagination) (res []domain.Cluster, err error) FetchByCloudAccountId(cloudAccountId uuid.UUID, pg *pagination.Pagination) (res []domain.Cluster, err error) - FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (res []domain.Cluster, err error) + FetchByOrganizationId(organizationId string, userId uuid.UUID, pg *pagination.Pagination) (res []domain.Cluster, err error) Get(id domain.ClusterId) (domain.Cluster, error) GetByName(organizationId string, name string) (domain.Cluster, error) Create(dto domain.Cluster) (clusterId domain.ClusterId, err error) Update(dto domain.Cluster) (err error) Delete(id domain.ClusterId) error + InitWorkflow(clusterId domain.ClusterId, workflowId string, status domain.ClusterStatus) error InitWorkflowDescription(clusterId domain.ClusterId) error + + SetFavorite(clusterId domain.ClusterId, userId uuid.UUID) error + DeleteFavorite(clusterId domain.ClusterId, userId uuid.UUID) error } type ClusterRepository struct { @@ -45,28 +50,37 @@ func NewClusterRepository(db *gorm.DB) IClusterRepository { type Cluster struct { gorm.Model - ID domain.ClusterId `gorm:"primarykey"` - Name string `gorm:"index"` - OrganizationId string - Organization Organization `gorm:"foreignKey:OrganizationId"` - Description string `gorm:"index"` - WorkflowId string - Status domain.ClusterStatus - StatusDesc string - CloudAccountId uuid.UUID - CloudAccount CloudAccount `gorm:"foreignKey:CloudAccountId"` - StackTemplateId uuid.UUID - StackTemplate StackTemplate `gorm:"foreignKey:StackTemplateId"` - CpNodeCnt int - CpNodeMachineType string - TksNodeCnt int - TksNodeMachineType string - UserNodeCnt int - UserNodeMachineType string - CreatorId *uuid.UUID `gorm:"type:uuid"` - Creator User `gorm:"foreignKey:CreatorId"` - UpdatorId *uuid.UUID `gorm:"type:uuid"` - Updator User `gorm:"foreignKey:UpdatorId"` + ID domain.ClusterId `gorm:"primarykey"` + Name string `gorm:"index"` + CloudService string `gorm:"default:AWS"` + OrganizationId string + Organization Organization `gorm:"foreignKey:OrganizationId"` + Description string `gorm:"index"` + WorkflowId string + Status domain.ClusterStatus + StatusDesc string + CloudAccountId *uuid.UUID + CloudAccount CloudAccount `gorm:"foreignKey:CloudAccountId"` + StackTemplateId uuid.UUID + StackTemplate StackTemplate `gorm:"foreignKey:StackTemplateId"` + Favorites *[]ClusterFavorite + ClusterType domain.ClusterType `gorm:"default:0"` + ByoClusterEndpointHost string + ByoClusterEndpointPort int + IsStack bool `gorm:"default:false"` + TksCpNode int + TksCpNodeMax int + TksCpNodeType string + TksInfraNode int + TksInfraNodeMax int + TksInfraNodeType string + TksUserNode int + TksUserNodeMax int + TksUserNodeType string + CreatorId *uuid.UUID `gorm:"type:uuid"` + Creator User `gorm:"foreignKey:CreatorId"` + UpdatorId *uuid.UUID `gorm:"type:uuid"` + Updator User `gorm:"foreignKey:UpdatorId"` } func (c *Cluster) BeforeCreate(tx *gorm.DB) (err error) { @@ -74,6 +88,21 @@ func (c *Cluster) BeforeCreate(tx *gorm.DB) (err error) { return nil } +type ClusterFavorite struct { + gorm.Model + + ID uuid.UUID `gorm:"primarykey;type:uuid"` + ClusterId domain.ClusterId + Cluster Cluster `gorm:"foreignKey:ClusterId"` + UserId uuid.UUID `gorm:"type:uuid"` + User User `gorm:"foreignKey:UserId"` +} + +func (c *ClusterFavorite) BeforeCreate(tx *gorm.DB) (err error) { + c.ID = uuid.New() + return nil +} + // Logics func (r *ClusterRepository) WithTrx(trxHandle *gorm.DB) IClusterRepository { if trxHandle == nil { @@ -107,7 +136,7 @@ func (r *ClusterRepository) Fetch(pg *pagination.Pagination) (out []domain.Clust return } -func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { +func (r *ClusterRepository) FetchByOrganizationId(organizationId string, userId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) { var clusters []Cluster if pg == nil { pg = pagination.NewDefaultPagination() @@ -115,14 +144,16 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag pg.SortColumn = "created_at" pg.SortOrder = "DESC" filterFunc := CombinedGormFilter("clusters", pg.GetFilters(), pg.CombinedFilter) - db := filterFunc(r.db.Model(&Cluster{}).Preload(clause.Associations). + db := filterFunc(r.db.Model(&Cluster{}). + Preload(clause.Associations). + Joins("left outer join cluster_favorites on clusters.id = cluster_favorites.cluster_id AND cluster_favorites.user_id = ?", userId). Where("organization_id = ? AND status != ?", organizationId, domain.ClusterStatus_DELETED)) db.Count(&pg.TotalRows) pg.TotalPages = int(math.Ceil(float64(pg.TotalRows) / float64(pg.Limit))) orderQuery := fmt.Sprintf("%s %s", pg.SortColumn, pg.SortOrder) - res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order(orderQuery).Find(&clusters) + res := db.Offset(pg.GetOffset()).Limit(pg.GetLimit()).Order("cluster_favorites.cluster_id").Order(orderQuery).Find(&clusters) if res.Error != nil { return nil, res.Error } @@ -130,6 +161,8 @@ func (r *ClusterRepository) FetchByOrganizationId(organizationId string, pg *pag outCluster := reflectCluster(cluster) out = append(out, outCluster) } + + //log.Info(helper.ModelToJson(clusters)) return } @@ -180,21 +213,34 @@ func (r *ClusterRepository) GetByName(organizationId string, name string) (out d } func (r *ClusterRepository) Create(dto domain.Cluster) (clusterId domain.ClusterId, err error) { + var cloudAccountId *uuid.UUID + cloudAccountId = &dto.CloudAccountId + if dto.CloudService == domain.CloudService_BYOH { + cloudAccountId = nil + } cluster := Cluster{ - OrganizationId: dto.OrganizationId, - Name: dto.Name, - Description: dto.Description, - CloudAccountId: dto.CloudAccountId, - StackTemplateId: dto.StackTemplateId, - CreatorId: dto.CreatorId, - UpdatorId: nil, - Status: domain.ClusterStatus_PENDING, - CpNodeCnt: dto.Conf.CpNodeCnt, - CpNodeMachineType: dto.Conf.CpNodeMachineType, - TksNodeCnt: dto.Conf.TksNodeCnt, - TksNodeMachineType: dto.Conf.TksNodeMachineType, - UserNodeCnt: dto.Conf.UserNodeCnt, - UserNodeMachineType: dto.Conf.UserNodeMachineType, + OrganizationId: dto.OrganizationId, + Name: dto.Name, + Description: dto.Description, + CloudAccountId: cloudAccountId, + StackTemplateId: dto.StackTemplateId, + CreatorId: dto.CreatorId, + UpdatorId: nil, + Status: domain.ClusterStatus_PENDING, + ClusterType: dto.ClusterType, + CloudService: dto.CloudService, + ByoClusterEndpointHost: dto.ByoClusterEndpointHost, + ByoClusterEndpointPort: dto.ByoClusterEndpointPort, + IsStack: dto.IsStack, + TksCpNode: dto.Conf.TksCpNode, + TksCpNodeMax: dto.Conf.TksCpNodeMax, + TksCpNodeType: dto.Conf.TksCpNodeType, + TksInfraNode: dto.Conf.TksInfraNode, + TksInfraNodeMax: dto.Conf.TksInfraNodeMax, + TksInfraNodeType: dto.Conf.TksInfraNodeType, + TksUserNode: dto.Conf.TksUserNode, + TksUserNodeMax: dto.Conf.TksUserNodeMax, + TksUserNodeType: dto.Conf.TksUserNodeType, } res := r.db.Create(&cluster) if res.Error != nil { @@ -247,39 +293,60 @@ func (r *ClusterRepository) InitWorkflowDescription(clusterId domain.ClusterId) return nil } -func reflectCluster(cluster Cluster) domain.Cluster { - return domain.Cluster{ - ID: cluster.ID, - OrganizationId: cluster.OrganizationId, - Name: cluster.Name, - Description: cluster.Description, - CloudAccountId: cluster.CloudAccountId, - CloudAccount: reflectCloudAccount(cluster.CloudAccount), - StackTemplateId: cluster.StackTemplateId, - StackTemplate: reflectStackTemplate(cluster.StackTemplate), - Status: cluster.Status, - StatusDesc: cluster.StatusDesc, - CreatorId: cluster.CreatorId, - Creator: reflectSimpleUser(cluster.Creator), - UpdatorId: cluster.UpdatorId, - Updator: reflectSimpleUser(cluster.Updator), - CreatedAt: cluster.CreatedAt, - UpdatedAt: cluster.UpdatedAt, - Conf: domain.ClusterConf{ - CpNodeCnt: int(cluster.CpNodeCnt), - CpNodeMachineType: cluster.CpNodeMachineType, - TksNodeCnt: int(cluster.TksNodeCnt), - TksNodeMachineType: cluster.TksNodeMachineType, - UserNodeCnt: int(cluster.UserNodeCnt), - UserNodeMachineType: cluster.UserNodeMachineType, - }, +func (r *ClusterRepository) SetFavorite(clusterId domain.ClusterId, userId uuid.UUID) error { + var clusterFavorites []ClusterFavorite + res := r.db.Where("cluster_id = ? AND user_id = ?", clusterId, userId).Find(&clusterFavorites) + if res.Error != nil { + log.Info(res.Error) + return res.Error + } + + if len(clusterFavorites) > 0 { + return nil + } + + clusterFavorite := ClusterFavorite{ + ClusterId: clusterId, + UserId: userId, + } + resCreate := r.db.Create(&clusterFavorite) + if resCreate.Error != nil { + log.Error(resCreate.Error) + return fmt.Errorf("could not create cluster favorite for clusterId %s, userId %s", clusterId, userId) + } + + return nil +} + +func (r *ClusterRepository) DeleteFavorite(clusterId domain.ClusterId, userId uuid.UUID) error { + res := r.db.Unscoped().Delete(&ClusterFavorite{}, "cluster_id = ? AND user_id = ?", clusterId, userId) + if res.Error != nil { + log.Error(res.Error) + return fmt.Errorf("could not delete cluster favorite for clusterId %s, userId %s", clusterId, userId) } + return nil } -func reflectSimpleCluster(cluster Cluster) domain.Cluster { - return domain.Cluster{ - ID: cluster.ID, - OrganizationId: cluster.OrganizationId, - Name: cluster.Name, +func reflectCluster(cluster Cluster) (out domain.Cluster) { + if err := serializer.Map(cluster.Model, &out); err != nil { + log.Error(err) } + + if err := serializer.Map(cluster, &out); err != nil { + log.Error(err) + } + + if err := serializer.Map(cluster, &out.Conf); err != nil { + log.Error(err) + } + out.StackTemplate.Services = cluster.StackTemplate.Services + + if cluster.Favorites != nil && len(*cluster.Favorites) > 0 { + out.Favorited = true + + } else { + out.Favorited = false + } + + return } diff --git a/internal/repository/organization.go b/internal/repository/organization.go index 7e1312a0..75cc2e7a 100644 --- a/internal/repository/organization.go +++ b/internal/repository/organization.go @@ -6,6 +6,7 @@ import ( "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/log" "gorm.io/gorm" @@ -164,16 +165,14 @@ func (r *OrganizationRepository) InitWorkflow(organizationId string, workflowId return nil } -func (r *OrganizationRepository) reflect(organization Organization) domain.Organization { - return domain.Organization{ - ID: organization.ID, - Name: organization.Name, - Description: organization.Description, - Phone: organization.Phone, - PrimaryClusterId: organization.PrimaryClusterId, - Status: organization.Status, - Creator: organization.Creator.String(), - CreatedAt: organization.CreatedAt, - UpdatedAt: organization.UpdatedAt, +func (r *OrganizationRepository) reflect(organization Organization) (out domain.Organization) { + if err := serializer.Map(organization.Model, &out); err != nil { + log.Error(err) } + if err := serializer.Map(organization, &out); err != nil { + log.Error(err) + } + out.Creator = organization.Creator.String() + return + } diff --git a/internal/repository/stack-template.go b/internal/repository/stack-template.go index dc27b967..8a373949 100644 --- a/internal/repository/stack-template.go +++ b/internal/repository/stack-template.go @@ -10,7 +10,9 @@ import ( "gorm.io/gorm/clause" "github.com/openinfradev/tks-api/internal/pagination" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/log" ) // Interfaces @@ -42,6 +44,7 @@ type StackTemplate struct { Name string `gorm:"index"` Description string `gorm:"index"` Template string + TemplateType string Version string CloudService string Platform string @@ -102,6 +105,7 @@ func (r *StackTemplateRepository) Create(dto domain.StackTemplate) (stackTemplat CloudService: dto.CloudService, Platform: dto.Platform, Template: dto.Template, + TemplateType: dto.TemplateType, CreatorId: &dto.CreatorId, UpdatorId: nil} res := r.db.Create(&stackTemplate) @@ -131,23 +135,13 @@ func (r *StackTemplateRepository) Delete(dto domain.StackTemplate) (err error) { return nil } -func reflectStackTemplate(stackTemplate StackTemplate) domain.StackTemplate { - // hardcoded sample json : [{"type":"LMA","applications":[{"name":"Logging","description":"Logging 설명","version":"v1"},{"name":"Monitoring","description":"Monitoring 설명","version":"v1"},{"name":"Grafana","description":"Grafana 설명","version":"v1"}]},{"type":"SERVICE_MESH","applications":[{"name":"Istio","description":"Istio 설명","version":"v1"},{"name":"Jaeger","description":"Jaeger 설명","version":"v1"}]}] - return domain.StackTemplate{ - ID: stackTemplate.ID, - OrganizationId: stackTemplate.OrganizationId, - Name: stackTemplate.Name, - Description: stackTemplate.Description, - Template: stackTemplate.Template, - CloudService: stackTemplate.CloudService, - Platform: stackTemplate.Platform, - Version: stackTemplate.Version, - KubeVersion: stackTemplate.KubeVersion, - KubeType: stackTemplate.KubeType, - Services: stackTemplate.Services, - Creator: reflectSimpleUser(stackTemplate.Creator), - Updator: reflectSimpleUser(stackTemplate.Updator), - CreatedAt: stackTemplate.CreatedAt, - UpdatedAt: stackTemplate.UpdatedAt, +func reflectStackTemplate(stackTemplate StackTemplate) (out domain.StackTemplate) { + if err := serializer.Map(stackTemplate.Model, &out); err != nil { + log.Error(err) } + if err := serializer.Map(stackTemplate, &out); err != nil { + log.Error(err) + } + out.Services = stackTemplate.Services + return } diff --git a/internal/repository/user.go b/internal/repository/user.go index 2571b1f6..c4c254c3 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -506,16 +506,3 @@ func (r *UserRepository) reflectRole(role Role) domain.Role { UpdatedAt: role.UpdatedAt, } } - -func reflectSimpleUser(user User) domain.User { - return domain.User{ - ID: user.ID.String(), - AccountId: user.AccountId, - Name: user.Name, - Email: user.Email, - Department: user.Department, - Description: user.Description, - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - } -} diff --git a/internal/route/route.go b/internal/route/route.go index 429e8c1c..7edbd419 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "net/http" "time" @@ -74,6 +73,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa authHandler := delivery.NewAuthHandler(usecase.NewAuthUsecase(repoFactory, kc)) r.HandleFunc(API_PREFIX+API_VERSION+"/auth/login", authHandler.Login).Methods(http.MethodPost) + r.HandleFunc(API_PREFIX+API_VERSION+"/auth/ping", authHandler.PingToken).Methods(http.MethodPost) r.Handle(API_PREFIX+API_VERSION+"/auth/logout", authMiddleware.Handle(http.HandlerFunc(authHandler.Logout))).Methods(http.MethodPost) r.Handle(API_PREFIX+API_VERSION+"/auth/refresh", authMiddleware.Handle(http.HandlerFunc(authHandler.RefreshToken))).Methods(http.MethodPost) r.HandleFunc(API_PREFIX+API_VERSION+"/auth/find-id/verification", authHandler.FindId).Methods(http.MethodPost) @@ -112,8 +112,12 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+"/clusters", authMiddleware.Handle(http.HandlerFunc(clusterHandler.CreateCluster))).Methods(http.MethodPost) r.Handle(API_PREFIX+API_VERSION+"/clusters", authMiddleware.Handle(http.HandlerFunc(clusterHandler.GetClusters))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}", authMiddleware.Handle(http.HandlerFunc(clusterHandler.GetCluster))).Methods(http.MethodGet) - r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}/site-values", authMiddleware.Handle(http.HandlerFunc(clusterHandler.GetClusterSiteValues))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}", authMiddleware.Handle(http.HandlerFunc(clusterHandler.DeleteCluster))).Methods(http.MethodDelete) + r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}/site-values", authMiddleware.Handle(http.HandlerFunc(clusterHandler.GetClusterSiteValues))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}/install", authMiddleware.Handle(http.HandlerFunc(clusterHandler.InstallCluster))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}/bootstrap-kubeconfig", authMiddleware.Handle(http.HandlerFunc(clusterHandler.CreateBootstrapKubeconfig))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}/bootstrap-kubeconfig", authMiddleware.Handle(http.HandlerFunc(clusterHandler.GetBootstrapKubeconfig))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/clusters/{clusterId}/nodes", authMiddleware.Handle(http.HandlerFunc(clusterHandler.GetNodes))).Methods(http.MethodGet) appGroupHandler := delivery.NewAppGroupHandler(usecase.NewAppGroupUsecase(repoFactory, argoClient)) r.Handle(API_PREFIX+API_VERSION+"/app-groups", authMiddleware.Handle(http.HandlerFunc(appGroupHandler.CreateAppGroup))).Methods(http.MethodPost) @@ -148,6 +152,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/cloud-accounts/{cloudAccountId}", authMiddleware.Handle(http.HandlerFunc(cloudAccountHandler.UpdateCloudAccount))).Methods(http.MethodPut) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/cloud-accounts/{cloudAccountId}", authMiddleware.Handle(http.HandlerFunc(cloudAccountHandler.DeleteCloudAccount))).Methods(http.MethodDelete) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/cloud-accounts/{cloudAccountId}/error", authMiddleware.Handle(http.HandlerFunc(cloudAccountHandler.DeleteForceCloudAccount))).Methods(http.MethodDelete) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/cloud-accounts/{cloudAccountId}/quotas", authMiddleware.Handle(http.HandlerFunc(cloudAccountHandler.GetResourceQuota))).Methods(http.MethodGet) stackTemplateHandler := delivery.NewStackTemplateHandler(usecase.NewStackTemplateUsecase(repoFactory)) r.Handle(API_PREFIX+API_VERSION+"/stack-templates", authMiddleware.Handle(http.HandlerFunc(stackTemplateHandler.GetStackTemplates))).Methods(http.MethodGet) @@ -156,16 +161,6 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+"/stack-templates/{stackTemplateId}", authMiddleware.Handle(http.HandlerFunc(stackTemplateHandler.UpdateStackTemplate))).Methods(http.MethodPut) r.Handle(API_PREFIX+API_VERSION+"/stack-templates/{stackTemplateId}", authMiddleware.Handle(http.HandlerFunc(stackTemplateHandler.DeleteStackTemplate))).Methods(http.MethodDelete) - stackHandler := delivery.NewStackHandler(usecase.NewStackUsecase(repoFactory, argoClient)) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStacks))).Methods(http.MethodGet) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks", authMiddleware.Handle(http.HandlerFunc(stackHandler.CreateStack))).Methods(http.MethodPost) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/name/{name}/existence", authMiddleware.Handle(http.HandlerFunc(stackHandler.CheckStackName))).Methods(http.MethodGet) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStack))).Methods(http.MethodGet) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.UpdateStack))).Methods(http.MethodPut) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.DeleteStack))).Methods(http.MethodDelete) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/kube-config", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStackKubeConfig))).Methods(http.MethodGet) - r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/status", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStackStatus))).Methods(http.MethodGet) - dashboardHandler := delivery.NewDashboardHandler(usecase.NewDashboardUsecase(repoFactory, cache)) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/dashboard/charts", authMiddleware.Handle(http.HandlerFunc(dashboardHandler.GetCharts))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/dashboard/charts/{chartType}", authMiddleware.Handle(http.HandlerFunc(dashboardHandler.GetChart))).Methods(http.MethodGet) @@ -181,6 +176,19 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/alerts/{alertId}/actions", authMiddleware.Handle(http.HandlerFunc(alertHandler.CreateAlertAction))).Methods(http.MethodPost) //r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/alerts/{alertId}/actions/status", authMiddleware.Handle(http.HandlerFunc(alertHandler.UpdateAlertActionStatus))).Methods(http.MethodPatch) + stackHandler := delivery.NewStackHandler(usecase.NewStackUsecase(repoFactory, argoClient, usecase.NewDashboardUsecase(repoFactory, cache))) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStacks))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks", authMiddleware.Handle(http.HandlerFunc(stackHandler.CreateStack))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/name/{name}/existence", authMiddleware.Handle(http.HandlerFunc(stackHandler.CheckStackName))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStack))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.UpdateStack))).Methods(http.MethodPut) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}", authMiddleware.Handle(http.HandlerFunc(stackHandler.DeleteStack))).Methods(http.MethodDelete) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/kube-config", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStackKubeConfig))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/status", authMiddleware.Handle(http.HandlerFunc(stackHandler.GetStackStatus))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/favorite", authMiddleware.Handle(http.HandlerFunc(stackHandler.SetFavorite))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/favorite", authMiddleware.Handle(http.HandlerFunc(stackHandler.DeleteFavorite))).Methods(http.MethodDelete) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/stacks/{stackId}/install", authMiddleware.Handle(http.HandlerFunc(stackHandler.InstallStack))).Methods(http.MethodPost) + r.HandleFunc(API_PREFIX+API_VERSION+"/alerttest", alertHandler.CreateAlert).Methods(http.MethodPost) // assets r.PathPrefix("/api/").HandlerFunc(http.NotFound) @@ -207,7 +215,7 @@ func loggingMiddleware(next http.Handler) http.Handler { if err == nil { log.InfoWithContext(r.Context(), fmt.Sprintf("REQUEST BODY : %s", bytes.NewBuffer(body).String())) } - r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + r.Body = io.NopCloser(bytes.NewBuffer(body)) next.ServeHTTP(w, r) diff --git a/internal/serializer/serializer.go b/internal/serializer/serializer.go new file mode 100644 index 00000000..70e96552 --- /dev/null +++ b/internal/serializer/serializer.go @@ -0,0 +1,115 @@ +package serializer + +import ( + "fmt" + "reflect" + + "github.com/google/uuid" + "github.com/openinfradev/tks-api/pkg/domain" + "github.com/openinfradev/tks-api/pkg/log" +) + +type ConverterMap map[compositeKey]func(interface{}) (interface{}, error) + +type compositeKey struct { + srcType reflect.Type + dstType reflect.Type +} + +func recursiveMap(src interface{}, dst interface{}, converterMap ConverterMap) error { + srcVal := reflect.ValueOf(src) + srcType := srcVal.Type() + + if srcType.Kind() == reflect.Slice { + return fmt.Errorf("not support src type (Slice)") + } + + dstVal := reflect.ValueOf(dst) + if dstVal.Kind() != reflect.Ptr || dstVal.IsNil() { + return fmt.Errorf("dst must be a non-nil pointer") + } + dstElem := dstVal.Elem() + + for i := 0; i < srcVal.NumField(); i++ { + fieldName := srcType.Field(i).Name + srcField := srcVal.Field(i) + dstField := dstElem.FieldByName(fieldName) + + if dstField.IsValid() && dstField.CanSet() { + if dstField.Type() == srcField.Type() { + dstField.Set(srcField) + continue + } else if srcField.Type().Kind() == reflect.Struct && dstField.Type().Kind() == reflect.Struct { + if err := recursiveMap(srcField.Interface(), dstField.Addr().Interface(), converterMap); err != nil { + return err + } + } else { + if functionExists(srcField.Interface(), "String") && + functionExists(srcField.Interface(), "FromString") && + dstField.Type().Kind() == reflect.String { + mthd := reflect.ValueOf(srcField.Interface()).MethodByName("String").Call([]reflect.Value{}) + if len(mthd) > 0 { + dstField.Set(mthd[0]) + continue + } + } + if functionExists(dstField.Interface(), "String") && + functionExists(dstField.Interface(), "FromString") && + srcField.Type().Kind() == reflect.String { + mthd := reflect.ValueOf(dstField.Interface()).MethodByName("FromString").Call([]reflect.Value{srcField}) + if len(mthd) > 0 { + dstField.Set(mthd[0]) + continue + } + } + + converterKey := compositeKey{srcType: srcField.Type(), dstType: dstField.Type()} + if converter, ok := converterMap[converterKey]; ok { + if converted, err := converter(srcField.Interface()); err != nil { + return err + } else { + dstField.Set(reflect.ValueOf(converted)) + } + } else { + log.Debugf("no converter found for %s -> %s", srcField.Type(), dstField.Type()) + continue + } + } + + /* + else if srcField.Type().Kind() == reflect.Ptr && dstField.Type().Kind() == reflect.Ptr { + log.Info("AAA ", dstField.Type()) + ptr := reflect.New(dstField.Elem().Type()) + if err := recursiveMap(srcField.Elem().Interface(), ptr.Elem().Interface(), converterMap); err != nil { + return err + } + } + */ + + } + } + + return nil +} +func Map(src interface{}, dst interface{}) error { + return recursiveMap(src, dst, ConverterMap{ + {srcType: reflect.TypeOf((*uuid.UUID)(nil)).Elem(), dstType: reflect.TypeOf("")}: func(i interface{}) (interface{}, error) { + return i.(uuid.UUID).String(), nil + }, + {srcType: reflect.TypeOf(""), dstType: reflect.TypeOf((*uuid.UUID)(nil)).Elem()}: func(i interface{}) (interface{}, error) { + val, _ := uuid.Parse(i.(string)) + return val, nil + }, + {srcType: reflect.TypeOf((*domain.Role)(nil)).Elem(), dstType: reflect.TypeOf("")}: func(i interface{}) (interface{}, error) { + return i.(domain.Role).Name, nil + }, + {srcType: reflect.TypeOf(""), dstType: reflect.TypeOf((*domain.Role)(nil)).Elem()}: func(i interface{}) (interface{}, error) { + return domain.Role{Name: i.(string)}, nil + }, + }) +} + +func functionExists(obj interface{}, funcName string) bool { + mthd := reflect.ValueOf(obj).MethodByName(funcName) + return mthd.IsValid() +} diff --git a/internal/usecase/app-group.go b/internal/usecase/app-group.go index e17fa685..1595bafa 100644 --- a/internal/usecase/app-group.go +++ b/internal/usecase/app-group.go @@ -78,25 +78,30 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d } // check cloudAccount - cloudAccounts, err := u.cloudAccountRepo.Fetch(cluster.OrganizationId, nil) - if err != nil { - return "", httpErrors.NewBadRequestError(fmt.Errorf("Failed to get cloudAccounts"), "", "") - } - tksCloudAccountId := cluster.CloudAccountId.String() - isExist := false - for _, ca := range cloudAccounts { - if ca.ID == cluster.CloudAccountId { - - // FOR TEST. ADD MAGIC KEYWORD - if strings.Contains(ca.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { - tksCloudAccountId = "" + tksCloudAccountId := "" + tksObjectStore := "minio" + if cluster.CloudService != domain.CloudService_BYOH { + tksObjectStore = "aws" + cloudAccounts, err := u.cloudAccountRepo.Fetch(cluster.OrganizationId, nil) + if err != nil { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Failed to get cloudAccounts"), "", "") + } + tksCloudAccountId = cluster.CloudAccountId.String() + isExist := false + for _, ca := range cloudAccounts { + if ca.ID == cluster.CloudAccountId { + + // FOR TEST. ADD MAGIC KEYWORD + if strings.Contains(ca.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { + tksCloudAccountId = "" + } + isExist = true + break } - isExist = true - break } - } - if !isExist { - return "", httpErrors.NewBadRequestError(fmt.Errorf("Not found cloudAccountId[%s] in organization[%s]", cluster.CloudAccountId, cluster.OrganizationId), "", "") + if !isExist { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Not found cloudAccountId[%s] in organization[%s]", cluster.CloudAccountId, cluster.OrganizationId), "", "") + } } if dto.ID == "" { @@ -123,6 +128,7 @@ func (u *AppGroupUsecase) Create(ctx context.Context, dto domain.AppGroup) (id d "alert_tks=" + viper.GetString("external-address") + "/system-api/1.0/alerts", "alert_slack=" + viper.GetString("alert-slack"), "cloud_account_id=" + tksCloudAccountId, + "object_store=" + tksObjectStore, } switch dto.AppGroupType { diff --git a/internal/usecase/app-serve-app.go b/internal/usecase/app-serve-app.go index 53e38005..38e0b702 100644 --- a/internal/usecase/app-serve-app.go +++ b/internal/usecase/app-serve-app.go @@ -41,14 +41,18 @@ type IAppServeAppUsecase interface { } type AppServeAppUsecase struct { - repo repository.IAppServeAppRepository - argo argowf.ArgoClient + repo repository.IAppServeAppRepository + organizationRepo repository.IOrganizationRepository + appGroupRepo repository.IAppGroupRepository + argo argowf.ArgoClient } func NewAppServeAppUsecase(r repository.Repository, argoClient argowf.ArgoClient) IAppServeAppUsecase { return &AppServeAppUsecase{ - repo: r.AppServeApp, - argo: argoClient, + repo: r.AppServeApp, + organizationRepo: r.Organization, + appGroupRepo: r.AppGroup, + argo: argoClient, } } @@ -158,7 +162,7 @@ func (u *AppServeAppUsecase) CreateAppServeApp(app *domain.AppServeApp) (string, "pv_access_mode=" + app.AppServeAppTasks[0].PvAccessMode, "pv_size=" + app.AppServeAppTasks[0].PvSize, "pv_mount_path=" + app.AppServeAppTasks[0].PvMountPath, - "tks_info_host=" + viper.GetString("external-address"), + "tks_api_url=" + viper.GetString("external-address"), } log.Info("Submitting workflow: ", workflow) @@ -183,12 +187,37 @@ func (u *AppServeAppUsecase) GetAppServeApps(organizationId string, showAll bool } func (u *AppServeAppUsecase) GetAppServeAppById(appId string) (*domain.AppServeApp, error) { - app, err := u.repo.GetAppServeAppById(appId) + asa, err := u.repo.GetAppServeAppById(appId) if err != nil { return nil, err } - return app, nil + /************************ + * Construct grafana URL * + ************************/ + organization, err := u.organizationRepo.Get(asa.OrganizationId) + if err != nil { + return asa, httpErrors.NewInternalServerError(errors.Wrap(err, fmt.Sprintf("Failed to get organization for app %s", asa.Name)), "S_FAILED_FETCH_ORGANIZATION", "") + } + + appGroupsInPrimaryCluster, err := u.appGroupRepo.Fetch(domain.ClusterId(organization.PrimaryClusterId), nil) + if err != nil { + return asa, err + } + + for _, appGroup := range appGroupsInPrimaryCluster { + if appGroup.AppGroupType == domain.AppGroupType_LMA { + applications, err := u.appGroupRepo.GetApplications(appGroup.ID, domain.ApplicationType_GRAFANA) + if err != nil { + return asa, err + } + if len(applications) > 0 { + asa.GrafanaUrl = applications[0].Endpoint + "/d/tks_appserving_dashboard/tks-appserving-dashboard?refresh=30s&var-cluster=" + asa.TargetClusterId + "&var-kubernetes_namespace_name=" + asa.Namespace + "&var-kubernetes_pod_name=All&var-kubernetes_container_name=main&var-TopK=10" + } + } + } + + return asa, nil } func (u *AppServeAppUsecase) GetAppServeAppLatestTask(appId string) (*domain.AppServeAppTask, error) { @@ -350,7 +379,7 @@ func (u *AppServeAppUsecase) DeleteAppServeApp(appId string) (res string, err er "asa_id=" + app.ID, "asa_task_id=" + taskId, "organization_id=" + app.OrganizationId, - "tks_info_host=" + viper.GetString("external-address"), + "tks_api_url=" + viper.GetString("external-address"), }, }) if err != nil { @@ -478,7 +507,7 @@ func (u *AppServeAppUsecase) UpdateAppServeApp(app *domain.AppServeApp, appTask "pv_access_mode=" + appTask.PvAccessMode, "pv_size=" + appTask.PvSize, "pv_mount_path=" + appTask.PvMountPath, - "tks_info_host=" + viper.GetString("external-address"), + "tks_api_url=" + viper.GetString("external-address"), }, }) if err != nil { @@ -536,7 +565,7 @@ func (u *AppServeAppUsecase) PromoteAppServeApp(appId string) (ret string, err e "asa_id=" + app.ID, "asa_task_id=" + latestTaskId, "strategy=" + strategy, - "tks_info_host=" + viper.GetString("external-address"), + "tks_api_url=" + viper.GetString("external-address"), }, }) if err != nil { @@ -589,7 +618,7 @@ func (u *AppServeAppUsecase) AbortAppServeApp(appId string) (ret string, err err "asa_id=" + app.ID, "asa_task_id=" + latestTaskId, "strategy=" + strategy, - "tks_info_host=" + viper.GetString("external-address"), + "tks_api_url=" + viper.GetString("external-address"), }, }) if err != nil { @@ -662,7 +691,7 @@ func (u *AppServeAppUsecase) RollbackAppServeApp(appId string, taskId string) (r "asa_id=" + app.ID, "asa_task_id=" + newTaskId, "helm_revision=" + strconv.Itoa(int(targetRev)), - "tks_info_host=" + viper.GetString("external-address"), + "tks_api_url=" + viper.GetString("external-address"), }, }) if err != nil { diff --git a/internal/usecase/auth.go b/internal/usecase/auth.go index 02b43103..1c1c3f8b 100644 --- a/internal/usecase/auth.go +++ b/internal/usecase/auth.go @@ -19,9 +19,9 @@ import ( "github.com/Nerzal/gocloak/v13" "github.com/google/uuid" "github.com/openinfradev/tks-api/internal" - "github.com/openinfradev/tks-api/internal/aws/ses" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/keycloak" + "github.com/openinfradev/tks-api/internal/mail" "github.com/openinfradev/tks-api/internal/repository" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -30,6 +30,7 @@ import ( type IAuthUsecase interface { Login(accountId string, password string, organizationId string) (domain.User, error) Logout(accessToken string, organizationId string) error + PingToken(accessToken string, organizationId string) error FindId(code string, email string, userName string, organizationId string) (string, error) FindPassword(code string, accountId string, email string, userName string, organizationId string) error VerifyIdentity(accountId string, email string, userName string, organizationId string) error @@ -103,6 +104,15 @@ func (u *AuthUsecase) Logout(accessToken string, organizationName string) error } return nil } + +func (u *AuthUsecase) PingToken(accessToken string, organizationId string) error { + if err := u.kc.VerifyAccessToken(accessToken, organizationId); err != nil { + log.Errorf("failed to verify access token: %v", err) + return err + } + return nil +} + func (u *AuthUsecase) FindId(code string, email string, userName string, organizationId string) (string, error) { users, err := u.userRepository.List(u.userRepository.OrganizationFilter(organizationId), u.userRepository.NameFilter(userName), u.userRepository.EmailFilter(email)) @@ -182,7 +192,15 @@ func (u *AuthUsecase) FindPassword(code string, accountId string, email string, return httpErrors.NewInternalServerError(err, "", "") } - if err = ses.SendEmailForTemporaryPassword(ses.Client, email, randomPassword); err != nil { + message, err := mail.MakeTemporaryPasswordMessage(email, randomPassword) + if err != nil { + log.Errorf("mail.MakeVerityIdentityMessage error. %v", err) + return httpErrors.NewInternalServerError(err, "", "") + } + + mailer := mail.New(message) + + if err := mailer.SendMail(); err != nil { return httpErrors.NewInternalServerError(err, "", "") } @@ -230,7 +248,17 @@ func (u *AuthUsecase) VerifyIdentity(accountId string, email string, userName st return httpErrors.NewInternalServerError(err, "", "") } } - if err := ses.SendEmailForVerityIdentity(ses.Client, email, code); err != nil { + + message, err := mail.MakeVerityIdentityMessage(email, code) + if err != nil { + log.Errorf("mail.MakeVerityIdentityMessage error. %v", err) + return httpErrors.NewInternalServerError(err, "", "") + } + + mailer := mail.New(message) + + if err := mailer.SendMail(); err != nil { + log.Errorf("mailer.SendMail error. %v", err) return httpErrors.NewInternalServerError(err, "", "") } diff --git a/internal/usecase/cloud-account.go b/internal/usecase/cloud-account.go index 713f953d..a938066f 100644 --- a/internal/usecase/cloud-account.go +++ b/internal/usecase/cloud-account.go @@ -5,6 +5,17 @@ import ( "fmt" "strings" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/eks" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" + "github.com/aws/aws-sdk-go-v2/service/servicequotas" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/google/uuid" @@ -24,6 +35,7 @@ type ICloudAccountUsecase interface { Get(ctx context.Context, cloudAccountId uuid.UUID) (domain.CloudAccount, error) GetByName(ctx context.Context, organizationId string, name string) (domain.CloudAccount, error) GetByAwsAccountId(ctx context.Context, awsAccountId string) (domain.CloudAccount, error) + GetResourceQuota(ctx context.Context, cloudAccountId uuid.UUID) (available bool, out domain.ResourceQuota, err error) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.CloudAccount, error) Create(ctx context.Context, dto domain.CloudAccount) (cloudAccountId uuid.UUID, err error) Update(ctx context.Context, dto domain.CloudAccount) error @@ -228,6 +240,205 @@ func (u *CloudAccountUsecase) DeleteForce(ctx context.Context, cloudAccountId uu return nil } +func (u *CloudAccountUsecase) GetResourceQuota(ctx context.Context, cloudAccountId uuid.UUID) (available bool, out domain.ResourceQuota, err error) { + cloudAccount, err := u.repo.Get(cloudAccountId) + if err != nil { + return false, out, err + } + + awsAccessKeyId, awsSecretAccessKey, _ := kubernetes.GetAwsSecret() + if err != nil || awsAccessKeyId == "" || awsSecretAccessKey == "" { + log.ErrorWithContext(ctx, err) + return false, out, httpErrors.NewInternalServerError(fmt.Errorf("Invalid aws secret."), "", "") + } + + cfg, err := config.LoadDefaultConfig(ctx, + config.WithCredentialsProvider(credentials.StaticCredentialsProvider{ + Value: aws.Credentials{ + AccessKeyID: awsAccessKeyId, SecretAccessKey: awsSecretAccessKey, + }, + })) + if err != nil { + log.ErrorWithContext(ctx, err) + } + + stsSvc := sts.NewFromConfig(cfg) + + if !strings.Contains(cloudAccount.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { + log.InfoWithContext(ctx, "Use assume role. awsAccountId : ", cloudAccount.AwsAccountId) + creds := stscreds.NewAssumeRoleProvider(stsSvc, "arn:aws:iam::"+cloudAccount.AwsAccountId+":role/controllers.cluster-api-provider-aws.sigs.k8s.io") + cfg.Credentials = aws.NewCredentialsCache(creds) + } + client := servicequotas.NewFromConfig(cfg) + + quotaMap := map[string]string{ + "L-69A177A2": "elasticloadbalancing", // NLB + "L-E9E9831D": "elasticloadbalancing", // Classic + "L-A4707A72": "vpc", // IGW + "L-1194D53C": "eks", // Cluster + "L-0263D0A3": "ec2", // Elastic IP + } + + // current usage + type CurrentUsage struct { + NLB int + CLB int + IGW int + Cluster int + EIP int + } + + out.Quotas = make([]domain.ResourceQuotaAttr, 0) + + // get current usage + currentUsage := CurrentUsage{} + { + c := elasticloadbalancingv2.NewFromConfig(cfg) + pageSize := int32(100) + res, err := c.DescribeLoadBalancers(ctx, &elasticloadbalancingv2.DescribeLoadBalancersInput{ + PageSize: &pageSize, + }, func(o *elasticloadbalancingv2.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + return false, out, err + } + + for _, elb := range res.LoadBalancers { + switch elb.Type { + case "network": + currentUsage.NLB += 1 + } + } + } + + { + c := elasticloadbalancing.NewFromConfig(cfg) + pageSize := int32(100) + res, err := c.DescribeLoadBalancers(ctx, &elasticloadbalancing.DescribeLoadBalancersInput{ + PageSize: &pageSize, + }, func(o *elasticloadbalancing.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + return false, out, err + } + currentUsage.CLB = len(res.LoadBalancerDescriptions) + } + + { + c := ec2.NewFromConfig(cfg) + res, err := c.DescribeInternetGateways(ctx, &ec2.DescribeInternetGatewaysInput{}, func(o *ec2.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + return false, out, err + } + currentUsage.IGW = len(res.InternetGateways) + } + + { + c := eks.NewFromConfig(cfg) + res, err := c.ListClusters(ctx, &eks.ListClustersInput{}, func(o *eks.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + return false, out, err + } + currentUsage.Cluster = len(res.Clusters) + } + + { + c := ec2.NewFromConfig(cfg) + res, err := c.DescribeAddresses(ctx, &ec2.DescribeAddressesInput{}, func(o *ec2.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + log.ErrorWithContext(ctx, err) + return false, out, err + } + currentUsage.EIP = len(res.Addresses) + } + + for key, val := range quotaMap { + res, err := getServiceQuota(client, key, val) + if err != nil { + return false, out, err + } + log.DebugfWithContext(ctx, "%s %s %v", *res.Quota.QuotaName, *res.Quota.QuotaCode, *res.Quota.Value) + + quotaValue := int(*res.Quota.Value) + + // stack 1개 생성하는데 필요한 quota + // Classic 1 + // Network 5 + // IGW 1 + // EIP 3 + // Cluster 1 + switch key { + case "L-69A177A2": // NLB + log.InfofWithContext(ctx, "NLB : usage %d, quota %d", currentUsage.NLB, quotaValue) + out.Quotas = append(out.Quotas, domain.ResourceQuotaAttr{ + Type: "NLB", + Usage: currentUsage.NLB, + Quota: quotaValue, + Required: 5, + }) + if quotaValue < currentUsage.NLB+5 { + available = false + } + case "L-E9E9831D": // Classic + log.InfofWithContext(ctx, "CLB : usage %d, quota %d", currentUsage.CLB, quotaValue) + out.Quotas = append(out.Quotas, domain.ResourceQuotaAttr{ + Type: "CLB", + Usage: currentUsage.CLB, + Quota: quotaValue, + Required: 1, + }) + if quotaValue < currentUsage.CLB+1 { + available = false + } + case "L-A4707A72": // IGW + log.InfofWithContext(ctx, "IGW : usage %d, quota %d", currentUsage.IGW, quotaValue) + out.Quotas = append(out.Quotas, domain.ResourceQuotaAttr{ + Type: "IGW", + Usage: currentUsage.IGW, + Quota: quotaValue, + Required: 1, + }) + if quotaValue < currentUsage.IGW+1 { + available = false + } + case "L-1194D53C": // Cluster + log.InfofWithContext(ctx, "Cluster : usage %d, quota %d", currentUsage.Cluster, quotaValue) + out.Quotas = append(out.Quotas, domain.ResourceQuotaAttr{ + Type: "EKS", + Usage: currentUsage.Cluster, + Quota: quotaValue, + Required: 1, + }) + if quotaValue < currentUsage.Cluster+1 { + available = false + } + case "L-0263D0A3": // Elastic IP + log.InfofWithContext(ctx, "Elastic IP : usage %d, quota %d", currentUsage.EIP, quotaValue) + out.Quotas = append(out.Quotas, domain.ResourceQuotaAttr{ + Type: "EIP", + Usage: currentUsage.EIP, + Quota: quotaValue, + Required: 3, + }) + if quotaValue < currentUsage.EIP+3 { + available = false + } + } + + } + + //return fmt.Errorf("Always return err") + return true, out, nil +} + func (u *CloudAccountUsecase) getClusterCnt(cloudAccountId uuid.UUID) (cnt int) { cnt = 0 @@ -245,3 +456,16 @@ func (u *CloudAccountUsecase) getClusterCnt(cloudAccountId uuid.UUID) (cnt int) return cnt } + +func getServiceQuota(client *servicequotas.Client, quotaCode string, serviceCode string) (res *servicequotas.GetServiceQuotaOutput, err error) { + res, err = client.GetServiceQuota(context.TODO(), &servicequotas.GetServiceQuotaInput{ + QuotaCode: "aCode, + ServiceCode: &serviceCode, + }, func(o *servicequotas.Options) { + o.Region = "ap-northeast-2" + }) + if err != nil { + return nil, err + } + return +} diff --git a/internal/usecase/cluster.go b/internal/usecase/cluster.go index 8048c068..13d2be0b 100644 --- a/internal/usecase/cluster.go +++ b/internal/usecase/cluster.go @@ -2,14 +2,21 @@ package usecase import ( "context" + "encoding/json" "fmt" "strings" + "time" + "github.com/openinfradev/tks-api/internal/helper" + "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/middleware/auth/request" + byoh "github.com/vmware-tanzu/cluster-api-provider-bringyourownhost/apis/infrastructure/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" + "github.com/openinfradev/tks-api/internal/serializer" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -17,6 +24,7 @@ import ( gcache "github.com/patrickmn/go-cache" "github.com/pkg/errors" "github.com/spf13/viper" + "gopkg.in/yaml.v3" "gorm.io/gorm" ) @@ -25,9 +33,14 @@ type IClusterUsecase interface { Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.Cluster, error) FetchByCloudAccountId(ctx context.Context, cloudAccountId uuid.UUID, pg *pagination.Pagination) (out []domain.Cluster, err error) Create(ctx context.Context, dto domain.Cluster) (clusterId domain.ClusterId, err error) + Bootstrap(ctx context.Context, dto domain.Cluster) (clusterId domain.ClusterId, err error) + Install(ctx context.Context, clusterId domain.ClusterId) (err error) Get(ctx context.Context, clusterId domain.ClusterId) (out domain.Cluster, err error) GetClusterSiteValues(ctx context.Context, clusterId domain.ClusterId) (out domain.ClusterSiteValuesResponse, err error) Delete(ctx context.Context, clusterId domain.ClusterId) (err error) + CreateBootstrapKubeconfig(ctx context.Context, clusterId domain.ClusterId) (out domain.BootstrapKubeconfig, err error) + GetBootstrapKubeconfig(ctx context.Context, clusterId domain.ClusterId) (out domain.BootstrapKubeconfig, err error) + GetNodes(ctx context.Context, clusterId domain.ClusterId) (out []domain.ClusterNode, err error) } type ClusterUsecase struct { @@ -85,11 +98,16 @@ func (u *ClusterUsecase) WithTrx(trxHandle *gorm.DB) IClusterUsecase { } func (u *ClusterUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []domain.Cluster, err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return out, httpErrors.NewBadRequestError(fmt.Errorf("Invalid token"), "", "") + } + if organizationId == "" { // [TODO] 사용자가 속한 organization 리스트 out, err = u.repo.Fetch(pg) } else { - out, err = u.repo.FetchByOrganizationId(organizationId, pg) + out, err = u.repo.FetchByOrganizationId(organizationId, user.GetUserId(), pg) } if err != nil { @@ -150,20 +168,9 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste if err != nil { return "", httpErrors.NewBadRequestError(errors.Wrap(err, "Invalid stackTemplateId"), "", "") } - - /*************************** - * Pre-process cluster conf * - ***************************/ - /* - clConf, err := u.constructClusterConf(&domain.ClusterConf{ - Region: dto.Conf.Region, - NumOfAz: dto.Conf.NumOfAz, - SshKeyName: "", - MachineType: dto.Conf.MachineType, - MachineReplicas: dto.Conf.MachineReplicas, - }, - ) - */ + if stackTemplate.CloudService != dto.CloudService { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloudService for stackTemplate "), "", "") + } userId := user.GetUserId() dto.CreatorId = &userId @@ -172,12 +179,11 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste return "", errors.Wrap(err, "Failed to create cluster") } - // Call argo workflow workflowId, err := u.argo.SumbitWorkflowFromWftpl( "create-tks-usercluster", argowf.SubmitOptions{ Parameters: []string{ - fmt.Sprintf("tks_info_host=%s", viper.GetString("external-address")), + fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), "contract_id=" + dto.OrganizationId, "cluster_id=" + clusterId.String(), "site_name=" + clusterId.String(), @@ -186,6 +192,7 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste "creator=" + user.GetUserId().String(), "cloud_account_id=" + tksCloudAccountId, "base_repo_branch=" + viper.GetString("revision"), + "keycloak_url=" + viper.GetString("keycloak-address"), //"manifest_repo_url=" + viper.GetString("git-base-url") + "/" + viper.GetString("git-account") + "/" + clusterId + "-manifests", }, }) @@ -202,6 +209,105 @@ func (u *ClusterUsecase) Create(ctx context.Context, dto domain.Cluster) (cluste return clusterId, nil } +func (u *ClusterUsecase) Bootstrap(ctx context.Context, dto domain.Cluster) (clusterId domain.ClusterId, err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid token"), "", "") + } + + _, err = u.repo.GetByName(dto.OrganizationId, dto.Name) + if err == nil { + return "", httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "", "") + } + + stackTemplate, err := u.stackTemplateRepo.Get(dto.StackTemplateId) + if err != nil { + return "", httpErrors.NewBadRequestError(errors.Wrap(err, "Invalid stackTemplateId"), "", "") + } + log.InfofWithContext(ctx, "%s %s", stackTemplate.CloudService, dto.CloudService) + if stackTemplate.CloudService != dto.CloudService { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloudService for stackTemplate "), "", "") + } + + userId := user.GetUserId() + dto.CreatorId = &userId + clusterId, err = u.repo.Create(dto) + if err != nil { + return "", errors.Wrap(err, "Failed to create cluster") + } + + workflow := "create-byoh-bootstrapkubeconfig" + workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflow, argowf.SubmitOptions{ + Parameters: []string{ + fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), + "cluster_id=" + clusterId.String(), + }, + }) + if err != nil { + log.ErrorWithContext(ctx, "failed to submit argo workflow template. err : ", err) + return "", err + } + log.InfoWithContext(ctx, "Successfully submited workflow: ", workflowId) + + if err := u.repo.InitWorkflow(clusterId, workflowId, domain.ClusterStatus_BOOTSTRAPPING); err != nil { + return "", errors.Wrap(err, "Failed to initialize status") + } + + return clusterId, nil +} + +func (u *ClusterUsecase) Install(ctx context.Context, clusterId domain.ClusterId) (err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid token"), "", "") + } + + cluster, err := u.repo.Get(clusterId) + if err != nil { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterId"), "C_INVALID_CLUSTER_ID", "") + } + if cluster.CloudService != domain.CloudService_BYOH { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloudService"), "C_INVALID_CLOUD_SERVICE", "") + } + + stackTemplate, err := u.stackTemplateRepo.Get(cluster.StackTemplateId) + if err != nil { + return httpErrors.NewBadRequestError(errors.Wrap(err, "Invalid stackTemplateId"), "", "") + } + if stackTemplate.CloudService != cluster.CloudService { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloudService for stackTemplate "), "", "") + } + + workflowId, err := u.argo.SumbitWorkflowFromWftpl( + "create-tks-usercluster", + argowf.SubmitOptions{ + Parameters: []string{ + fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), + "contract_id=" + cluster.OrganizationId, + "cluster_id=" + cluster.ID.String(), + "site_name=" + cluster.ID.String(), + "template_name=" + stackTemplate.Template, + "git_account=" + viper.GetString("git-account"), + "creator=" + user.GetUserId().String(), + "cloud_account_id=NULL", + "base_repo_branch=" + viper.GetString("revision"), + "keycloak_url=" + viper.GetString("keycloak-address"), + //"manifest_repo_url=" + viper.GetString("git-base-url") + "/" + viper.GetString("git-account") + "/" + clusterId + "-manifests", + }, + }) + if err != nil { + log.ErrorWithContext(ctx, "failed to submit argo workflow template. err : ", err) + return err + } + log.InfoWithContext(ctx, "Successfully submited workflow: ", workflowId) + + if err := u.repo.InitWorkflow(cluster.ID, workflowId, domain.ClusterStatus_INSTALLING); err != nil { + return errors.Wrap(err, "Failed to initialize status") + } + + return nil +} + func (u *ClusterUsecase) Get(ctx context.Context, clusterId domain.ClusterId) (out domain.Cluster, err error) { cluster, err := u.repo.Get(clusterId) if err != nil { @@ -234,13 +340,16 @@ func (u *ClusterUsecase) Delete(ctx context.Context, clusterId domain.ClusterId) // FOR TEST. ADD MAGIC KEYWORD // check cloudAccount - cloudAccount, err := u.cloudAccountRepo.Get(cluster.CloudAccountId) - if err != nil { - return httpErrors.NewInternalServerError(fmt.Errorf("Failed to get cloudAccount"), "", "") - } - tksCloudAccountId := cluster.CloudAccountId.String() - if strings.Contains(cloudAccount.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { - tksCloudAccountId = "NULL" + tksCloudAccountId := "NULL" + if cluster.CloudService != domain.CloudService_BYOH { + cloudAccount, err := u.cloudAccountRepo.Get(cluster.CloudAccountId) + if err != nil { + return httpErrors.NewInternalServerError(fmt.Errorf("Failed to get cloudAccount"), "", "") + } + tksCloudAccountId = cluster.CloudAccountId.String() + if strings.Contains(cloudAccount.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { + tksCloudAccountId = "NULL" + } } workflowId, err := u.argo.SumbitWorkflowFromWftpl( @@ -248,9 +357,11 @@ func (u *ClusterUsecase) Delete(ctx context.Context, clusterId domain.ClusterId) argowf.SubmitOptions{ Parameters: []string{ "app_group=tks-cluster-aws", - "tks_info_host=http://tks-api.tks.svc:9110", + "tks_api_url=http://tks-api.tks.svc:9110", "cluster_id=" + clusterId.String(), "cloud_account_id=" + tksCloudAccountId, + "keycloak_url=" + viper.GetString("keycloak-address"), + "contract_id=" + cluster.OrganizationId, }, }) if err != nil { @@ -268,17 +379,21 @@ func (u *ClusterUsecase) Delete(ctx context.Context, clusterId domain.ClusterId) } func (u *ClusterUsecase) GetClusterSiteValues(ctx context.Context, clusterId domain.ClusterId) (out domain.ClusterSiteValuesResponse, err error) { - cluster, err := u.Get(ctx, clusterId) + cluster, err := u.repo.Get(clusterId) if err != nil { return domain.ClusterSiteValuesResponse{}, errors.Wrap(err, "Failed to get cluster") } out.SshKeyName = "tks-seoul" out.ClusterRegion = "ap-northeast-2" - out.CpReplicas = cluster.Conf.CpNodeCnt - out.CpNodeMachineType = cluster.Conf.CpNodeMachineType - out.MpReplicas = cluster.Conf.TksNodeCnt - out.MpNodeMachineType = cluster.Conf.TksNodeMachineType + + if err := serializer.Map(cluster.Conf, &out); err != nil { + log.ErrorWithContext(ctx, err) + } + + if err := serializer.Map(cluster, &out); err != nil { + log.ErrorWithContext(ctx, err) + } /* // 기능 변경 : 20230614 : machine deployment 사용하지 않음. 단, aws-standard 는 사용할 여지가 있으므로 주석처리해둔다. @@ -293,11 +408,299 @@ func (u *ClusterUsecase) GetClusterSiteValues(ctx context.Context, clusterId dom out.MdMaxSizePerAz = cluster.Conf.UserNodeCnt * 5 } */ + return +} + +func (u *ClusterUsecase) CreateBootstrapKubeconfig(ctx context.Context, clusterId domain.ClusterId) (out domain.BootstrapKubeconfig, err error) { + _, err = u.repo.Get(clusterId) + if err != nil { + return out, httpErrors.NewNotFoundError(err, "", "") + } + + workflow := "create-byoh-bootstrapkubeconfig" + workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflow, argowf.SubmitOptions{ + Parameters: []string{ + fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), + "cluster_id=" + clusterId.String(), + }, + }) + if err != nil { + log.ErrorWithContext(ctx, err) + return out, httpErrors.NewInternalServerError(err, "S_FAILED_TO_CALL_WORKFLOW", "") + } + log.DebugWithContext(ctx, "Submitted workflow: ", workflowId) + + // wait & get clusterId ( max 1min ) + for i := 0; i < 60; i++ { + time.Sleep(time.Second * 3) + workflow, err := u.argo.GetWorkflow("argo", workflowId) + if err != nil { + return out, err + } + + log.DebugWithContext(ctx, "workflow ", workflow) + + if workflow.Status.Phase == "Succeeded" { + break + } + if workflow.Status.Phase != "" && workflow.Status.Phase != "Running" { + return out, fmt.Errorf("Invalid workflow status [%s]", workflow.Status.Phase) + } + } + + out, err = u.GetBootstrapKubeconfig(ctx, clusterId) + if err != nil { + return out, err + } + + return out, nil +} + +func (u *ClusterUsecase) GetBootstrapKubeconfig(ctx context.Context, clusterId domain.ClusterId) (out domain.BootstrapKubeconfig, err error) { + cluster, err := u.repo.Get(clusterId) + if err != nil { + return out, httpErrors.NewNotFoundError(err, "", "") + } + client, err := kubernetes.GetClientAdminCluster() + if err != nil { + return out, err + } + + kubeconfig := byoh.BootstrapKubeconfig{} + data, err := client.RESTClient(). + Get(). + AbsPath("/apis/infrastructure.cluster.x-k8s.io/v1beta1"). + Namespace("default"). + Name("bootstrap-kubeconfig-" + cluster.ID.String()). + Resource("bootstrapkubeconfigs"). + DoRaw(ctx) + if err != nil { + return out, err + } + + if err := json.Unmarshal(data, &kubeconfig); err != nil { + return out, err + } + + log.DebugWithContext(ctx, helper.ModelToJson(kubeconfig.Status.BootstrapKubeconfigData)) + + type BootstrapKubeconfigUser struct { + Users []struct { + Name string `yaml:"name"` + User struct { + Token string `yaml:"token"` + } `yaml:"user"` + } `yaml:"users"` + } + bytes := []byte(string(*kubeconfig.Status.BootstrapKubeconfigData)) + + kubeconfigData := BootstrapKubeconfigUser{} + err = yaml.Unmarshal(bytes, &kubeconfigData) + if err != nil { + return out, err + } + + token := kubeconfigData.Users[0].User.Token[:6] + log.InfoWithContext(ctx, "token : ", token) + + secrets, err := client.CoreV1().Secrets("kube-system").Get(context.TODO(), "bootstrap-token-"+token, metav1.GetOptions{}) + if err != nil { + log.ErrorWithContext(ctx, err) + return out, err + } + + log.Info(secrets.Data["expiration"][:]) + + // 2023-10-17T11:05:33Z + now := time.Now() + expiration, err := time.Parse(time.RFC3339, string(secrets.Data["expiration"][:])) + if err != nil { + return out, err + } + + period, err := time.ParseDuration(expiration.Sub(now).String()) + if err != nil { + return out, err + } + out.Expiration = int(period.Seconds()) + + return out, nil +} + +func (u *ClusterUsecase) GetNodes(ctx context.Context, clusterId domain.ClusterId) (out []domain.ClusterNode, err error) { + cluster, err := u.repo.Get(clusterId) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return out, httpErrors.NewNotFoundError(err, "S_FAILED_FETCH_CLUSTER", "") + } + return out, err + } + if cluster.CloudService != domain.CloudService_BYOH { + return out, httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloud service"), "", "") + } + + client, err := kubernetes.GetClientAdminCluster() + if err != nil { + return out, err + } + + hosts := byoh.ByoHostList{} + data, err := client.RESTClient(). + Get(). + AbsPath("/apis/infrastructure.cluster.x-k8s.io/v1beta1"). + Namespace("default"). + //Namespace(cluster.ID). [TODO] + Resource("byohosts"). + DoRaw(ctx) + if err != nil { + return out, err + } + + if err = json.Unmarshal(data, &hosts); err != nil { + return out, err + } + + /* FOR DEBUG + for _, host := range hosts.Items { + log.Info(host.Name) + log.Info(host.Labels) + log.Info(host.Status.Conditions[0].Type) + } + */ + + clusterNodeStatus := func(targeted int, registered int) string { + if targeted <= registered { + return "COMPLETED" + } + return "INPROGRESS" + } - out.MdMachineType = cluster.Conf.UserNodeMachineType - out.MdNumOfAz = cluster.Conf.UserNodeCnt - out.MdMinSizePerAz = 1 - out.MdMaxSizePerAz = cluster.Conf.UserNodeCnt + tksCpNodeRegistered, tksCpNodeRegistering, tksCpHosts := 0, 0, make([]domain.ClusterHost, 0) + tksInfraNodeRegistered, tksInfraNodeRegistering, tksInfraHosts := 0, 0, make([]domain.ClusterHost, 0) + tksUserNodeRegistered, tksUserNodeRegistering, tksUserHosts := 0, 0, make([]domain.ClusterHost, 0) + for _, host := range hosts.Items { + label := host.Labels["role"] + arr := strings.Split(host.Labels["role"], "-") + if len(arr) < 2 { + continue + } + clusterId := arr[0] + role := label[10:] + if label[9] != '-' || clusterId != string(cluster.ID) { + continue + } + /* + if host.Name == "ip-10-0-12-87.ap-northeast-2.compute.internal" { + continue + } + + role := host.Labels["role"] // [FOR TEST] + */ + + hostStatus := host.Status.Conditions[0].Type + registered, registering := 0, 0 + // K8sComponentsInstallationSucceeded + if hostStatus == "K8sNodeBootstrapSucceeded" || hostStatus == "K8sComponentsInstallationSucceeded" { + registered = 1 + } else { + registering = 1 + } + + log.Info(role) + + switch role { + case "control-plane": + tksCpNodeRegistered = tksCpNodeRegistered + registered + tksCpNodeRegistering = tksCpNodeRegistering + registering + tksCpHosts = append(tksCpHosts, domain.ClusterHost{Name: host.Name, Status: string(hostStatus)}) + case "tks": + tksInfraNodeRegistered = tksInfraNodeRegistered + registered + tksInfraNodeRegistering = tksInfraNodeRegistering + registering + tksInfraHosts = append(tksInfraHosts, domain.ClusterHost{Name: host.Name, Status: string(hostStatus)}) + case "worker": + tksUserNodeRegistered = tksUserNodeRegistered + registered + tksUserNodeRegistering = tksUserNodeRegistering + registering + tksUserHosts = append(tksUserHosts, domain.ClusterHost{Name: host.Name, Status: string(hostStatus)}) + } + } + + bootstrapKubeconfig, err := u.GetBootstrapKubeconfig(ctx, cluster.ID) + if err != nil { + return out, err + } + + command := fmt.Sprintf("curl -fL %s/api/packages/%s/generic/byoh_hostagent_install/%s/byoh_hostagent-install-%s.sh | sh -s -- --role %s-", + viper.GetString("external-gitea-url"), + viper.GetString("git-account"), + string(cluster.ID), + string(cluster.ID), + string(cluster.ID)) + + out = []domain.ClusterNode{ + { + Type: "TKS_CP_NODE", + Targeted: cluster.Conf.TksCpNode, + Registered: tksCpNodeRegistered, + Registering: tksCpNodeRegistering, + Status: clusterNodeStatus(cluster.Conf.TksCpNode, tksCpNodeRegistered), + Command: command + "control-plane", + Validity: bootstrapKubeconfig.Expiration, + Hosts: tksCpHosts, + }, + { + Type: "TKS_INFRA_NODE", + Targeted: cluster.Conf.TksInfraNode, + Registered: tksInfraNodeRegistered, + Registering: tksInfraNodeRegistering, + Status: clusterNodeStatus(cluster.Conf.TksInfraNode, tksInfraNodeRegistered), + Command: command + "tks", + Validity: bootstrapKubeconfig.Expiration, + Hosts: tksInfraHosts, + }, + { + Type: "TKS_USER_NODE", + Targeted: cluster.Conf.TksUserNode, + Registered: tksUserNodeRegistered, + Registering: tksUserNodeRegistering, + Status: clusterNodeStatus(cluster.Conf.TksUserNode, tksUserNodeRegistered), + Command: command + "worker", + Validity: bootstrapKubeconfig.Expiration, + Hosts: tksUserHosts, + }, + } + + // [TODO] for integration + /* + out.Nodes = []domain.StackNodeResponse{ + { + ID: "1", + Type: "TKS_CP_NODE", + Targeted: 3, + Registered: 1, + Status: "INPROGRESS", + Command: "curl -fL http://192.168.0.77/tks-byoh-hostagent-install.sh | sh -s CLUSTER-ID-control-plane", + Validity: 3000, + }, + { + ID: "2", + Type: "TKS_INFRA_NODE", + Targeted: 0, + Registered: 0, + Status: "PENDING", + Command: "curl -fL http://192.168.0.77/tks-byoh-hostagent-install.sh | sh -s CLUSTER-ID-control-plane", + Validity: 3000, + }, + { + ID: "3", + Type: "TKS_USER_NODE", + Targeted: 3, + Registered: 3, + Status: "COMPLETED", + Command: "curl -fL http://192.168.0.77/tks-byoh-hostagent-install.sh | sh -s CLUSTER-ID-control-plane", + Validity: 3000, + }, + } + */ return } diff --git a/internal/usecase/dashboard.go b/internal/usecase/dashboard.go index aa25da53..18ceda50 100644 --- a/internal/usecase/dashboard.go +++ b/internal/usecase/dashboard.go @@ -8,9 +8,11 @@ import ( "strconv" "time" + "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/repository" + "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" "github.com/openinfradev/tks-api/pkg/log" @@ -70,7 +72,7 @@ func (u *DashboardUsecase) GetCharts(ctx context.Context, organizationId string, } func (u *DashboardUsecase) GetStacks(ctx context.Context, organizationId string) (out []domain.DashboardStack, err error) { - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, uuid.Nil, nil) if err != nil { return out, err } @@ -102,7 +104,7 @@ func (u *DashboardUsecase) GetStacks(ctx context.Context, organizationId string) } stack := reflectClusterToStack(cluster, appGroups) dashboardStack := domain.DashboardStack{} - if err := domain.Map(stack, &dashboardStack); err != nil { + if err := serializer.Map(stack, &dashboardStack); err != nil { log.InfoWithContext(ctx, err) } @@ -110,13 +112,13 @@ func (u *DashboardUsecase) GetStacks(ctx context.Context, organizationId string) cpu := u.getStackCpu(stackCpu.Data.Result, cluster.ID.String()) if cpu != "" { - cpu = cpu + " %" + cpu = cpu + "%" } if memory != "" { - memory = memory + " %" + memory = memory + "%" } if disk != "" { - disk = disk + " %" + disk = disk + "%" } dashboardStack.Cpu = cpu @@ -146,7 +148,7 @@ func (u *DashboardUsecase) GetResources(ctx context.Context, organizationId stri } // Stack - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, uuid.Nil, nil) if err != nil { return out, err } @@ -416,28 +418,46 @@ func (u *DashboardUsecase) getThanosUrl(organizationId string) (out string, err return out, fmt.Errorf("Invalid primary clusterId") } - clientset_user, err := kubernetes.GetClientFromClusterId(organization.PrimaryClusterId) + clientset_admin, err := kubernetes.GetClientAdminCluster() if err != nil { return out, errors.Wrap(err, "Failed to get client set for user cluster") } - service, err := clientset_user.CoreV1().Services("lma").Get(context.TODO(), "thanos-query-frontend", metav1.GetOptions{}) + + // tks-endpoint-secret 이 있다면 그 secret 내의 endpoint 를 사용한다. + secrets, err := clientset_admin.CoreV1().Secrets(organization.PrimaryClusterId).Get(context.TODO(), "tks-endpoint-secret", metav1.GetOptions{}) if err != nil { - service, err = clientset_user.CoreV1().Services("lma").Get(context.TODO(), "thanos-query", metav1.GetOptions{}) + log.Info("cannot found tks-endpoint-secret. so use LoadBalancer...") + + clientset_user, err := kubernetes.GetClientFromClusterId(organization.PrimaryClusterId) if err != nil { - return out, errors.Wrap(err, "Failed to get services.") + return out, errors.Wrap(err, "Failed to get client set for user cluster") } - } - // LoadBalaner 일경우, aws address 형태의 경우만 가정한다. - if service.Spec.Type != "LoadBalancer" { - return out, fmt.Errorf("Service type is not LoadBalancer. [%s] ", service.Spec.Type) - } + service, err := clientset_user.CoreV1().Services("lma").Get(context.TODO(), "thanos-query-frontend", metav1.GetOptions{}) + if err != nil { + service, err = clientset_user.CoreV1().Services("lma").Get(context.TODO(), "thanos-query", metav1.GetOptions{}) + if err != nil { + return out, errors.Wrap(err, "Failed to get services.") + } + } + + // LoadBalaner 일경우, aws address 형태의 경우만 가정한다. + if service.Spec.Type != "LoadBalancer" { + return out, fmt.Errorf("Service type is not LoadBalancer. [%s] ", service.Spec.Type) + } - lbs := service.Status.LoadBalancer.Ingress - ports := service.Spec.Ports - if len(lbs) > 0 && len(ports) > 0 { - out = ports[0].TargetPort.StrVal + "://" + lbs[0].Hostname + ":" + strconv.Itoa(int(ports[0].Port)) + lbs := service.Status.LoadBalancer.Ingress + ports := service.Spec.Ports + if len(lbs) > 0 && len(ports) > 0 { + out = ports[0].TargetPort.StrVal + "://" + lbs[0].Hostname + ":" + strconv.Itoa(int(ports[0].Port)) + u.cache.Set(prefix+organizationId, out, gcache.DefaultExpiration) + return out, nil + } + } else { + out = "http://" + string(secrets.Data["thanos"]) + log.Info("thanosUrl : ", out) u.cache.Set(prefix+organizationId, out, gcache.DefaultExpiration) + return out, nil } return diff --git a/internal/usecase/stack.go b/internal/usecase/stack.go index 2182a658..328042eb 100644 --- a/internal/usecase/stack.go +++ b/internal/usecase/stack.go @@ -3,24 +3,17 @@ package usecase import ( "context" "fmt" + "sort" "strings" "time" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/credentials" - "github.com/aws/aws-sdk-go-v2/credentials/stscreds" - "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/aws/aws-sdk-go-v2/service/eks" - "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" - "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - "github.com/aws/aws-sdk-go-v2/service/servicequotas" - "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/kubernetes" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" + "github.com/openinfradev/tks-api/internal/serializer" argowf "github.com/openinfradev/tks-api/pkg/argo-client" "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" @@ -35,10 +28,13 @@ type IStackUsecase interface { GetByName(ctx context.Context, organizationId string, name string) (domain.Stack, error) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) ([]domain.Stack, error) Create(ctx context.Context, dto domain.Stack) (stackId domain.StackId, err error) + Install(ctx context.Context, stackId domain.StackId) (err error) Update(ctx context.Context, dto domain.Stack) error Delete(ctx context.Context, dto domain.Stack) error GetKubeConfig(ctx context.Context, stackId domain.StackId) (kubeConfig string, err error) GetStepStatus(ctx context.Context, stackId domain.StackId) (out []domain.StackStepStatus, stackStatus string, err error) + SetFavorite(ctx context.Context, stackId domain.StackId) error + DeleteFavorite(ctx context.Context, stackId domain.StackId) error } type StackUsecase struct { @@ -49,9 +45,10 @@ type StackUsecase struct { stackTemplateRepo repository.IStackTemplateRepository appServeAppRepo repository.IAppServeAppRepository argo argowf.ArgoClient + dashbordUsecase IDashboardUsecase } -func NewStackUsecase(r repository.Repository, argoClient argowf.ArgoClient) IStackUsecase { +func NewStackUsecase(r repository.Repository, argoClient argowf.ArgoClient, dashbordUsecase IDashboardUsecase) IStackUsecase { return &StackUsecase{ clusterRepo: r.Cluster, appGroupRepo: r.AppGroup, @@ -60,6 +57,7 @@ func NewStackUsecase(r repository.Repository, argoClient argowf.ArgoClient) ISta stackTemplateRepo: r.StackTemplate, appServeAppRepo: r.AppServeApp, argo: argoClient, + dashbordUsecase: dashbordUsecase, } } @@ -74,17 +72,12 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do return "", httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "S_CREATE_ALREADY_EXISTED_NAME", "") } - stackTemplate, err := u.stackTemplateRepo.Get(dto.StackTemplateId) + _, err = u.stackTemplateRepo.Get(dto.StackTemplateId) if err != nil { return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid stackTemplateId"), "S_INVALID_STACK_TEMPLATE", "") } - cloudAccount, err := u.cloudAccountRepo.Get(dto.CloudAccountId) - if err != nil { - return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid cloudAccountId"), "S_INVALID_CLOUD_ACCOUNT", "") - } - - clusters, err := u.clusterRepo.FetchByOrganizationId(dto.OrganizationId, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(dto.OrganizationId, user.GetUserId(), nil) if err != nil { return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Failed to get clusters"), "S_FAILED_GET_CLUSTERS", "") } @@ -94,26 +87,27 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do } log.DebugWithContext(ctx, "isPrimary ", isPrimary) - workflow := "" - if strings.Contains(stackTemplate.Template, "aws-reference") || strings.Contains(stackTemplate.Template, "eks-reference") { - workflow = "tks-stack-create-aws" - } else if strings.Contains(stackTemplate.Template, "aws-msa-reference") || strings.Contains(stackTemplate.Template, "eks-msa-reference") { - workflow = "tks-stack-create-aws-msa" + if dto.CloudService == domain.CloudService_BYOH { + if dto.ClusterEndpoint == "" { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterEndpoint"), "S_INVALID_ADMINCLUSTER_URL", "") + } + arr := strings.Split(dto.ClusterEndpoint, ":") + if len(arr) != 2 { + return "", httpErrors.NewBadRequestError(fmt.Errorf("Invalid clusterEndpoint"), "S_INVALID_ADMINCLUSTER_URL", "") + } } else { - log.ErrorWithContext(ctx, "Invalid template : ", stackTemplate.Template) - return "", httpErrors.NewInternalServerError(fmt.Errorf("Invalid stackTemplate. %s", stackTemplate.Template), "", "") + if _, err = u.cloudAccountRepo.Get(dto.CloudAccountId); err != nil { + return "", httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid cloudAccountId"), "S_INVALID_CLOUD_ACCOUNT", "") + } } + // Make stack nodes var stackConf domain.StackConfResponse if err = domain.Map(dto.Conf, &stackConf); err != nil { log.InfoWithContext(ctx, err) } - // Check service quota - if err = u.checkAwsResourceQuota(ctx, cloudAccount); err != nil { - return "", err - } - + workflow := "tks-stack-create" workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflow, argowf.SubmitOptions{ Parameters: []string{ fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), @@ -125,6 +119,8 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do "creator=" + user.GetUserId().String(), "base_repo_branch=" + viper.GetString("revision"), "infra_conf=" + strings.Replace(helper.ModelToJson(stackConf), "\"", "\\\"", -1), + "cloud_service=" + dto.CloudService, + "cluster_endpoint=" + dto.ClusterEndpoint, }, }) if err != nil { @@ -160,165 +156,55 @@ func (u *StackUsecase) Create(ctx context.Context, dto domain.Stack) (stackId do return dto.ID, nil } -func (u *StackUsecase) checkAwsResourceQuota(ctx context.Context, cloudAccount domain.CloudAccount) (err error) { - awsAccessKeyId, awsSecretAccessKey, _ := kubernetes.GetAwsSecret() - if err != nil || awsAccessKeyId == "" || awsSecretAccessKey == "" { - log.ErrorWithContext(ctx, err) - return httpErrors.NewInternalServerError(fmt.Errorf("Invalid aws secret."), "", "") - } - - cfg, err := config.LoadDefaultConfig(ctx, - config.WithCredentialsProvider(credentials.StaticCredentialsProvider{ - Value: aws.Credentials{ - AccessKeyID: awsAccessKeyId, SecretAccessKey: awsSecretAccessKey, - }, - })) +func (u *StackUsecase) Install(ctx context.Context, stackId domain.StackId) (err error) { + cluster, err := u.Get(ctx, stackId) if err != nil { - log.ErrorWithContext(ctx, err) - } - - stsSvc := sts.NewFromConfig(cfg) - - if !strings.Contains(cloudAccount.Name, domain.CLOUD_ACCOUNT_INCLUSTER) { - log.InfoWithContext(ctx, "Use assume role. awsAccountId : ", cloudAccount.AwsAccountId) - creds := stscreds.NewAssumeRoleProvider(stsSvc, "arn:aws:iam::"+cloudAccount.AwsAccountId+":role/controllers.cluster-api-provider-aws.sigs.k8s.io") - cfg.Credentials = aws.NewCredentialsCache(creds) + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid stackId"), "S_INVALID_STACK_ID", "") } - client := servicequotas.NewFromConfig(cfg) - quotaMap := map[string]string{ - "L-69A177A2": "elasticloadbalancing", // NLB - "L-E9E9831D": "elasticloadbalancing", // Classic - "L-A4707A72": "vpc", // IGW - "L-1194D53C": "eks", // Cluster - "L-0263D0A3": "ec2", // Elastic IP - } - - // current usage - type CurrentUsage struct { - NLB int - CLB int - IGW int - Cluster int - EIP int - } - - // get current usage - currentUsage := CurrentUsage{} - { - c := elasticloadbalancingv2.NewFromConfig(cfg) - pageSize := int32(100) - res, err := c.DescribeLoadBalancers(ctx, &elasticloadbalancingv2.DescribeLoadBalancersInput{ - PageSize: &pageSize, - }, func(o *elasticloadbalancingv2.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - return err - } - - for _, elb := range res.LoadBalancers { - switch elb.Type { - case "network": - currentUsage.NLB += 1 - } - } + _, err = u.stackTemplateRepo.Get(cluster.StackTemplateId) + if err != nil { + return httpErrors.NewInternalServerError(errors.Wrap(err, "Invalid stackTemplateId"), "S_INVALID_STACK_TEMPLATE", "") } - { - c := elasticloadbalancing.NewFromConfig(cfg) - pageSize := int32(100) - res, err := c.DescribeLoadBalancers(ctx, &elasticloadbalancing.DescribeLoadBalancersInput{ - PageSize: &pageSize, - }, func(o *elasticloadbalancing.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - return err - } - currentUsage.CLB = len(res.LoadBalancerDescriptions) + clusters, err := u.clusterRepo.FetchByOrganizationId(cluster.OrganizationId, uuid.Nil, nil) + if err != nil { + return httpErrors.NewInternalServerError(errors.Wrap(err, "Failed to get clusters"), "S_FAILED_GET_CLUSTERS", "") } - - { - c := ec2.NewFromConfig(cfg) - res, err := c.DescribeInternetGateways(ctx, &ec2.DescribeInternetGatewaysInput{}, func(o *ec2.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - return err - } - currentUsage.IGW = len(res.InternetGateways) + isPrimary := false + if len(clusters) == 0 { + isPrimary = true } + log.DebugWithContext(ctx, "isPrimary ", isPrimary) - { - c := eks.NewFromConfig(cfg) - res, err := c.ListClusters(ctx, &eks.ListClustersInput{}, func(o *eks.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - return err - } - currentUsage.Cluster = len(res.Clusters) + if cluster.CloudService != domain.CloudService_BYOH { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid cloud service"), "S_INVALID_CLOUD_SERVICE", "") } - { - c := ec2.NewFromConfig(cfg) - res, err := c.DescribeAddresses(ctx, &ec2.DescribeAddressesInput{}, func(o *ec2.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - log.ErrorWithContext(ctx, err) - return err - } - currentUsage.EIP = len(res.Addresses) + // Make stack nodes + var stackConf domain.StackConfResponse + if err = domain.Map(cluster.Conf, &stackConf); err != nil { + log.InfoWithContext(ctx, err) } - for key, val := range quotaMap { - res, err := getServiceQuota(client, key, val) - if err != nil { - return err - } - log.DebugfWithContext(ctx, "%s %s %v", *res.Quota.QuotaName, *res.Quota.QuotaCode, *res.Quota.Value) - - quotaValue := int(*res.Quota.Value) - - // stack 1개 생성하는데 필요한 quota - // Classic 1 - // Network 5 - // IGW 1 - // EIP 3 - // Cluster 1 - switch key { - case "L-69A177A2": // NLB - log.InfofWithContext(ctx, "NLB : usage %d, quota %d", currentUsage.NLB, quotaValue) - if quotaValue < currentUsage.NLB+5 { - return httpErrors.NewInternalServerError(fmt.Errorf("Not enough quota (NLB). current[%d], quota[%d]", currentUsage.NLB, quotaValue), "S_NOT_ENOUGH_QUOTA", "") - } - case "L-E9E9831D": // Classic - log.InfofWithContext(ctx, "CLB : usage %d, quota %d", currentUsage.CLB, quotaValue) - if quotaValue < currentUsage.CLB+1 { - return httpErrors.NewInternalServerError(fmt.Errorf("Not enough quota (Classic ELB). current[%d], quota[%d]", currentUsage.CLB, quotaValue), "S_NOT_ENOUGH_QUOTA", "") - } - case "L-A4707A72": // IGW - log.InfofWithContext(ctx, "IGW : usage %d, quota %d", currentUsage.IGW, quotaValue) - if quotaValue < currentUsage.IGW+1 { - return httpErrors.NewInternalServerError(fmt.Errorf("Not enough quota (Internet Gateway). current[%d], quota[%d]", currentUsage.IGW, quotaValue), "S_NOT_ENOUGH_QUOTA", "") - } - case "L-1194D53C": // Cluster - log.InfofWithContext(ctx, "Cluster : usage %d, quota %d", currentUsage.Cluster, quotaValue) - if quotaValue < currentUsage.Cluster+1 { - return httpErrors.NewInternalServerError(fmt.Errorf("Not enough quota (EKS cluster quota). current[%d], quota[%d]", currentUsage.Cluster, quotaValue), "S_NOT_ENOUGH_QUOTA", "") - } - case "L-0263D0A3": // Elastic IP - log.InfofWithContext(ctx, "Elastic IP : usage %d, quota %d", currentUsage.EIP, quotaValue) - if quotaValue < currentUsage.EIP+3 { - return httpErrors.NewInternalServerError(fmt.Errorf("Not enough quota (Elastic IP). current[%d], quota[%d]", currentUsage.EIP, quotaValue), "S_NOT_ENOUGH_QUOTA", "") - } - } - + workflow := "tks-stack-install" + workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflow, argowf.SubmitOptions{ + Parameters: []string{ + fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), + "cluster_id=" + cluster.ID.String(), + "description=" + cluster.Description, + "organization_id=" + cluster.OrganizationId, + "stack_template_id=" + cluster.StackTemplateId.String(), + "creator=" + (*cluster.CreatorId).String(), + "base_repo_branch=" + viper.GetString("revision"), + }, + }) + if err != nil { + log.ErrorWithContext(ctx, err) + return httpErrors.NewInternalServerError(err, "S_FAILED_TO_CALL_WORKFLOW", "") } + log.DebugWithContext(ctx, "Submitted workflow: ", workflowId) - //return fmt.Errorf("Always return err") return nil } @@ -333,7 +219,7 @@ func (u *StackUsecase) Get(ctx context.Context, stackId domain.StackId) (out dom organization, err := u.organizationRepo.Get(cluster.OrganizationId) if err != nil { - return out, httpErrors.NewInternalServerError(errors.Wrap(err, fmt.Sprintf("Failed to get organization for clusterId %s", cluster.OrganizationId)), "S_FAILED_FETCH_ORGANIZATION", "") + return out, httpErrors.NewInternalServerError(errors.Wrap(err, fmt.Sprintf("Failed to get organization for clusterId %s", domain.ClusterId(stackId))), "S_FAILED_FETCH_ORGANIZATION", "") } appGroups, err := u.appGroupRepo.Fetch(domain.ClusterId(stackId), nil) @@ -385,16 +271,23 @@ func (u *StackUsecase) GetByName(ctx context.Context, organizationId string, nam } func (u *StackUsecase) Fetch(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []domain.Stack, err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return out, httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "") + } + organization, err := u.organizationRepo.Get(organizationId) if err != nil { return out, httpErrors.NewInternalServerError(errors.Wrap(err, fmt.Sprintf("Failed to get organization for clusterId %s", organizationId)), "S_FAILED_FETCH_ORGANIZATION", "") } - clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, pg) + clusters, err := u.clusterRepo.FetchByOrganizationId(organizationId, user.GetUserId(), pg) if err != nil { return out, err } + stackResources, _ := u.dashbordUsecase.GetStacks(ctx, organizationId) + for _, cluster := range clusters { appGroups, err := u.appGroupRepo.Fetch(cluster.ID, nil) if err != nil { @@ -417,9 +310,22 @@ func (u *StackUsecase) Fetch(ctx context.Context, organizationId string, pg *pag } } } + + for _, resource := range stackResources { + if resource.ID == domain.StackId(cluster.ID) { + if err := serializer.Map(resource, &outStack.Resource); err != nil { + log.Error(err) + } + } + } + out = append(out, outStack) } + sort.Slice(out, func(i, j int) bool { + return string(out[i].ID) == organization.PrimaryClusterId + }) + return } @@ -450,6 +356,11 @@ func (u *StackUsecase) Update(ctx context.Context, dto domain.Stack) (err error) } func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewBadRequestError(fmt.Errorf("Invalid token"), "", "") + } + cluster, err := u.clusterRepo.Get(domain.ClusterId(dto.ID)) if err != nil { return httpErrors.NewBadRequestError(errors.Wrap(err, "Failed to get cluster"), "S_FAILED_FETCH_CLUSTER", "") @@ -464,7 +375,7 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) for _, organization := range *organizations { if organization.PrimaryClusterId == cluster.ID.String() { - clusters, err := u.clusterRepo.FetchByOrganizationId(organization.ID, nil) + clusters, err := u.clusterRepo.FetchByOrganizationId(organization.ID, user.GetUserId(), nil) if err != nil { return errors.Wrap(err, "Failed to get organizations") } @@ -499,22 +410,16 @@ func (u *StackUsecase) Delete(ctx context.Context, dto domain.Stack) (err error) return httpErrors.NewBadRequestError(fmt.Errorf("existed appServeApps in %s", dto.OrganizationId), "S_FAILED_DELETE_EXISTED_ASA", "") } - workflow := "" - if strings.Contains(cluster.StackTemplate.Template, "aws-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-reference") { - workflow = "tks-stack-delete-aws" - } else if strings.Contains(cluster.StackTemplate.Template, "aws-msa-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-msa-reference") { - workflow = "tks-stack-delete-aws-msa" - } else { - log.ErrorWithContext(ctx, "Invalid template : ", cluster.StackTemplate.Template) - return httpErrors.NewInternalServerError(fmt.Errorf("Invalid stack-template %s", cluster.StackTemplate.Template), "", "") - } + // [TODO] BYOH 삭제는 어떻게 처리하는게 좋은가? + workflow := "tks-stack-delete" workflowId, err := u.argo.SumbitWorkflowFromWftpl(workflow, argowf.SubmitOptions{ Parameters: []string{ fmt.Sprintf("tks_api_url=%s", viper.GetString("external-address")), "organization_id=" + dto.OrganizationId, "cluster_id=" + dto.ID.String(), "cloud_account_id=" + cluster.CloudAccount.ID.String(), + "stack_template_id=" + cluster.StackTemplate.ID.String(), }, }) if err != nil { @@ -588,7 +493,7 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId out = append(out, clusterStepStatus) // make default appgroup status - if strings.Contains(cluster.StackTemplate.Template, "aws-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-reference") { + if cluster.StackTemplate.TemplateType == "STANDARD" { // LMA out = append(out, domain.StackStepStatus{ Status: domain.AppGroupStatus_PENDING.String(), @@ -596,7 +501,7 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId Step: 0, MaxStep: domain.MAX_STEP_LMA_CREATE_MEMBER, }) - } else if strings.Contains(cluster.StackTemplate.Template, "aws-msa-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-msa-reference") { + } else { // LMA + SERVICE_MESH out = append(out, domain.StackStepStatus{ Status: domain.AppGroupStatus_PENDING.String(), @@ -661,31 +566,77 @@ func (u *StackUsecase) GetStepStatus(ctx context.Context, stackId domain.StackId return } -func reflectClusterToStack(cluster domain.Cluster, appGroups []domain.AppGroup) domain.Stack { - status, statusDesc := getStackStatus(cluster, appGroups) - return domain.Stack{ - ID: domain.StackId(cluster.ID), - OrganizationId: cluster.OrganizationId, - Name: cluster.Name, - Description: cluster.Description, - Status: status, - StatusDesc: statusDesc, - CloudAccountId: cluster.CloudAccountId, - CloudAccount: cluster.CloudAccount, - StackTemplateId: cluster.StackTemplateId, - StackTemplate: cluster.StackTemplate, - CreatorId: cluster.CreatorId, - Creator: cluster.Creator, - UpdatorId: cluster.UpdatorId, - Updator: cluster.Updator, - CreatedAt: cluster.CreatedAt, - UpdatedAt: cluster.UpdatedAt, - Conf: domain.StackConf{ - CpNodeCnt: cluster.Conf.CpNodeCnt, - TksNodeCnt: cluster.Conf.TksNodeCnt, - UserNodeCnt: cluster.Conf.UserNodeCnt, - }, +func (u *StackUsecase) SetFavorite(ctx context.Context, stackId domain.StackId) error { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "") } + + err := u.clusterRepo.SetFavorite(domain.ClusterId(stackId), user.GetUserId()) + if err != nil { + return err + } + + return nil +} + +func (u *StackUsecase) DeleteFavorite(ctx context.Context, stackId domain.StackId) error { + user, ok := request.UserFrom(ctx) + if !ok { + return httpErrors.NewUnauthorizedError(fmt.Errorf("Invalid token"), "A_INVALID_TOKEN", "") + } + + err := u.clusterRepo.DeleteFavorite(domain.ClusterId(stackId), user.GetUserId()) + if err != nil { + return err + } + + return nil +} + +func reflectClusterToStack(cluster domain.Cluster, appGroups []domain.AppGroup) (out domain.Stack) { + if err := serializer.Map(cluster, &out); err != nil { + log.Error(err) + } + + status, statusDesc := getStackStatus(cluster, appGroups) + + out.ID = domain.StackId(cluster.ID) + out.Status = status + out.StatusDesc = statusDesc + + /* + return domain.Stack{ + ID: domain.StackId(cluster.ID), + OrganizationId: cluster.OrganizationId, + Name: cluster.Name, + Description: cluster.Description, + Status: status, + StatusDesc: statusDesc, + CloudAccountId: cluster.CloudAccountId, + CloudAccount: cluster.CloudAccount, + StackTemplateId: cluster.StackTemplateId, + StackTemplate: cluster.StackTemplate, + CreatorId: cluster.CreatorId, + Creator: cluster.Creator, + UpdatorId: cluster.UpdatorId, + Updator: cluster.Updator, + CreatedAt: cluster.CreatedAt, + UpdatedAt: cluster.UpdatedAt, + Conf: domain.StackConf{ + TksCpNode: cluster.Conf.TksCpNode, + TksCpNodeMax: cluster.Conf.TksCpNodeMax, + TksCpNodeType: cluster.Conf.TksCpNodeType, + TksInfraNode: cluster.Conf.TksInfraNode, + TksInfraNodeMax: cluster.Conf.TksInfraNodeMax, + TksInfraNodeType: cluster.Conf.TksInfraNodeType, + TksUserNode: cluster.Conf.TksUserNode, + TksUserNodeMax: cluster.Conf.TksUserNodeMax, + TksUserNodeType: cluster.Conf.TksUserNodeType, + }, + } + */ + return } // [TODO] more pretty @@ -708,6 +659,12 @@ func getStackStatus(cluster domain.Cluster, appGroups []domain.AppGroup) (domain } } + if cluster.Status == domain.ClusterStatus_BOOTSTRAPPING { + return domain.StackStatus_CLUSTER_BOOTSTRAPPING, cluster.StatusDesc + } + if cluster.Status == domain.ClusterStatus_BOOTSTRAPPED { + return domain.StackStatus_CLUSTER_BOOTSTRAPPED, cluster.StatusDesc + } if cluster.Status == domain.ClusterStatus_INSTALLING { return domain.StackStatus_CLUSTER_INSTALLING, cluster.StatusDesc } @@ -725,7 +682,7 @@ func getStackStatus(cluster domain.Cluster, appGroups []domain.AppGroup) (domain } // workflow 중간 중간 비는 status 처리... - if strings.Contains(cluster.StackTemplate.Template, "aws-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-reference") { + if cluster.StackTemplate.TemplateType == "STANDARD" { if len(appGroups) < 1 { return domain.StackStatus_APPGROUP_INSTALLING, "(0/0)" } else { @@ -735,7 +692,7 @@ func getStackStatus(cluster domain.Cluster, appGroups []domain.AppGroup) (domain } } } - } else if strings.Contains(cluster.StackTemplate.Template, "aws-msa-reference") || strings.Contains(cluster.StackTemplate.Template, "eks-msa-reference") { + } else if cluster.StackTemplate.TemplateType == "MSA" { if len(appGroups) < 2 { return domain.StackStatus_APPGROUP_INSTALLING, "(0/0)" } else { @@ -770,16 +727,3 @@ func parseStatusDescription(statusDesc string) (step int) { } return } - -func getServiceQuota(client *servicequotas.Client, quotaCode string, serviceCode string) (res *servicequotas.GetServiceQuotaOutput, err error) { - res, err = client.GetServiceQuota(context.TODO(), &servicequotas.GetServiceQuotaInput{ - QuotaCode: "aCode, - ServiceCode: &serviceCode, - }, func(o *servicequotas.Options) { - o.Region = "ap-northeast-2" - }) - if err != nil { - return nil, err - } - return -} diff --git a/internal/usecase/user.go b/internal/usecase/user.go index a65b6649..1ae6319a 100644 --- a/internal/usecase/user.go +++ b/internal/usecase/user.go @@ -7,9 +7,9 @@ import ( "github.com/Nerzal/gocloak/v13" "github.com/google/uuid" - "github.com/openinfradev/tks-api/internal/aws/ses" "github.com/openinfradev/tks-api/internal/helper" "github.com/openinfradev/tks-api/internal/keycloak" + "github.com/openinfradev/tks-api/internal/mail" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/repository" @@ -118,7 +118,15 @@ func (u *UserUsecase) ResetPassword(userId uuid.UUID) error { return httpErrors.NewInternalServerError(err, "", "") } - if err = ses.SendEmailForTemporaryPassword(ses.Client, user.Email, randomPassword); err != nil { + message, err := mail.MakeTemporaryPasswordMessage(user.Email, randomPassword) + if err != nil { + log.Errorf("mail.MakeVerityIdentityMessage error. %v", err) + return httpErrors.NewInternalServerError(err, "", "") + } + + mailer := mail.New(message) + + if err := mailer.SendMail(); err != nil { return httpErrors.NewInternalServerError(err, "", "") } @@ -220,7 +228,8 @@ func (u *UserUsecase) CreateAdmin(orgainzationId string, email string) (*domain. Temporary: gocloak.BoolP(false), }, }, - Groups: &groups, + Groups: &groups, + FirstName: gocloak.StringP(user.Name), }) if err != nil { return nil, errors.Wrap(err, "creating user in keycloak failed") @@ -267,8 +276,16 @@ func (u *UserUsecase) CreateAdmin(orgainzationId string, email string) (*domain. if err != nil { return nil, err } - if err = ses.SendEmailForGeneratingOrganization(ses.Client, orgainzationId, organizationInfo.Name, user.Email, user.AccountId, randomPassword); err != nil { - return nil, err + + message, err := mail.MakeGeneratingOrganizationMessage(orgainzationId, organizationInfo.Name, user.Email, user.AccountId, randomPassword) + if err != nil { + return nil, httpErrors.NewInternalServerError(err, "", "") + } + + mailer := mail.New(message) + + if err := mailer.SendMail(); err != nil { + return nil, httpErrors.NewInternalServerError(err, "", "") } return &resUser, nil @@ -397,8 +414,9 @@ func (u *UserUsecase) UpdateByAccountId(ctx context.Context, accountId string, u if err != nil { return nil, err } - if originUser.Email == nil || *originUser.Email != user.Email { + if (originUser.Email == nil || *originUser.Email != user.Email) || (originUser.FirstName == nil || *originUser.FirstName != user.Name) { originUser.Email = gocloak.StringP(user.Email) + originUser.FirstName = gocloak.StringP(user.Name) err = u.kc.UpdateUser(userInfo.GetOrganizationId(), originUser) if err != nil { return nil, err @@ -495,8 +513,9 @@ func (u *UserUsecase) Create(ctx context.Context, user *domain.User) (*domain.Us Temporary: gocloak.BoolP(false), }, }, - Email: gocloak.StringP(user.Email), - Groups: &groups, + Email: gocloak.StringP(user.Email), + Groups: &groups, + FirstName: gocloak.StringP(user.Name), }) if err != nil { if _, err := u.kc.GetUser(user.Organization.ID, user.AccountId); err == nil { @@ -553,8 +572,9 @@ func (u *UserUsecase) UpdateByAccountIdByAdmin(ctx context.Context, accountId st if err != nil { return nil, err } - if originUser.Email == nil || *originUser.Email != user.Email { + if (originUser.Email == nil || *originUser.Email != user.Email) || (originUser.FirstName == nil || *originUser.FirstName != user.Name) { originUser.Email = gocloak.StringP(user.Email) + originUser.FirstName = gocloak.StringP(user.Name) err = u.kc.UpdateUser(userInfo.GetOrganizationId(), originUser) if err != nil { return nil, err diff --git a/pkg/api-client/api-client.go b/pkg/api-client/api-client.go index 1fd8d210..47f1ef05 100644 --- a/pkg/api-client/api-client.go +++ b/pkg/api-client/api-client.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "time" @@ -17,6 +17,7 @@ type ApiClient interface { Delete(path string, input interface{}) (out interface{}, err error) Put(path string, input interface{}) (out interface{}, err error) Patch(path string, input interface{}) (out interface{}, err error) + SetToken(token string) } type ApiClientImpl struct { @@ -26,7 +27,7 @@ type ApiClientImpl struct { } // New -func New(host string, token string) (ApiClient, error) { +func NewWithToken(host string, token string) (ApiClient, error) { return &ApiClientImpl{ client: &http.Client{ Timeout: 30 * time.Second, @@ -39,6 +40,23 @@ func New(host string, token string) (ApiClient, error) { }, nil } +func New(host string) (ApiClient, error) { + return &ApiClientImpl{ + client: &http.Client{ + Timeout: 30 * time.Second, + Transport: &http.Transport{ + MaxIdleConns: 10, + }, + }, + url: host, + token: "", + }, nil +} + +func (c *ApiClientImpl) SetToken(token string) { + c.token = token +} + func (c *ApiClientImpl) Get(path string) (out interface{}, err error) { req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/1.0/%s", c.url, path), nil) if err != nil { @@ -54,7 +72,7 @@ func (c *ApiClientImpl) Get(path string) (out interface{}, err error) { return nil, fmt.Errorf("Failed to call api server.") } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return nil, err } @@ -79,31 +97,33 @@ func (c *ApiClientImpl) Get(path string) (out interface{}, err error) { } func (c *ApiClientImpl) Post(path string, input interface{}) (out interface{}, err error) { - return c.callWithBody("POST", path, input) + return c.callWithBody("api", "POST", path, input) } func (c *ApiClientImpl) Delete(path string, input interface{}) (out interface{}, err error) { - return c.callWithBody("DELETE", path, input) + return c.callWithBody("api", "DELETE", path, input) } func (c *ApiClientImpl) Put(path string, input interface{}) (out interface{}, err error) { - return c.callWithBody("PUT", path, input) + return c.callWithBody("api", "PUT", path, input) } func (c *ApiClientImpl) Patch(path string, input interface{}) (out interface{}, err error) { - return c.callWithBody("PATCH", path, input) + return c.callWithBody("api", "PATCH", path, input) } -func (c *ApiClientImpl) callWithBody(method string, path string, input interface{}) (out interface{}, err error) { +func (c *ApiClientImpl) callWithBody(prefix string, method string, path string, input interface{}) (out interface{}, err error) { pbytes, _ := json.Marshal(input) buff := bytes.NewBuffer(pbytes) - req, err := http.NewRequest(method, fmt.Sprintf("%s/api/1.0/%s", c.url, path), buff) + req, err := http.NewRequest(method, fmt.Sprintf("%s/%s/1.0/%s", c.url, prefix, path), buff) if err != nil { return nil, err } - req.Header.Add("Authorization", "Bearer "+c.token) + if prefix == "api" { + req.Header.Add("Authorization", "Bearer "+c.token) + } res, err := c.client.Do(req) if err != nil { return nil, err @@ -112,7 +132,7 @@ func (c *ApiClientImpl) callWithBody(method string, path string, input interface return nil, fmt.Errorf("Failed to call api server.") } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return nil, err } diff --git a/pkg/argo-client/client.go b/pkg/argo-client/client.go index 4fafcd49..b100b5a4 100644 --- a/pkg/argo-client/client.go +++ b/pkg/argo-client/client.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "time" @@ -64,7 +64,7 @@ func (c *ArgoClientImpl) GetWorkflowTemplates(namespace string) (*GetWorkflowTem } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return nil, err } @@ -95,7 +95,7 @@ func (c *ArgoClientImpl) GetWorkflow(namespace string, workflowName string) (*Wo } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return nil, err } @@ -128,7 +128,7 @@ func (c *ArgoClientImpl) GetWorkflowLog(namespace string, container string, work } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return logs, err } @@ -154,7 +154,7 @@ func (c *ArgoClientImpl) GetWorkflows(namespace string) (*GetWorkflowsResponse, } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return nil, err } @@ -204,7 +204,7 @@ func (c *ArgoClientImpl) SumbitWorkflowFromWftpl(wftplName string, opts SubmitOp } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return "", err } diff --git a/pkg/domain/app-serve-app.go b/pkg/domain/app-serve-app.go index 1624f90d..5cb82ff1 100644 --- a/pkg/domain/app-serve-app.go +++ b/pkg/domain/app-serve-app.go @@ -19,6 +19,7 @@ type AppServeApp struct { TargetClusterId string `json:"targetClusterId,omitempty"` // target cluster to which the app is deployed TargetClusterName string `gorm:"-:all" json:"targetClusterName,omitempty"` // target cluster name Status string `gorm:"index" json:"status,omitempty"` // status is status of deployed app + GrafanaUrl string `json:"grafanaUrl,omitempty"` // grafana dashboard URL for deployed app CreatedAt time.Time `gorm:"autoCreateTime:false" json:"createdAt" ` UpdatedAt *time.Time `gorm:"autoUpdateTime:false" json:"updatedAt"` DeletedAt *time.Time `json:"deletedAt"` diff --git a/pkg/domain/auth.go b/pkg/domain/auth.go index 2840ea3d..abab6f97 100644 --- a/pkg/domain/auth.go +++ b/pkg/domain/auth.go @@ -6,6 +6,11 @@ type LoginRequest struct { OrganizationId string `json:"organizationId" validate:"required"` } +type PingTokenRequest struct { + Token string `json:"token" validate:"required"` + OrganizationId string `json:"organizationId" validate:"required"` +} + type LoginResponse struct { User struct { AccountId string `json:"accountId"` diff --git a/pkg/domain/cloud-account.go b/pkg/domain/cloud-account.go index 981f7589..5e4720c8 100644 --- a/pkg/domain/cloud-account.go +++ b/pkg/domain/cloud-account.go @@ -13,6 +13,7 @@ const ( CloudService_AWS = "AWS" CloudService_AZURE = "AZZURE" CloudService_GCP = "GCP" + CloudService_BYOH = "BYOH" ) // enum @@ -72,6 +73,17 @@ type CloudAccount struct { UpdatedAt time.Time } +type ResourceQuotaAttr struct { + Type string `json:"type"` + Usage int `json:"usage"` + Quota int `json:"quota"` + Required int `json:"required"` +} + +type ResourceQuota struct { + Quotas []ResourceQuotaAttr `json:"quotas"` +} + type CloudAccountResponse struct { ID string `json:"id"` OrganizationId string `json:"organizationId"` @@ -140,3 +152,8 @@ type CheckCloudAccountNameResponse struct { type CheckCloudAccountAwsAccountIdResponse struct { Existed bool `json:"existed"` } + +type GetCloudAccountResourceQuotaResponse struct { + Available bool `json:"available"` + ResourceQuota ResourceQuota `json:"resourceQuota"` +} diff --git a/pkg/domain/cluster.go b/pkg/domain/cluster.go index ab9264ff..6964a83a 100644 --- a/pkg/domain/cluster.go +++ b/pkg/domain/cluster.go @@ -7,6 +7,10 @@ import ( "github.com/openinfradev/tks-api/internal/helper" ) +const NODE_TYPE_TKS_CP_NODE = "TKS_CP_NODE" +const NODE_TYPE_TKS_INFRA_NODE = "TKS_INFRA_NODE" +const NODE_TYPE_TKS_USER_NODE = "TKS_USER_NODE" + type ClusterId string func (c ClusterId) String() string { @@ -28,6 +32,9 @@ const ( ClusterStatus_DELETED ClusterStatus_INSTALL_ERROR ClusterStatus_DELETE_ERROR + ClusterStatus_BOOTSTRAPPING + ClusterStatus_BOOTSTRAPPED + ClusterStatus_BOOTSTRAP_ERROR ) var clusterStatus = [...]string{ @@ -38,6 +45,9 @@ var clusterStatus = [...]string{ "DELETED", "INSTALL_ERROR", "DELETE_ERROR", + "BOOTSTRAPPING", + "BOOTSTRAPPED", + "BOOTSTRAP_ERROR", } func (m ClusterStatus) String() string { return clusterStatus[(m)] } @@ -50,70 +60,132 @@ func (m ClusterStatus) FromString(s string) ClusterStatus { return ClusterStatus_PENDING } +type ClusterType int32 + +const ( + ClusterType_USER = iota + ClusterType_ADMIN +) + +var clusterType = [...]string{ + "USER", + "ADMIN", +} + +func (m ClusterType) String() string { return clusterType[(m)] } +func (m ClusterType) FromString(s string) ClusterType { + for i, v := range clusterType { + if v == s { + return ClusterType(i) + } + } + return ClusterType_USER +} + // model type Cluster struct { - ID ClusterId - OrganizationId string - Name string - Description string - CloudAccountId uuid.UUID - CloudAccount CloudAccount - StackTemplateId uuid.UUID - StackTemplate StackTemplate - Status ClusterStatus - StatusDesc string - Conf ClusterConf - CreatorId *uuid.UUID - Creator User - UpdatorId *uuid.UUID - Updator User - CreatedAt time.Time - UpdatedAt time.Time + ID ClusterId + CloudService string + OrganizationId string + Name string + Description string + CloudAccountId uuid.UUID + CloudAccount CloudAccount + StackTemplateId uuid.UUID + StackTemplate StackTemplate + Status ClusterStatus + StatusDesc string + Conf ClusterConf + Favorited bool + CreatorId *uuid.UUID + Creator User + ClusterType ClusterType + UpdatorId *uuid.UUID + Updator User + CreatedAt time.Time + UpdatedAt time.Time + ByoClusterEndpointHost string + ByoClusterEndpointPort int + IsStack bool } type ClusterConf struct { - CpNodeCnt int - CpNodeMachineType string - TksNodeCnt int - TksNodeMachineType string - UserNodeCnt int - UserNodeMachineType string + TksCpNode int + TksCpNodeMax int + TksCpNodeType string + TksInfraNode int + TksInfraNodeMax int + TksInfraNodeType string + TksUserNode int + TksUserNodeMax int + TksUserNodeType string +} + +type ClusterHost struct { + Name string `json:"name"` + Status string `json:"status"` +} + +type ClusterNode struct { + Type string `json:"type"` + Targeted int `json:"targeted"` + Registered int `json:"registered"` + Registering int `json:"registering"` + Status string `json:"status"` + Command string `json:"command"` + Validity int `json:"validity"` + Hosts []ClusterHost `json:"hosts"` +} + +type BootstrapKubeconfig struct { + Expiration int `json:"expiration"` } // [TODO] annotaion 으로 가능하려나? func (m *ClusterConf) SetDefault() { - if m.CpNodeCnt == 0 { - m.CpNodeCnt = 3 - } - if m.TksNodeCnt == 0 { - m.TksNodeCnt = 3 + m.TksCpNodeMax = m.TksCpNode + + if m.TksInfraNode == 0 { + m.TksInfraNode = 3 } - if m.UserNodeCnt == 0 { - m.UserNodeCnt = 1 + m.TksInfraNodeMax = m.TksInfraNode + + if m.TksUserNode == 0 { + m.TksUserNode = 1 } - if m.CpNodeMachineType == "" { - m.CpNodeMachineType = "t3.xlarge" + m.TksUserNodeMax = m.TksUserNode + + if m.TksCpNodeType == "" { + m.TksCpNodeType = "t3.xlarge" } - if m.TksNodeMachineType == "" { - m.TksNodeMachineType = "t3.2xlarge" + if m.TksInfraNodeType == "" { + m.TksInfraNodeType = "t3.2xlarge" } - if m.UserNodeMachineType == "" { - m.UserNodeMachineType = "t3.large" + if m.TksUserNodeType == "" { + m.TksUserNodeType = "t3.large" } } type CreateClusterRequest struct { - OrganizationId string `json:"organizationId" validate:"required"` - StackTemplateId string `json:"stackTemplateId" validate:"required"` - Name string `json:"name" validate:"required,name"` - Description string `json:"description"` - CloudAccountId string `json:"cloudAccountId" validate:"required"` - CpNodeCnt int `json:"cpNodeCnt,omitempty"` - CpNodeMachineType string `json:"cpNodeMachineType,omitempty"` - TksNodeCnt int `json:"tksNodeCnt,omitempty"` - TksNodeMachineType string `json:"tksNodeMachineType,omitempty"` - UserNodeCnt int `json:"userNodeCnt,omitempty"` - UserNodeMachineType string `json:"userNodeMachineType,omitempty"` + OrganizationId string `json:"organizationId" validate:"required"` + CloudService string `json:"cloudService" validate:"required,oneof=AWS BYOH"` + StackTemplateId string `json:"stackTemplateId" validate:"required"` + Name string `json:"name" validate:"required,name"` + Description string `json:"description"` + CloudAccountId string `json:"cloudAccountId"` + ClusterType string `json:"clusterType"` + ByoClusterEndpointHost string `json:"byoClusterEndpointHost,omitempty"` + ByoClusterEndpointPort int `json:"byoClusterEndpointPort,omitempty"` + IsStack bool `json:"isStack,omitempty"` + TksCpNode int `json:"tksCpNode"` + TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` + TksCpNodeType string `json:"tksCpNodeType,omitempty"` + TksInfraNode int `json:"tksInfraNode"` + TksInfraNodeMax int `json:"tksInfraNodeMax,omitempty"` + TksInfraNodeType string `json:"tksInfraNodeType,omitempty"` + TksUserNode int `json:"tksUserNode"` + TksUserNodeMax int `json:"tksUserNodeMax,omitempty"` + TksUserNodeType string `json:"tksUserNodeType,omitempty"` } type CreateClusterResponse struct { @@ -121,25 +193,36 @@ type CreateClusterResponse struct { } type ClusterConfResponse struct { - CpNodeCnt int `json:"cpNodeCnt"` - TksNodeCnt int `json:"tksNodeCnt"` - UserNodeCnt int `json:"userpNodeCnt"` + TksCpNode int `json:"tksCpNode"` + TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` + TksCpNodeType string `json:"tksCpNodeType,omitempty"` + TksInfraNode int `json:"tksInfraNode"` + TksInfraNodeMax int `json:"tksInfraNodeMax,omitempty"` + TksInfraNodeType string `json:"tksInfraNodeType,omitempty"` + TksUserNode int `json:"tksUserNode"` + TksUserNodeMax int `json:"tksUserNodeMax,omitempty"` + TksUserNodeType string `json:"tksUserNodeType,omitempty"` } type ClusterResponse struct { - ID ClusterId `json:"id"` - OrganizationId string `json:"organizationId"` - Name string `json:"name"` - Description string `json:"description"` - CloudAccount SimpleCloudAccountResponse `json:"cloudAccount"` - StackTemplate SimpleStackTemplateResponse `json:"stackTemplate"` - Status string `json:"status"` - StatusDesc string `json:"statusDesc"` - Conf ClusterConfResponse `json:"conf"` - Creator SimpleUserResponse `json:"creator"` - Updator SimpleUserResponse `json:"updator"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID ClusterId `json:"id"` + CloudService string `json:"cloudService"` + OrganizationId string `json:"organizationId"` + Name string `json:"name"` + Description string `json:"description"` + CloudAccount SimpleCloudAccountResponse `json:"cloudAccount"` + StackTemplate SimpleStackTemplateResponse `json:"stackTemplate"` + Status string `json:"status"` + StatusDesc string `json:"statusDesc"` + Conf ClusterConfResponse `json:"conf"` + ClusterType string `json:"clusterType"` + Creator SimpleUserResponse `json:"creator"` + Updator SimpleUserResponse `json:"updator"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + ByoClusterEndpointHost string `json:"byoClusterEndpointHost,omitempty"` + ByoClusterEndpointInt int `json:"byoClusterEndpointPort,omitempty"` + IsStack bool `json:"isStack,omitempty"` } type SimpleClusterResponse struct { @@ -149,16 +232,19 @@ type SimpleClusterResponse struct { } type ClusterSiteValuesResponse struct { - SshKeyName string `json:"sshKeyName"` - ClusterRegion string `json:"clusterRegion"` - CpReplicas int `json:"cpReplicas"` - CpNodeMachineType string `json:"cpNodeMachineType"` - MpReplicas int `json:"mpReplicas"` - MpNodeMachineType string `json:"mpNodeMachineType"` - MdNumOfAz int `json:"mdNumOfAz"` - MdMinSizePerAz int `json:"mdMinSizePerAz"` - MdMaxSizePerAz int `json:"mdMaxSizePerAz"` - MdMachineType string `json:"mdMachineType"` + SshKeyName string `json:"sshKeyName"` + ClusterRegion string `json:"clusterRegion"` + TksCpNode int `json:"tksCpNode"` + TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` + TksCpNodeType string `json:"tksCpNodeType,omitempty"` + TksInfraNode int `json:"tksInfraNode"` + TksInfraNodeMax int `json:"tksInfraNodeMax,omitempty"` + TksInfraNodeType string `json:"tksInfraNodeType,omitempty"` + TksUserNode int `json:"tksUserNode"` + TksUserNodeMax int `json:"tksUserNodeMax,omitempty"` + TksUserNodeType string `json:"tksUserNodeType,omitempty"` + ByoClusterEndpointHost string `json:"byoClusterEndpointHost,omitempty"` + ByoClusterEndpointPort int `json:"byoClusterEndpointPort,omitempty"` } type GetClustersResponse struct { @@ -173,3 +259,20 @@ type GetClusterResponse struct { type GetClusterSiteValuesResponse struct { ClusterSiteValues ClusterSiteValuesResponse `json:"clusterSiteValues"` } + +type InstallClusterRequest struct { + ClusterId string `json:"clusterId" validate:"required"` + OrganizationId string `json:"organizationId" validate:"required"` +} + +type CreateBootstrapKubeconfigResponse struct { + Data BootstrapKubeconfig `json:"kubeconfig"` +} + +type GetBootstrapKubeconfigResponse struct { + Data BootstrapKubeconfig `json:"kubeconfig"` +} + +type GetClusterNodesResponse struct { + Nodes []ClusterNode `json:"nodes"` +} diff --git a/pkg/domain/stack-template.go b/pkg/domain/stack-template.go index 0be6ae35..b1fff5c6 100644 --- a/pkg/domain/stack-template.go +++ b/pkg/domain/stack-template.go @@ -6,6 +6,9 @@ import ( "github.com/google/uuid" ) +const STACK_TEMPLATE_TYPE_STANDARD = "STANDARD" +const STACK_TEMPLATE_TYPE_MSA = "MSA" + // 내부 type StackTemplate struct { ID uuid.UUID @@ -13,6 +16,7 @@ type StackTemplate struct { Name string Description string Template string + TemplateType string CloudService string Version string Platform string @@ -43,6 +47,7 @@ type StackTemplateResponse struct { Name string `json:"name"` Description string `json:"description"` Template string `json:"template"` + TemplateType string `json:"templateType"` CloudService string `json:"cloudService"` Version string `json:"version"` Platform string `json:"platform"` @@ -56,11 +61,12 @@ type StackTemplateResponse struct { } type SimpleStackTemplateResponse struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Template string `json:"template"` - CloudService string `json:"cloudService"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Template string `json:"template"` + CloudService string `json:"cloudService"` + Services []StackTemplateServiceResponse `json:"services"` } type GetStackTemplatesResponse struct { @@ -79,6 +85,7 @@ type CreateStackTemplateRequest struct { Version string `json:"version" validate:"required"` Platform string `json:"platform" validate:"required"` Template string `json:"template" validate:"required"` + TemplateType string `json:"templateType" validate:"oneof=STANDARD MSA"` } type CreateStackTemplateResponse struct { diff --git a/pkg/domain/stack.go b/pkg/domain/stack.go index f405ad99..07de89d8 100644 --- a/pkg/domain/stack.go +++ b/pkg/domain/stack.go @@ -35,6 +35,9 @@ const ( StackStatus_CLUSTER_DELETE_ERROR StackStatus_RUNNING + + StackStatus_CLUSTER_BOOTSTRAPPING + StackStatus_CLUSTER_BOOTSTRAPPED ) var stackStatus = [...]string{ @@ -49,6 +52,8 @@ var stackStatus = [...]string{ "CLUSTER_INSTALL_ERROR", "CLUSTER_DELETE_ERROR", "RUNNING", + "BOOTSTRAPPING", + "BOOTSTRAPPED", } func (m StackStatus) String() string { return stackStatus[(m)] } @@ -74,7 +79,9 @@ type Stack = struct { ID StackId Name string Description string + ClusterId string OrganizationId string + CloudService string CloudAccountId uuid.UUID CloudAccount CloudAccount StackTemplateId uuid.UUID @@ -90,17 +97,22 @@ type Stack = struct { Updator User CreatedAt time.Time UpdatedAt time.Time + Favorited bool + ClusterEndpoint string + Resource DashboardStackResponse } type StackConf struct { - CpNodeCnt int - CpNodeMachineType string - TksNodeCnt int - TksNodeMachineType string - UserNodeCnt int - UserNodeMachineType string + TksCpNode int + TksCpNodeMax int + TksCpNodeType string + TksInfraNode int + TksInfraNodeMax int + TksInfraNodeType string + TksUserNode int + TksUserNodeMax int + TksUserNodeType string } - type StackStepStatus struct { Status string `json:"status"` Stage string `json:"stage"` @@ -109,16 +121,22 @@ type StackStepStatus struct { } type CreateStackRequest struct { - Name string `json:"name" validate:"required,name,rfc1123"` - Description string `json:"description"` - StackTemplateId string `json:"stackTemplateId" validate:"required"` - CloudAccountId string `json:"cloudAccountId" validate:"required"` - CpNodeCnt int `json:"cpNodeCnt,omitempty"` - CpNodeMachineType string `json:"cpNodeMachineType,omitempty"` - TksNodeCnt int `json:"tksNodeCnt" validate:"required,min=3,max=6"` - TksNodeMachineType string `json:"tksNodeMachineType,omitempty"` - UserNodeCnt int `json:"userNodeCnt" validate:"required,min=0,max=100"` - UserNodeMachineType string `json:"userNodeMachineType,omitempty"` + Name string `json:"name" validate:"required,name,rfc1123"` + Description string `json:"description"` + ClusterId string `json:"clusterId"` + CloudService string `json:"cloudService" validate:"required,oneof=AWS BYOH"` + StackTemplateId string `json:"stackTemplateId" validate:"required"` + CloudAccountId string `json:"cloudAccountId"` + ClusterEndpoint string `json:"userClusterEndpoint,omitempty"` + TksCpNode int `json:"tksCpNode"` + TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` + TksCpNodeType string `json:"tksCpNodeType,omitempty"` + TksInfraNode int `json:"tksInfraNode"` + TksInfraNodeMax int `json:"tksInfraNodeMax,omitempty"` + TksInfraNodeType string `json:"tksInfraNodeType,omitempty"` + TksUserNode int `json:"tksUserNode"` + TksUserNodeMax int `json:"tksUserNodeMax,omitempty"` + TksUserNodeType string `json:"tksUserNodeType,omitempty"` } type CreateStackResponse struct { @@ -126,30 +144,36 @@ type CreateStackResponse struct { } type StackConfResponse struct { - CpNodeCnt int `json:"cpNodeCnt"` - CpNodeMachineType string `json:"cpNodeMachineType,omitempty"` - TksNodeCnt int `json:"tksNodeCnt"` - TksNodeMachineType string `json:"tksNodeMachineType,omitempty"` - UserNodeCnt int `json:"userNodeCnt"` - UserNodeMachineType string `json:"userNodeMachineType,omitempty"` + TksCpNode int `json:"tksCpNode"` + TksCpNodeMax int `json:"tksCpNodeMax,omitempty"` + TksCpNodeType string `json:"tksCpNodeType,omitempty"` + TksInfraNode int `json:"tksInfraNode" validate:"required,min=1,max=3"` + TksInfraNodeMax int `json:"tksInfraNodeMax,omitempty"` + TksInfraNodeType string `json:"tksInfraNodeType,omitempty"` + TksUserNode int `json:"tksUserNode" validate:"required,min=0,max=100"` + TksUserNodeMax int `json:"tksUserNodeMax,omitempty"` + TksUserNodeType string `json:"tksUserNodeType,omitempty"` } type StackResponse struct { - ID StackId `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - OrganizationId string `json:"organizationId"` - StackTemplate SimpleStackTemplateResponse `json:"stackTemplate,omitempty"` - CloudAccount SimpleCloudAccountResponse `json:"cloudAccount,omitempty"` - Status string `json:"status"` - StatusDesc string `json:"statusDesc"` - PrimaryCluster bool `json:"primaryCluster"` - Conf StackConfResponse `json:"conf"` - GrafanaUrl string `json:"grafanaUrl"` - Creator SimpleUserResponse `json:"creator,omitempty"` - Updator SimpleUserResponse `json:"updator,omitempty"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID StackId `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + OrganizationId string `json:"organizationId"` + StackTemplate SimpleStackTemplateResponse `json:"stackTemplate,omitempty"` + CloudAccount SimpleCloudAccountResponse `json:"cloudAccount,omitempty"` + Status string `json:"status"` + StatusDesc string `json:"statusDesc"` + PrimaryCluster bool `json:"primaryCluster"` + Conf StackConfResponse `json:"conf"` + GrafanaUrl string `json:"grafanaUrl"` + Creator SimpleUserResponse `json:"creator,omitempty"` + Updator SimpleUserResponse `json:"updator,omitempty"` + Favorited bool `json:"favorited"` + ClusterEndpoint string `json:"userClusterEndpoint,omitempty"` + Resource DashboardStackResponse `json:"resource,omitempty"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } type GetStacksResponse struct { diff --git a/pkg/httpErrors/errorCode.go b/pkg/httpErrors/errorCode.go index 17f62395..ff6b05ae 100644 --- a/pkg/httpErrors/errorCode.go +++ b/pkg/httpErrors/errorCode.go @@ -14,6 +14,8 @@ var errorMap = map[ErrorCode]string{ "C_INVALID_STACK_TEMPLATE_ID": "유효하지 않은 스택템플릿 아이디입니다. 스택템플릿 아이디를 확인하세요.", "C_INVALID_ASA_ID": "유효하지 않은 앱서빙앱 아이디입니다. 앱서빙앱 아이디를 확인하세요.", "C_INVALID_ASA_TASK_ID": "유효하지 않은 테스크 아이디입니다. 테스크 아이디를 확인하세요.", + "C_INVALID_CLOUD_SERVICE": "유효하지 않은 클라우드서비스입니다.", + "C_FAILED_TO_CALL_WORKFLOW": "워크플로우 호출에 실패했습니다.", // Auth "A_INVALID_ID": "아이디가 존재하지 않습니다.", @@ -42,6 +44,9 @@ var errorMap = map[ErrorCode]string{ // AppServeApp "D_NO_ASA": "요청한 앱아이디에 해당하는 어플리케이션이 없습니다.", + // Cluster + "CL_INVALID_BYOH_CLUSTER_ENDPOINT": "BYOH 타입의 클러스터 생성을 위한 cluster endpoint 가 유효하지 않습니다.", + // Stack "S_INVALID_STACK_TEMPLATE": "스택 템플릿을 가져올 수 없습니다.", "S_INVALID_CLOUD_ACCOUNT": "클라우드 계정설정을 가져올 수 없습니다.", @@ -55,6 +60,9 @@ var errorMap = map[ErrorCode]string{ "S_FAILED_GET_CLUSTERS": "클러스터를 가져오는데 실패했습니다.", "S_FAILED_DELETE_EXISTED_ASA": "지우고자 하는 스택에 남아 있는 앱서빙앱이 있습니다.", "S_NOT_ENOUGH_QUOTA": "AWS 의 resource quota 가 부족합니다. 관리자에게 문의하세요.", + "S_INVALID_CLUSTER_URL": "BYOH 타입의 클러스터 생성은 반드시 userClusterEndpoint 값이 필요합니다.", + "S_INVALID_CLUSTER_ID": "BYOH 타입의 클러스터 생성은 반드시 clusterId 값이 필요합니다.", + "S_INVALID_CLOUD_SERVICE": "클라우드 서비스 타입이 잘못되었습니다.", // Alert "AL_NOT_FOUND_ALERT": "지정한 앨럿이 존재하지 않습니다.", diff --git a/pkg/log/log.go b/pkg/log/log.go index 039bd547..5ad235dd 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -2,7 +2,7 @@ package log import ( "context" - "io/ioutil" + "io" "os" "strings" @@ -109,5 +109,5 @@ func Fatalf(format string, v ...interface{}) { } func Disable() { - logger.Out = ioutil.Discard + logger.Out = io.Discard } diff --git a/pkg/thanos-client/client.go b/pkg/thanos-client/client.go index 1cdf034c..61a602b7 100644 --- a/pkg/thanos-client/client.go +++ b/pkg/thanos-client/client.go @@ -3,7 +3,7 @@ package thanos import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "time" @@ -63,7 +63,7 @@ func (c *ThanosClientImpl) Get(query string) (out Metric, err error) { } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return out, err } @@ -100,7 +100,7 @@ func (c *ThanosClientImpl) FetchRange(query string, start int, end int, step int } }() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return out, err } diff --git a/scripts/init_postgres.sql b/scripts/init_postgres.sql index cf90c12b..a335c9a5 100644 --- a/scripts/init_postgres.sql +++ b/scripts/init_postgres.sql @@ -15,15 +15,19 @@ insert into policies ( role_id, name, description, c, create_priviledge, u, upda insert into organizations ( id, name, description, created_at, updated_at ) values ( 'master', 'master', 'tks', now(), now() ); insert into users ( id, account_id, name, password, organization_id, role_id, created_at, updated_at ) values ( 'bf67de40-ce15-4dc0-b6c2-17f053ca504f', 'admin', 'admin', '$2a$10$Akf03nbLHk93sTtozm35XuINXkJeNX7A1T9o/Pxpg9R2B2PToBPOO', 'master', 'b2b689f0-ceeb-46c2-b280-0bc06896acd1', now(), now() ); -insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '49901092-be76-4d4f-94e9-b84525f560b5', 'master', 'AWS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'aws-reference', 'v1.25', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); -insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '44d5e76b-63db-4dd0-a16e-11bd3f6054cf', 'master', 'AWS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'aws-msa-reference', 'v1.25', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); -insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( 'fe1d97e0-7428-4be6-9c69-310a88b4ff46', 'master', 'AWS Standard (arm)', 'included LMA', 'v2', 'AWS', 'arm', 'aws-arm-reference', 'v1.25', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); -insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '3696cb38-4da0-4235-97eb-b6eb15962bd1', 'master', 'AWS Standard (arm)', 'included LMA, SERVICE_MESH', 'v2', 'AWS', 'arm', 'aws-arm-msa-reference', 'v1.25', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); -insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( 'c8a4658d-d5a6-4191-8a91-e26f6aee007f', 'master', 'EKS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'eks-reference', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.30.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.66.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.25.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"8.3.3","description":"모니터링/로그 통합대시보드"}]}]' ); -insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, kube_version, kube_type, created_at, updated_at, services ) -values ( '39f18a09-5b94-4772-bdba-e4c32ee002f7', 'master', 'EKS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'eks-msa-reference', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.30.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.66.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.25.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"8.3.3","description":"모니터링/로그 통합대시보드"}]},{"name":"MSA","type":"SERVICE_MESH","applications":[{"name":"istio","version":"v1.17.2","description":"MSA 플랫폼"},{"name":"jagger","version":"1.35.0","description":"분산 서비스간 트랜잭션 추적을 위한 플랫폼"},{"name":"kiali","version":"v1.63.0","description":"MSA 구조 및 성능을 볼 수 있는 Dashboard"},{"name":"k8ssandra","version":"1.6.0","description":"분산 서비스간 호출 로그를 저장하는 스토리지"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( '49901092-be76-4d4f-94e9-b84525f560b5', 'master', 'AWS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'aws-reference', 'STANDARD', 'v1.25', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( '44d5e76b-63db-4dd0-a16e-11bd3f6054cf', 'master', 'AWS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'aws-msa-reference', 'MSA', 'v1.25', 'AWS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( 'fe1d97e0-7428-4be6-9c69-310a88b4ff46', 'master', 'AWS Standard (arm)', 'included LMA', 'v2', 'AWS', 'arm', 'aws-arm-reference', 'STANDARD', 'v1.25', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( '3696cb38-4da0-4235-97eb-b6eb15962bd1', 'master', 'AWS Standard (arm)', 'included LMA, SERVICE_MESH', 'v2', 'AWS', 'arm', 'aws-arm-msa-reference', 'MSA', 'v1.25', 'EKS', now(), now(), '[{"name": "Logging,Monitoring,Alerting", "type": "LMA", "applications": [{"name": "prometheus-stack", "version": "v.44.3.1", "description": "통계데이터 제공을 위한 backend 플랫폼"}, {"name": "elastic-system", "version": "v1.8.0", "description": "로그 데이터 적재를 위한 Storage"}, {"name": "alertmanager", "version": "v0.23.0", "description": "Alert 관리를 위한 backend 서비스"}, {"name": "grafana", "version": "v6.50.7", "description": "모니터링 통합 포탈"}]}, {"name": "MSA", "type": "SERVICE_MESH", "applications": [{"name": "istio", "version": "v1.13.1", "description": "MSA 플랫폼"}, {"name": "jagger", "version": "v2.27.1", "description": "분산 서비스간 트랜잭션 추적을 위한 로깅 플랫폼"}, {"name": "kiali", "version": "v1.45.1", "description": "MSA 통합 모니터링포탈"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( 'c8a4658d-d5a6-4191-8a91-e26f6aee007f', 'master', 'EKS Standard (x86)', 'included LMA', 'v1', 'AWS', 'x86', 'eks-reference', 'STANDARD', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.30.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.66.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.25.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"8.3.3","description":"모니터링/로그 통합대시보드"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( '39f18a09-5b94-4772-bdba-e4c32ee002f7', 'master', 'EKS MSA Standard (x86)', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'eks-msa-reference', 'MSA', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.30.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.66.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.25.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"8.3.3","description":"모니터링/로그 통합대시보드"}]},{"name":"MSA","type":"SERVICE_MESH","applications":[{"name":"istio","version":"v1.17.2","description":"MSA 플랫폼"},{"name":"jagger","version":"1.35.0","description":"분산 서비스간 트랜잭션 추적을 위한 플랫폼"},{"name":"kiali","version":"v1.63.0","description":"MSA 구조 및 성능을 볼 수 있는 Dashboard"},{"name":"k8ssandra","version":"1.6.0","description":"분산 서비스간 호출 로그를 저장하는 스토리지"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( '5678bf11-256f-4d2c-a673-f2fedb82de5b', 'master', 'BYOH Standard', 'included LMA', 'v1', 'AWS', 'x86', 'eks-reference', 'STANDARD', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.30.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.66.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.25.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"8.3.3","description":"모니터링/로그 통합대시보드"}]}]' ); +insert into stack_templates ( id, organization_id, name, description, version, cloud_service, platform, template, template_type, kube_version, kube_type, created_at, updated_at, services ) +values ( '92f5e5ce-7ffd-4c3e-aff6-9b7fb03dd881', 'master', 'BYOH MSA Standard', 'included LMA, SERVICE MESH', 'v1', 'AWS', 'x86', 'eks-msa-reference', 'MSA', 'v1.25', 'AWS', now(), now(), '[{"name":"Logging,Monitoring,Alerting","type":"LMA","applications":[{"name":"thanos","version":"0.30.2","description":"다중클러스터의 모니터링 데이터 통합 질의처리"},{"name":"prometheus-stack","version":"v0.66.0","description":"모니터링 데이터 수집/저장 및 질의처리"},{"name":"alertmanager","version":"v0.25.0","description":"알람 처리를 위한 노티피케이션 서비스"},{"name":"loki","version":"2.6.1","description":"로그데이터 저장 및 질의처리"},{"name":"grafana","version":"8.3.3","description":"모니터링/로그 통합대시보드"}]},{"name":"MSA","type":"SERVICE_MESH","applications":[{"name":"istio","version":"v1.17.2","description":"MSA 플랫폼"},{"name":"jagger","version":"1.35.0","description":"분산 서비스간 트랜잭션 추적을 위한 플랫폼"},{"name":"kiali","version":"v1.63.0","description":"MSA 구조 및 성능을 볼 수 있는 Dashboard"},{"name":"k8ssandra","version":"1.6.0","description":"분산 서비스간 호출 로그를 저장하는 스토리지"}]}]' ); \ No newline at end of file