From d480709d3d29a3920135908527a58ea3dd2d535d Mon Sep 17 00:00:00 2001 From: Asher Liu Date: Thu, 8 Jul 2021 20:23:07 +0800 Subject: [PATCH] feature: cmp support new import method (#806) --- .../20210708-add-manageconfig.sql | 2 + .../20210528-cmp-base.sql} | 0 apistructs/cluster.go | 22 +- apistructs/cmp.go | 34 ++ apistructs/cmp_cloud_resource.go | 26 +- apistructs/erda_operator.go | 98 +++ apistructs/org.go | 5 + bundle/cluster.go | 14 +- bundle/org.go | 37 ++ cmd/cluster-init/main.go | 24 + conf/cluster-init/cluster-init.yaml | 1 + erda.yml | 3 + go.mod | 6 +- go.sum | 170 +++++- modules/admin/manager/cluster.go | 6 + modules/cluster-init/client/client.go | 165 ++++++ modules/cluster-init/config/config.go | 31 + modules/cluster-init/provider.go | 53 ++ .../services/apierrors/errors.go | 1 + .../services/cluster/cluster.go | 4 + modules/cmp/conf/conf.go | 91 ++- modules/cmp/dbclient/models.go | 43 +- modules/cmp/endpoints/cluster.go | 145 ++++- modules/cmp/endpoints/common.go | 4 +- modules/cmp/endpoints/endpoints.go | 10 + modules/cmp/endpoints/records.go | 4 + modules/cmp/i18n/i18n.go | 1 + modules/cmp/impl/clusters/cluster_hook.go | 63 ++ modules/cmp/impl/clusters/clusterinfo.go | 205 ++++++- modules/cmp/impl/clusters/import_cluster.go | 561 ++++++++++++++++++ .../cmp/impl/clusters/offline_edge_cluster.go | 14 +- modules/cmp/impl/clusters/proxy-deploy.go | 86 +++ modules/cmp/impl/clusters/update_cluster.go | 59 ++ .../cmp/impl/clusters/upgrade_edge_cluster.go | 4 +- modules/cmp/initialize.go | 56 +- modules/cmp/services/kubernetes/kubernetes.go | 108 ++++ .../api/apis/cmdb/cmdb_cluster_create.go | 49 -- .../api/apis/cmp/cmp_cluster_import.go | 30 + .../api/apis/cmp/cmp_cluster_init_command.go | 27 + pkg/helm/getter.go | 72 +++ pkg/helm/helm.go | 383 ++++++++++++ pkg/helm/manager.go | 184 ++++++ pkg/k8sclient/client.go | 32 +- pkg/k8sclient/config/config.go | 12 +- pkg/k8sclient/scheme/register.go | 2 + 45 files changed, 2794 insertions(+), 153 deletions(-) create mode 100644 .erda/migrations/cluster-manager/20210708-add-manageconfig.sql rename .erda/migrations/{ops/20210528-ops-base.sql => cmp/20210528-cmp-base.sql} (100%) create mode 100644 apistructs/erda_operator.go create mode 100644 cmd/cluster-init/main.go create mode 100644 conf/cluster-init/cluster-init.yaml create mode 100644 modules/cluster-init/client/client.go create mode 100644 modules/cluster-init/config/config.go create mode 100644 modules/cluster-init/provider.go create mode 100644 modules/cmp/impl/clusters/cluster_hook.go create mode 100644 modules/cmp/impl/clusters/import_cluster.go create mode 100644 modules/cmp/impl/clusters/proxy-deploy.go create mode 100644 modules/cmp/impl/clusters/update_cluster.go create mode 100644 modules/cmp/services/kubernetes/kubernetes.go delete mode 100644 modules/openapi/api/apis/cmdb/cmdb_cluster_create.go create mode 100644 modules/openapi/api/apis/cmp/cmp_cluster_import.go create mode 100644 modules/openapi/api/apis/cmp/cmp_cluster_init_command.go create mode 100644 pkg/helm/getter.go create mode 100644 pkg/helm/helm.go create mode 100644 pkg/helm/manager.go diff --git a/.erda/migrations/cluster-manager/20210708-add-manageconfig.sql b/.erda/migrations/cluster-manager/20210708-add-manageconfig.sql new file mode 100644 index 00000000000..28ea635500c --- /dev/null +++ b/.erda/migrations/cluster-manager/20210708-add-manageconfig.sql @@ -0,0 +1,2 @@ +-- add manage config field to store cluster credential info +ALTER TABLE co_clusters ADD COLUMN `manage_config` text NOT NULL COMMENT "cluster crendtial config"; \ No newline at end of file diff --git a/.erda/migrations/ops/20210528-ops-base.sql b/.erda/migrations/cmp/20210528-cmp-base.sql similarity index 100% rename from .erda/migrations/ops/20210528-ops-base.sql rename to .erda/migrations/cmp/20210528-cmp-base.sql diff --git a/apistructs/cluster.go b/apistructs/cluster.go index bf78d93f773..a270064f5c4 100644 --- a/apistructs/cluster.go +++ b/apistructs/cluster.go @@ -99,6 +99,12 @@ type ClusterUpdateRequest struct { URLs map[string]string `json:"urls"` } +type CMPClusterUpdateRequest struct { + ClusterUpdateRequest + CredentialType string `json:"credentialType"` + Credential ICCredential `json:"credential"` +} + // ClusterUpdateResponse 集群更新响应 type ClusterUpdateResponse struct { Header @@ -324,10 +330,14 @@ type DereferenceClusterResponse struct { } type ManageConfig struct { - Type string `json:"type"` - Address string `json:"address"` - CaData string `json:"caData"` - CertData string `json:"certData"` - KeyData string `json:"keyData"` - Token string `json:"token"` + // manage type, support proxy,token,cert + Type string `json:"type"` + Address string `json:"address"` + CaData string `json:"caData"` + CertData string `json:"certData"` + KeyData string `json:"keyData"` + Token string `json:"token"` + AccessKey string `json:"accessKey"` + // credential content from, support kubeconfig, serviceAccount + CredentialSource string `json:"credentialSource"` } diff --git a/apistructs/cmp.go b/apistructs/cmp.go index d62dee96d63..62a07029c8c 100644 --- a/apistructs/cmp.go +++ b/apistructs/cmp.go @@ -19,6 +19,7 @@ import ( const ( AddNodesEssSource = "ess-autoscale" + ComClusterKey = "DICE_CLUSTER_NAME" ) type AddNodesRequest struct { @@ -1580,3 +1581,36 @@ type CloudAccountResponse struct { Header Data CloudAccount `json:"data"` } + +// ImportCluster cluster import request body +type ImportCluster struct { + ClusterName string `json:"name"` + ScheduleConfig ClusterSchedConfig `json:"scheduler"` + Credential ICCredential `json:"credential"` + CredentialType string `json:"credentialType"` + OrgID uint64 `json:"orgId"` + ClusterType string `json:"type"` + WildcardDomain string `json:"wildcardDomain"` + DisplayName string `json:"displayName"` + Description string `json:"description"` +} + +// ICCredential import cluster credential +type ICCredential struct { + Address string `json:"address"` + Content string `json:"content"` +} + +type ImportClusterResponse struct { + Header + Data string `json:"data"` +} + +type ClusterInitRetry struct { + ClusterName string `json:"clusterName"` +} + +type InitClusterResponse struct { + Header + Data string `json:"data"` +} diff --git a/apistructs/cmp_cloud_resource.go b/apistructs/cmp_cloud_resource.go index b5e75c20b9b..e088aa6575b 100644 --- a/apistructs/cmp_cloud_resource.go +++ b/apistructs/cmp_cloud_resource.go @@ -188,14 +188,14 @@ type CloudClusterNewCreateInfo struct { CloudBasicRsc string // ecs\ack // 云环境vpc配置信息 - Region string `json:"region"` //区域 - ClusterType string `json:"clusterType" default:"Edge"` //集群类型,默认边缘集群 - ClusterSpec ClusterSpec `json:"clusterSpec" default:"Standard"` //集群规格,Standard, Small, Test - ChargeType string `json:"chargeType" default:"PrePaid"` //付费类型,PrePaid, PostPaid - ChargePeriod int `json:"chargePeriod" default:"1"` //付费周期 - AppNodeNum int `json:"appNodeNum" default:"-1"` //平台节点数 - AccessKey string `json:"accessKey"` - SecretKey string `json:"secretKey"` + Region string `json:"region"` //区域 + ClusterType string `json:"clusterType" default:"Edge"` //集群类型,默认边缘集群 + ClusterSpec ClusterSpecification `json:"clusterSpec" default:"Standard"` //集群规格,Standard, Small, Test + ChargeType string `json:"chargeType" default:"PrePaid"` //付费类型,PrePaid, PostPaid + ChargePeriod int `json:"chargePeriod" default:"1"` //付费周期 + AppNodeNum int `json:"appNodeNum" default:"-1"` //平台节点数 + AccessKey string `json:"accessKey"` + SecretKey string `json:"secretKey"` // 从已有vpc创建,指定该值;否则新建vpc,指定VpcCIDR VpcID string `json:"vpcID"` VpcCIDR string `json:"vpcCIDR"` @@ -298,15 +298,15 @@ const ( NasSpec = "1TB" ) -type ClusterSpec string +type ClusterSpecification string const ( - ClusterSpecStandard ClusterSpec = "Standard" - ClusterSpecSmall ClusterSpec = "Small" - ClusterSpecTest ClusterSpec = "Test" + ClusterSpecStandard ClusterSpecification = "Standard" + ClusterSpecSmall ClusterSpecification = "Small" + ClusterSpecTest ClusterSpecification = "Test" ) -func (spec ClusterSpec) GetSpecNum() int { +func (spec ClusterSpecification) GetSpecNum() int { switch spec { case ClusterSpecStandard: return EdgeStandardNum diff --git a/apistructs/erda_operator.go b/apistructs/erda_operator.go new file mode 100644 index 00000000000..444c2d906ae --- /dev/null +++ b/apistructs/erda_operator.go @@ -0,0 +1,98 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package apistructs + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/erda-project/erda/pkg/parser/diceyml" +) + +const ( + ClusterPhaseNone ClusterPhase = "" + ClusterPhaseInitJobs ClusterPhase = "InitJobs" + ClusterPhaseCreating ClusterPhase = "Creating" + ClusterPhaseUpdating ClusterPhase = "Updating" + ClusterPhaseRunning ClusterPhase = "Running" + ClusterPhaseFailed ClusterPhase = "Failed" + ClusterPhasePending ClusterPhase = "Pending" +) + +type ClusterPhase string +type ComponentStatus string +type ClusterSize string + +type DiceClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Items []DiceCluster `json:"items"` +} + +type DiceCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec ClusterSpec `json:"spec"` + Status ClusterStatus `json:"status"` +} + +type ClusterSpec struct { + ResetStatus bool `json:"resetStatus"` + AddonConfigMap string `json:"addonConfigMap"` + ClusterinfoConfigMap string `json:"clusterinfoConfigMap"` + PlatformDomain string `json:"platformDomain"` + CookieDomain string `json:"cookieDomain"` + Size ClusterSize `json:"size"` + DiceCluster string `json:"diceCluster"` + // collector, openapi + MainPlatform map[string]string `json:"mainPlatform"` + // key: dice-service-name(e.g. ui), value: domain + // customDomain: + // ui: dice.terminus.io,*.terminus.io + CustomDomain map[string]string `json:"customDomain"` + // deployment affinity labels for specific dice-service + // key: dice-service-name(e.g. gittar), value: label + // e.g. + // gittar: dice/gittar + CustomAffinity map[string]string `json:"customAffinity"` + + InitJobs diceyml.Object `json:"initJobs"` + + Dice diceyml.Object `json:"dice"` + AddonPlatform diceyml.Object `json:"addonPlatform"` + Gittar diceyml.Object `json:"gittar"` + Pandora diceyml.Object `json:"pandora"` + DiceUI diceyml.Object `json:"diceUI"` + UC diceyml.Object `json:"uc"` + SpotAnalyzer diceyml.Object `json:"spotAnalyzer"` + SpotCollector diceyml.Object `json:"spotCollector"` + SpotDashboard diceyml.Object `json:"spotDashboard"` + SpotFilebeat diceyml.Object `json:"spotFilebeat"` + SpotStatus diceyml.Object `json:"spotStatus"` + SpotTelegraf diceyml.Object `json:"spotTelegraf"` + Tmc diceyml.Object `json:"tmc"` + Hepa diceyml.Object `json:"hepa"` + SpotMonitor diceyml.Object `json:"spotMonitor"` + Fdp diceyml.Object `json:"fdp"` + MeshController diceyml.Object `json:"meshController"` +} +type ClusterStatus struct { + Phase ClusterPhase `json:"phase"` + Conditions []ErdaCondition `json:"conditions"` + Components map[string]ComponentStatus `json:"components"` +} + +type ErdaCondition struct { + Reason string `json:"reason"` + TransitionTime string `json:"transitionTime"` +} diff --git a/apistructs/org.go b/apistructs/org.go index 0c193e0d9f1..93e54c6bdd0 100644 --- a/apistructs/org.go +++ b/apistructs/org.go @@ -228,6 +228,11 @@ type OrgClusterRelationDTOResponse struct { Data []OrgClusterRelationDTO `json:"data"` } +type OrgClusterRelationDTOCreateResponse struct { + Header + Data string `json:"data"` +} + // OrgClusterRelationDTO 企业对应集群关系结构 type OrgClusterRelationDTO struct { ID uint64 `json:"id"` diff --git a/bundle/cluster.go b/bundle/cluster.go index cbcff20a534..b540b932e75 100644 --- a/bundle/cluster.go +++ b/bundle/cluster.go @@ -140,7 +140,7 @@ func (b *Bundle) CreateCluster(req *apistructs.ClusterCreateRequest, header ...h var createResp apistructs.ClusterCreateResponse - q := hc.Post(host).Path("/api/clusters") + q := hc.Post(host).Path("/api/clusters").Header(httputil.InternalHeader, "bundle") if len(header) > 0 { q.Headers(header[0]) } @@ -156,6 +156,18 @@ func (b *Bundle) CreateCluster(req *apistructs.ClusterCreateRequest, header ...h return nil } +func (b *Bundle) CreateClusterWithOrg(userID string, orgID uint64, req *apistructs.ClusterCreateRequest, header ...http.Header) error { + if err := b.CreateCluster(req, header...); err != nil { + return err + } + + if err := b.CreateOrgClusterRelationsByOrg(req.Name, userID, orgID); err != nil { + return err + } + + return nil +} + // PatchCluster patch cluster with event func (b *Bundle) PatchCluster(req *apistructs.ClusterPatchRequest, header ...http.Header) error { host, err := b.urls.ClusterManager() diff --git a/bundle/org.go b/bundle/org.go index 6cd74abe856..e39c16f4d5d 100644 --- a/bundle/org.go +++ b/bundle/org.go @@ -350,3 +350,40 @@ func (b *Bundle) DereferenceCluster(orgID uint64, clusterName, userID string) (s } return resp.Data, nil } + +// CreateOrgClusterRelationsByOrg create orgClusters relation by orgID +func (b *Bundle) CreateOrgClusterRelationsByOrg(clusterName string, userID string, orgID uint64) error { + host, err := b.urls.CoreServices() + if err != nil { + return err + } + hc := b.hc + + org, err := b.GetOrg(orgID) + if err != nil { + return err + } + + var createResp apistructs.OrgClusterRelationDTOCreateResponse + + req := &apistructs.OrgClusterRelationCreateRequest{ + OrgID: orgID, + OrgName: org.Name, + ClusterName: clusterName, + } + + resp, err := hc.Post(host).Path("/api/orgs/actions/relate-cluster"). + Header(httputil.UserHeader, userID). + JSONBody(req). + Do(). + JSON(&createResp) + + if err != nil { + return apierrors.ErrInvoke.InternalError(err) + } + if !resp.IsOK() || !createResp.Success { + return toAPIError(resp.StatusCode(), createResp.Error) + } + + return nil +} diff --git a/cmd/cluster-init/main.go b/cmd/cluster-init/main.go new file mode 100644 index 00000000000..bb41ca2131a --- /dev/null +++ b/cmd/cluster-init/main.go @@ -0,0 +1,24 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +import ( + "github.com/erda-project/erda-infra/modcom" + _ "github.com/erda-project/erda-infra/providers" + _ "github.com/erda-project/erda/modules/cluster-init" +) + +func main() { + modcom.RunWithCfgDir("conf/cluster-init", "cluster-init") +} diff --git a/conf/cluster-init/cluster-init.yaml b/conf/cluster-init/cluster-init.yaml new file mode 100644 index 00000000000..059841a29b5 --- /dev/null +++ b/conf/cluster-init/cluster-init.yaml @@ -0,0 +1 @@ +cluster-init: diff --git a/erda.yml b/erda.yml index 0121838e3a9..09fdcdd3aee 100644 --- a/erda.yml +++ b/erda.yml @@ -506,6 +506,9 @@ services: exec: {} cmp: cmd: "/app/cmp" + envs: + UC_CLIENT_ID: "dice" + UC_CLIENT_SECRET: "secret" ports: - port: 9027 protocol: "TCP" diff --git a/go.mod b/go.mod index 97f26e3595e..4cb6d694546 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/clbanning/mxj v1.8.4 // indirect github.com/cockroachdb/apd v1.1.0 // indirect github.com/confluentinc/confluent-kafka-go v1.5.2 - github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa + github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 github.com/coreos/etcd v3.3.25+incompatible github.com/creack/pty v1.1.11 // indirect github.com/davecgh/go-spew v1.1.1 @@ -59,6 +59,7 @@ require ( github.com/go-sql-driver/mysql v1.5.0 github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a // indirect github.com/gocql/gocql v0.0.0-20210401103645-80ab1e13e309 + github.com/gofrs/flock v0.7.1 github.com/gofrs/uuid v4.0.0+incompatible github.com/gogap/errors v0.0.0-20200228125012-531a6449b28c github.com/gogap/stack v0.0.0-20150131034635-fef68dddd4f8 // indirect @@ -85,7 +86,6 @@ require ( github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect - github.com/lib/pq v1.3.0 // indirect github.com/libgit2/git2go/v30 v30.0.5 github.com/magiconair/properties v1.8.4 github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 @@ -152,10 +152,12 @@ require ( gorm.io/driver/mysql v1.0.5 gorm.io/gorm v1.21.8 gotest.tools v2.2.0+incompatible + helm.sh/helm/v3 v3.3.4 howett.net/plist v0.0.0-20201203080718-1454fab16a06 istio.io/api v0.0.0-20200715212100-dbf5277541ef istio.io/client-go v0.0.0-20201005161859-d8818315d678 k8s.io/api v0.19.1 + k8s.io/apiextensions-apiserver v0.18.8 k8s.io/apimachinery v0.19.1 k8s.io/client-go v12.0.0+incompatible k8s.io/kubernetes v1.18.3 diff --git a/go.sum b/go.sum index 425dd89541d..93021b0fbd7 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI= bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA= @@ -42,9 +43,12 @@ contrib.go.opencensus.io/exporter/stackdriver v0.0.0-20180421005815-665cf5131b71 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2 h1:MHu5KWWt28FzRGQgc4Ryj/lZT/W/by4NvsnstbWwkkY= github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2/go.mod h1:xc0ybJZXcn084ZaIvQv+LfCDQjMWfxkBa2K9nLXYJtI= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -63,6 +67,7 @@ github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4s github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet v2.1.2+incompatible h1:ybZoYzMBdoijK6I+Ke3vg9GZsmlKo/ZhKdNMWz0P26c= github.com/CloudyKit/jet v2.1.2+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20180321230639-1e456b1c68cb/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= github.com/GoogleCloudPlatform/spark-on-k8s-operator v0.0.0-20201215015655-2e8b733f5ad0 h1:80ikPib6BMEtsQb1nXUNXlY120WQvSam1HZrmMcJo8A= @@ -74,14 +79,25 @@ github.com/Jeffail/gabs v0.0.0-20180420203615-7a0fed31069a/go.mod h1:6xMvQMK4k33 github.com/Jeffail/gabs/v2 v2.5.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y= github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= +github.com/Masterminds/squirrel v1.4.0 h1:he5i/EXixZxrBUWcxzDYMiju9WZ3ld/l7QBNuo/eN3w= +github.com/Masterminds/squirrel v1.4.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= @@ -95,6 +111,7 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= @@ -157,9 +174,12 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.13.20/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.20.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.26.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -178,6 +198,7 @@ github.com/bazelbuild/buildtools v0.0.0-20190731111112-f720930ceb60/go.mod h1:5J github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= github.com/bazelbuild/rules_go v0.0.0-20190719190356-6dae44dc5cab/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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= @@ -186,8 +207,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= @@ -201,8 +224,12 @@ github.com/bndr/gotabulate v1.1.2/go.mod h1:0+8yUgaPTtLRTjf49E8oju7ojpU11YmXyvq1 github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/brancz/gojsontoyaml v0.0.0-20190425155809-e8bd32d46b3d/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/caarlos0/env v0.0.0-20180521112546-3e0f30cbf50b h1:v4t6ud4qRFWQj2PJFZrsao8F2JzesOabZc+ttozY4To= @@ -250,9 +277,23 @@ github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hj github.com/confluentinc/confluent-kafka-go v1.5.2 h1:l+qt+a0Okmq0Bdr1P55IX4fiwFJyg0lZQmfHkAFkv7E= github.com/confluentinc/confluent-kafka-go v1.5.2/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg= github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa h1:GnRy2maqb8vcJhYRN5L+5WyYNKfUG4otiz2zxE182ng= github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.4 h1:3o0smo5SKY7H6AJCmJhsnCjR2/V2T8VmiHt7seN2/kI= +github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coredns/corefile-migration v1.0.6/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E= @@ -288,6 +329,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= +github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cznic/golex v0.0.0-20181122101858-9c343928389c/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= @@ -306,12 +348,17 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/deislabs/oras v0.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c= +github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE= github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 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-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= @@ -320,11 +367,25 @@ github.com/dgryski/go-gk v0.0.0-20140819190930-201884a44051/go.mod h1:qm+vckxRlD github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v0.0.0-20180504081357-f8a7e8b9c630/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492 h1:FwssHbCDJD025h+BchanCwE1Q8fyMgqDr2mOQAWOLGw= +github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce h1:KXS1Jg+ddGcWA8e1N7cupxaHHZhit5rB9tfDU+mfjyY= +github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 h1:yWHOI+vFjEsAakUTSrtqc/SAHrhSkmn48pqjidZX3QA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= @@ -361,9 +422,14 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erda-project/elastic v0.0.1-ex h1:5ajfxQ5S5YjpzFqY9LzL9hiKWCn6q/JDT4n8sNv7+pU= github.com/erda-project/elastic v0.0.1-ex/go.mod h1:iAVsas6fcmt9pxtge1+dErMhecv+RLSXlD4rnZRJVW0= +github.com/erda-project/erda-infra v0.0.0-20210706133120-0a742437972c h1:1gSrsrIMk3sFDKZzxkI0yoz5Oif/BlD81akW/oev5B4= github.com/erda-project/erda-infra v0.0.0-20210706133120-0a742437972c/go.mod h1:TUQYSZ60w9dk7m0q3U3AVg7U74APj/sdEVvRWR3wYv8= github.com/erda-project/erda-infra v0.0.0-20210707114154-26659d826a1c h1:9T5OxyzFTkQGIkgaRtjtbipg9qsCXK9hdzNjbZ3xlqI= github.com/erda-project/erda-infra v0.0.0-20210707114154-26659d826a1c/go.mod h1:TUQYSZ60w9dk7m0q3U3AVg7U74APj/sdEVvRWR3wYv8= +github.com/erda-project/erda-proto-go v0.0.0-20210707034815-0df3817e79d2 h1:eODGKKUD6vfgi1DZjs/fTyrXceAOQA6bLRL9BrDqxfM= +github.com/erda-project/erda-proto-go v0.0.0-20210707034815-0df3817e79d2/go.mod h1:3p+zdizZPn3d0qq5y1GjNRP31Jd3mIvqN4809cldvN4= +github.com/erda-project/erda-proto-go v0.0.0-20210708033407-be5e2b8296b9 h1:9seVeJu3LvTCdZxMobbRR2mARXwJt7wQSzjfUhNnDlY= +github.com/erda-project/erda-proto-go v0.0.0-20210708033407-be5e2b8296b9/go.mod h1:3p+zdizZPn3d0qq5y1GjNRP31Jd3mIvqN4809cldvN4= github.com/erda-project/erda-proto-go v0.0.0-20210708055220-ccccc409ea19 h1:TPax3PKFuWdsWZzIFR1WMR3QyVt3bFecYwV6gYs59nc= github.com/erda-project/erda-proto-go v0.0.0-20210708055220-ccccc409ea19/go.mod h1:3p+zdizZPn3d0qq5y1GjNRP31Jd3mIvqN4809cldvN4= github.com/erda-project/influxql v1.1.0-ex h1:NgP5+S5Qo234IVSIJ3N/egvzCNYJURfMAett3e8a9LE= @@ -373,9 +439,11 @@ github.com/erda-project/remotedialer v0.2.6-0.20210618084817-52c879aadbcb/go.mod github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/extrame/ole2 v0.0.0-20160812065207-d69429661ad7 h1:n+nk0bNe2+gVbRI8WRbLFVwwcBQ0rr5p+gzkKb6ol8c= github.com/extrame/ole2 v0.0.0-20160812065207-d69429661ad7/go.mod h1:GPpMrAfHdb8IdQ1/R2uIRBsNfnPnwsYE9YYI5WyY1zw= @@ -410,6 +478,7 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsouza/fake-gcs-server v1.15.0/go.mod h1:HNxAJ/+FY/XSsxuwz8iIYdp2GtMmPbJ8WQjjGMxd6Qk= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/getkin/kin-openapi v0.49.0 h1:nKSq662fS0kZ11+Wu3FLg3GQGL0UuH1VxF8wV1QuDEU= @@ -439,6 +508,7 @@ github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+s 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-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ini/ini v1.37.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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= @@ -558,8 +628,14 @@ github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-graphviz v0.0.5/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk= github.com/gocql/gocql v0.0.0-20200131111108-92af2e088537/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= @@ -567,6 +643,10 @@ github.com/gocql/gocql v0.0.0-20210313142353-65899a66288b/go.mod h1:DL0ekTmBSTdl github.com/gocql/gocql v0.0.0-20210401103645-80ab1e13e309 h1:8MHuCGYDXh0skFrLumkCMlt9C29hxhqNx39+Haemeqw= github.com/gocql/gocql v0.0.0-20210401103645-80ab1e13e309/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= +github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc= +github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= 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/gogap/errors v0.0.0-20200228125012-531a6449b28c h1:dM8T2g87Kj9PBQjpstkQ20ZQjzrpZJwMwueX8mllrDI= @@ -715,10 +795,13 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -732,7 +815,10 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/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.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= @@ -752,6 +838,7 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -760,6 +847,7 @@ github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9 github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 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 v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= @@ -796,6 +884,7 @@ github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7U github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hypnoglow/gormzap v0.3.0/go.mod h1:5Wom8B7Jl2oK0Im9hs6KQ+Kl92w4Y7gKCrj66rhyvw0= @@ -835,12 +924,16 @@ github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 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/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -911,6 +1004,10 @@ github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8 github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= @@ -921,12 +1018,17 @@ github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgU github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8= github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc= github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= +github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libgit2/git2go/v30 v30.0.5 h1:gxKqXOslpvYDZNC62f8GV34TAk0qw4wZ++IdYw8V9I4= github.com/libgit2/git2go/v30 v30.0.5/go.mod h1:YReiQ7xhMoyAL4ISYFLZt+OGqn6xtLqvTC1xJ9oAH7Y= github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= @@ -954,6 +1056,7 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -971,6 +1074,7 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -978,7 +1082,10 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -1005,6 +1112,7 @@ github.com/minio/minio-go v0.0.0-20190308013636-b32976861da0 h1:yHdN+v8UkkeKXBF7 github.com/minio/minio-go v0.0.0-20190308013636-b32976861da0/go.mod h1:/haSOWG8hQNx2+JOfLJ9GKp61EAmgPwRVw/Sac0NzaM= github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1012,6 +1120,7 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= @@ -1021,6 +1130,8 @@ github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= @@ -1036,6 +1147,7 @@ github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb/go.mod h1:wL8QJ github.com/montanaflynn/stats v0.0.0-20180911141734-db72e6cae808/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.5.0 h1:2EkzeTSqBB4V4bJwWrt5gIIrZmpJBcoIRGS2kWLgzmk= github.com/montanaflynn/stats v0.5.0/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= @@ -1060,6 +1172,7 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/ncw/swift v1.0.49/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7 h1:7KAv7KMGTTqSmYZtNdcNTgsos+vFzULLwyElndwn+5c= @@ -1078,7 +1191,9 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olivere/env v1.1.0/go.mod h1:zaoXy53SjZfxqZBGiGrZCkuVLYPdwrc+vArPuUVhJdQ= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -1104,10 +1219,21 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc10 h1:AbmCEuSZXVflng0/cboQkpdEOeBsPMjz6tmq4Pv8MZw= github.com/opencontainers/runc v1.0.0-rc10/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= @@ -1146,6 +1272,7 @@ github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d h1:U+PMnTlV2tu7RuMK5etusZG3Cf+rpow5hqQByeCzJ2g= github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d/go.mod h1:lXfE4PvvTW5xOjO6Mba8zDPyw8M93B6AQ7frTGnMlA8= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= @@ -1237,6 +1364,7 @@ github.com/pingcap/tipb v0.0.0-20200522051215-f31a15d98fce/go.mod h1:RtkHW8WbcNx github.com/pingcap/tipb v0.0.0-20200618092958-4fad48b4c8c3 h1:ESL3eIt1kUt8IMvR1011ejZlAyDcOzw89ARvVHvpD5k= github.com/pingcap/tipb v0.0.0-20200618092958-4fad48b4c8c3/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/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= @@ -1250,6 +1378,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -1263,6 +1392,7 @@ github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1270,6 +1400,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/client_model v0.1.0/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-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1281,6 +1412,7 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1288,6 +1420,7 @@ github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7z 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.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= @@ -1323,7 +1456,11 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= @@ -1370,6 +1507,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20181020040650-a97a25d856ca/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -1404,7 +1542,9 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -1415,6 +1555,7 @@ github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1: github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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= @@ -1451,6 +1592,7 @@ github.com/swaggo/swag v1.6.3/go.mod h1:wcc83tB4Mb2aNiL/HP4MFeQdpHUrca+Rp/DRNgWA github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/swaggo/swag v1.6.6-0.20200323071853-8e21f4cefeea/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/swaggo/swag v1.6.6-0.20200529100950-7c765ddd0476/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.1-0.20190625010220-02440ea7a285 h1:uSDYjYejelKyceA6DiCsngFof9jAyeaSyX9XC5a1a7Q= @@ -1524,6 +1666,7 @@ github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -1550,6 +1693,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -1576,6 +1720,9 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= @@ -1638,6 +1785,7 @@ go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190927031335-2835ba2e683f/go.mod h1:fYw7AShPAhGMdXqA9gRadk/CcMsvLlClpE5oBwnS3dM= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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= @@ -1656,10 +1804,12 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1735,6 +1885,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/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= @@ -1818,6 +1969,9 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1827,6 +1981,7 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1922,6 +2077,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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= @@ -1978,13 +2134,12 @@ gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJ gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e h1:jRyg0XfpwWlhEV8mDfdNGBeSJM2fuyh9Yjrnd8kF2Ts= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180606215403-8e9de5a6de6d/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -2014,6 +2169,7 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180627194029-ff3583edef7d/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -2076,6 +2232,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/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= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= @@ -2095,6 +2252,8 @@ gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/R gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/igm/sockjs-go.v2 v2.0.0 h1:NfDyi1jrF9v2VOPESefhKH1NRqpoE9tp4v6kxVR3ubs= gopkg.in/igm/sockjs-go.v2 v2.0.0/go.mod h1:xvdpHZ3OpjP0TzQzl+174DglrrnYZKVd6qHPIX20Z1Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -2147,6 +2306,8 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +helm.sh/helm/v3 v3.3.4 h1:tbad6WQVMxEw1HlVBvI2rQqOblmI5lgXOrWAMwJ198M= +helm.sh/helm/v3 v3.3.4/go.mod h1:CyCGQa53/k1JFxXvXveGwtfJ4cuB9zkaBSGa5rnAiHU= 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= @@ -2172,12 +2333,14 @@ k8s.io/apiextensions-apiserver v0.18.3/go.mod h1:TMsNGs7DYpMXd+8MOCX8KzPOCx8fnZM k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk= k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apiserver v0.18.3/go.mod h1:tHQRmthRPLUtwqsOnJJMoI8SW3lnoReZeE861lH8vUw= +k8s.io/cli-runtime v0.18.3 h1:8IBtaTYmXiXipKdx2FAKotvnQMjcF0kSLvX4szY340c= k8s.io/cli-runtime v0.18.3/go.mod h1:pqbbi4nqRIQhUWAVzen8uE8DD/zcZLwf+8sQYO4lwLk= k8s.io/client-go v0.18.3 h1:QaJzz92tsN67oorwzmoB0a9r9ZVHuD5ryjbCKP0U22k= k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= k8s.io/cloud-provider v0.18.3/go.mod h1:sZelqNhA+TI+FqV6smLvZ84/DQCNdrEUmdQLneZpfC4= k8s.io/cluster-bootstrap v0.18.3/go.mod h1:iM3iptIPGNWCvFBvm67JJWaFdYb+7Gzle2bj125ZBy8= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/component-base v0.18.3 h1:QXq+P4lgi4LCIREya1RDr5gTcBaVFhxEcALir3QCSDA= k8s.io/component-base v0.18.3/go.mod h1:bp5GzGR0aGkYEfTj+eTY0AN/vXTgkJdQXjNTTVUaa3k= k8s.io/cri-api v0.18.3/go.mod h1:OJtpjDvfsKoLGhvcc0qfygved0S0dGX56IJzPbqTG1s= k8s.io/csi-translation-lib v0.18.3/go.mod h1:4UtVGtxPzhtFdadhRCYBL084NvJLNMouCat3UcTbbu0= @@ -2196,6 +2359,7 @@ k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOEC k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-proxy v0.18.3/go.mod h1:Uyqd3mVXhJeNzTmZYW/6N00Bu3kVJ6jzLQQ/T7f8jY0= k8s.io/kube-scheduler v0.18.3/go.mod h1:55V1fgqzVXEDJB/zkBYjVceixZFQVOVWZwfLrnXt3yA= +k8s.io/kubectl v0.18.3 h1:WvlO1MQvteqrpoX1SgYf5TZ+ofTGvdkhoNELzc2EBkQ= k8s.io/kubectl v0.18.3/go.mod h1:k/EpvXBDgEsHBzWr0A44l9+ArvYi3txBBnzXBjQasUQ= k8s.io/kubelet v0.18.3/go.mod h1:KXTAte7pUtoMyIlysam9g6HIY8C+D5Djd4fZvGXqLtg= k8s.io/kubernetes v1.18.3 h1:6qtm8v3z+OwYm2SnsTxYUtGCsIbGBZ/Dh9yER+aNIoI= @@ -2237,6 +2401,7 @@ sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKG sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvOk9NM= sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= sigs.k8s.io/controller-tools v0.2.5/go.mod h1:+t0Hz6tOhJQCdd7IYO0mNzimmiM9sqMU0021u6UCF2o= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/sig-storage-lib-external-provisioner/v6 v6.3.0 h1:IKsKAnscMyIOqyl8s8V7guTcx0QBEa6OT57EPgAgpmM= sigs.k8s.io/sig-storage-lib-external-provisioner/v6 v6.3.0/go.mod h1:DhZ52sQMJHW21+JXyA2LRUPRIxKnrNrwh+QFV+2tVA4= @@ -2251,7 +2416,6 @@ sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20180531100431-4c381bd170b4/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 h1:e1sMhtVq9AfcEy8AXNb8eSg6gbzfdpYhoNqnPJa+GzI= sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/modules/admin/manager/cluster.go b/modules/admin/manager/cluster.go index ce1ab6a9f0e..9c57e489620 100644 --- a/modules/admin/manager/cluster.go +++ b/modules/admin/manager/cluster.go @@ -63,6 +63,12 @@ func (am *AdminManager) ListCluster(ctx context.Context, req *http.Request, reso newClusters := []apistructs.ClusterInfo{} for _, cluster := range clusters { + if cluster.ManageConfig != nil { + cluster.ManageConfig = &apistructs.ManageConfig{ + CredentialSource: cluster.ManageConfig.CredentialSource, + Address: cluster.ManageConfig.Address, + } + } for _, relate := range clusterRelation { if relate.ClusterID == uint64(cluster.ID) { cluster.IsRelation = "Y" diff --git a/modules/cluster-init/client/client.go b/modules/cluster-init/client/client.go new file mode 100644 index 00000000000..5e7fbb971d0 --- /dev/null +++ b/modules/cluster-init/client/client.go @@ -0,0 +1,165 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package client + +import ( + "fmt" + "strings" + + "github.com/sirupsen/logrus" + "helm.sh/helm/v3/pkg/repo" + + "github.com/erda-project/erda/bundle" + "github.com/erda-project/erda/modules/cluster-init/config" + erdahelm "github.com/erda-project/erda/pkg/helm" + kc "github.com/erda-project/erda/pkg/k8sclient/config" +) + +const ( + defaultRepoName = "stable" + InstallModeRemote = "REMOTE" + RepoModeRemote = "REMOTE" + RepoModeLocal = "LOCAL" + LocalRepoPath = "/app/charts" + ErdaBaseCharts = "erda-base" + ErdaAddonsCharts = "erda-addons" + ErdaCharts = "erda" +) + +type Option func(client *Client) + +type Client struct { + config *config.Config +} + +func New(opts ...Option) *Client { + c := Client{} + for _, op := range opts { + op(&c) + } + + return &c +} + +func WithConfig(cfg *config.Config) Option { + return func(c *Client) { + c.config = cfg + } +} + +func (c *Client) Execute() error { + logrus.Debugf("load config: %+v", c.config) + + opts, err := c.newHelmClientOptions() + if err != nil { + return fmt.Errorf("get helm client error: %v", err) + } + + hc, err := erdahelm.New(opts...) + if err != nil { + return err + } + + switch strings.ToUpper(c.config.RepoMode) { + case RepoModeRemote: + // TODO: support repo auth info. + e := &repo.Entry{Name: defaultRepoName, URL: c.config.RepoURL} + + if err = hc.AddOrUpdateRepo(e); err != nil { + return err + } + } + + if c.config.Reinstall { + charts := c.getInitCharts() + for _, chart := range charts { + chart.Action = erdahelm.ActionUninstall + } + m := erdahelm.Manager{ + HelmClient: hc, + Charts: charts, + LocalRepoName: defaultRepoName, + } + + if err := m.Execute(); err != nil { + return err + } + } + + m := erdahelm.Manager{ + HelmClient: hc, + Charts: c.getInitCharts(), + LocalRepoName: defaultRepoName, + } + + if err := m.Execute(); err != nil { + return err + } + + return nil +} + +// newHelmClientOptions create helm client options +func (c *Client) newHelmClientOptions() ([]erdahelm.Option, error) { + opts := make([]erdahelm.Option, 0) + + switch strings.ToUpper(c.config.InstallMode) { + case InstallModeRemote: + b := bundle.New(bundle.WithClusterManager()) + cluster, err := b.GetCluster(c.config.TargetCluster) + if err != nil { + return nil, err + } + + rc, err := kc.ParseManageConfig(c.config.TargetCluster, cluster.ManageConfig) + if err != nil { + return nil, err + } + + opts = append(opts, erdahelm.WithRESTClientGetter(erdahelm.NewRESTClientGetterImpl(rc))) + } + + switch strings.ToUpper(c.config.RepoMode) { + case RepoModeLocal: + opts = append(opts, erdahelm.WithLocalChartDiscoverDir(LocalRepoPath)) + } + + return opts, nil +} + +func (c *Client) getInitCharts() []*erdahelm.ChartSpec { + return []*erdahelm.ChartSpec{ + { + ReleaseName: ErdaBaseCharts, + ChartName: ErdaBaseCharts, + Version: c.config.Version, + Action: erdahelm.ActionInstall, + Values: c.config.ErdaBaseValues, + }, + { + ReleaseName: ErdaAddonsCharts, + ChartName: ErdaAddonsCharts, + Version: c.config.Version, + Action: erdahelm.ActionInstall, + Values: c.config.ErdaAddonsValues, + }, + { + ReleaseName: ErdaCharts, + ChartName: ErdaCharts, + Version: c.config.Version, + Action: erdahelm.ActionInstall, + Values: c.config.ErdaValues, + }, + } +} diff --git a/modules/cluster-init/config/config.go b/modules/cluster-init/config/config.go new file mode 100644 index 00000000000..e01f08c3e09 --- /dev/null +++ b/modules/cluster-init/config/config.go @@ -0,0 +1,31 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package config + +type Config struct { + Debug bool `env:"DEBUG" default:"false" desc:"enable debug logging"` + RepoURL string `env:"HELM_REPO_URL" desc:"helm repo url"` + Reinstall bool `env:"REINSTALL" desc:"reinstall erda comp"` + Version string `env:"ERDA_CHART_VERSION" desc:"erda chart version"` + InstallMode string `env:"INSTALL_MODE" desc:"install mode, remote or local"` + RepoMode string `env:"REPO_MODE" desc:"get chart mode, download or use build in charts"` + TargetCluster string `env:"TARGET_CLUSTER" desc:"special when CREDENTIAL_FROM=CLUSTER_MANAGER"` + ErdaBaseValues string `env:"ERDA_BASE_VALUES" desc:"provide erda base values"` + ErdaAddonsValues string `env:"ERDA_ADDONS_VALUES" desc:"provide erda addons values"` + ErdaValues string `env:"ERDA_VALUES" desc:"provide erda values"` + // HELM_NAMESPACE: helm deploy namespace + // HELM_REPO_URL: helm repo address + // HELM_REPOSITORY_CONFIG: helm repository store path + // HELM_REPOSITORY_CACHE: helm charts cache path +} diff --git a/modules/cluster-init/provider.go b/modules/cluster-init/provider.go new file mode 100644 index 00000000000..dbfaecdd7bb --- /dev/null +++ b/modules/cluster-init/provider.go @@ -0,0 +1,53 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cluster_dialer + +import ( + "context" + + "github.com/sirupsen/logrus" + + "github.com/erda-project/erda-infra/base/servicehub" + "github.com/erda-project/erda/modules/cluster-init/client" + "github.com/erda-project/erda/modules/cluster-init/config" +) + +type provider struct { + Cfg *config.Config +} + +func (p *provider) Init(ctx servicehub.Context) error { + if p.Cfg.Debug { + logrus.SetLevel(logrus.DebugLevel) + } + return nil +} + +func (p *provider) Run(ctx context.Context) error { + c := client.New(client.WithConfig(p.Cfg)) + return c.Execute() +} + +func init() { + servicehub.Register("cluster-init", &servicehub.Spec{ + Services: []string{"cluster-init"}, + Description: "cluster init", + ConfigFunc: func() interface{} { + return &config.Config{} + }, + Creator: func() servicehub.Provider { + return &provider{} + }, + }) +} diff --git a/modules/cluster-manager/services/apierrors/errors.go b/modules/cluster-manager/services/apierrors/errors.go index c958a11de90..a58992f232a 100644 --- a/modules/cluster-manager/services/apierrors/errors.go +++ b/modules/cluster-manager/services/apierrors/errors.go @@ -25,6 +25,7 @@ var ( ErrGetCluster = err("ErrGetCluster", "failed to get cluster") ErrListCluster = err("ErrListCluster", "failed to list cluster") ErrDeleteCluster = err("ErrDeleteCluster", "failed to delete cluster") + ErrGetClusterInfo = err("ErrGetClusterInfo", "failed to get cluster info") ) func err(template, defaultValue string) *errorresp.APIError { diff --git a/modules/cluster-manager/services/cluster/cluster.go b/modules/cluster-manager/services/cluster/cluster.go index c4cea06ae4c..91ed676d62b 100644 --- a/modules/cluster-manager/services/cluster/cluster.go +++ b/modules/cluster-manager/services/cluster/cluster.go @@ -273,6 +273,10 @@ func (c *Cluster) PatchWithEvent(req *apistructs.ClusterPatchRequest) error { return nil } + cCluster := c.convert(cluster) + + req.ManageConfig.CredentialSource = cCluster.ManageConfig.CredentialSource + manageConfig, err := json.MarshalIndent(req.ManageConfig, "", "\t") if err != nil { return err diff --git a/modules/cmp/conf/conf.go b/modules/cmp/conf/conf.go index 0b58b0f9999..f3a90ad7345 100644 --- a/modules/cmp/conf/conf.go +++ b/modules/cmp/conf/conf.go @@ -22,13 +22,28 @@ import ( // Conf Define the configuration type Conf struct { - Debug bool `env:"DEBUG" default:"false"` - EnableEss bool `env:"ENABLE_ESS" default:"false"` - ListenAddr string `env:"LISTEN_ADDR" default:":9027"` - SoldierAddr string `env:"SOLDIER_ADDR"` - SchedulerAddr string `env:"SCHEDULER_ADDR"` - TaskSyncDuration time.Duration `env:"TASK_SYNC_DURATION" default:"2h"` - TaskCleanDuration time.Duration `env:"TASK_CLEAN_DURATION" default:"24h"` + Debug bool `env:"DEBUG" default:"false"` + EnableEss bool `env:"ENABLE_ESS" default:"false"` + ListenAddr string `env:"LISTEN_ADDR" default:":9027"` + SoldierAddr string `env:"SOLDIER_ADDR"` + SchedulerAddr string `env:"SCHEDULER_ADDR"` + TaskSyncDuration time.Duration `env:"TASK_SYNC_DURATION" default:"2h"` + TaskCleanDuration time.Duration `env:"TASK_CLEAN_DURATION" default:"24h"` + LocalMode bool `env:"LOCAL_MODE" default:"false"` + RedisMasterName string `default:"my-master" env:"REDIS_MASTER_NAME"` + RedisSentinelAddrs string `default:"" env:"REDIS_SENTINELS_ADDR"` + RedisAddr string `default:"127.0.0.1:6379" env:"REDIS_ADDR"` + RedisPwd string `default:"anywhere" env:"REDIS_PASSWORD"` + UCClientID string `env:"UC_CLIENT_ID"` + UCClientSecret string `env:"UC_CLIENT_SECRET"` + // ory/kratos config + OryEnabled bool `default:"false" env:"ORY_ENABLED"` + OryKratosAddr string `default:"kratos:4433" env:"KRATOS_ADDR"` + OryKratosPrivateAddr string `default:"kratos:4434" env:"KRATOS_PRIVATE_ADDR"` + + ErdaNamespace string `default:"erda-system" env:"ERDA_NAMESPACE"` + ErdaHelmChartVersion string `default:"0.1.0" env:"ERDA_HELM_CHART_VERSION"` + ReleaseRepo string `default:"registry.erda.cloud" env:"RELEASE_REPO"` } var cfg Conf @@ -69,3 +84,65 @@ func TaskSyncDuration() time.Duration { func TaskCleanDuration() time.Duration { return cfg.TaskCleanDuration } + +func LocalMode() bool { + return cfg.LocalMode +} + +// RedisMasterName 返回redis master name +func RedisMasterName() string { + return cfg.RedisMasterName +} + +// RedisSentinelAddrs 返回 redis 哨兵地址 +func RedisSentinelAddrs() string { + return cfg.RedisSentinelAddrs +} + +// RedisAddr 返回 redis 地址 +func RedisAddr() string { + return cfg.RedisAddr +} + +// RedisPwd 返回 redis 密码 +func RedisPwd() string { + return cfg.RedisPwd +} + +// UCClientID 返回 UCClientID 选项. +func UCClientID() string { + return cfg.UCClientID +} + +// UCClientSecret 返回 UCClientSecret 选项. +func UCClientSecret() string { + return cfg.UCClientSecret +} + +func OryEnabled() bool { + return cfg.OryEnabled +} + +func OryKratosPrivateAddr() string { + return cfg.OryKratosPrivateAddr +} + +func OryCompatibleClientID() string { + return "kratos" +} + +func OryCompatibleClientSecret() string { + return "" +} + +func ErdaNamespace() string { + return cfg.ErdaNamespace +} + +func ErdaHelmChartVersion() string { + return cfg.ErdaHelmChartVersion +} + +func ReleaseRepo() string { + return cfg.ReleaseRepo +} diff --git a/modules/cmp/dbclient/models.go b/modules/cmp/dbclient/models.go index c3cbe856cf6..6904990a2a1 100644 --- a/modules/cmp/dbclient/models.go +++ b/modules/cmp/dbclient/models.go @@ -22,27 +22,28 @@ import ( type RecordType string const ( - RecordTypeAddNodes RecordType = "addNodes" - RecordTypeAddEssNodes RecordType = "addEssNodes" - RecordTypeAddAliNodes RecordType = "addAliNodes" - RecordTypeRmNodes RecordType = "rmNodes" - RecordTypeDeleteNodes RecordType = "deleteNodes" - RecordTypeDeleteEssNodes RecordType = "deleteEssNodes" - RecordTypeDeleteEssNodesCronJob RecordType = "deleteEssNodesCronJob" - RecordTypeSetLabels RecordType = "setLabels" - RecordTypeAddAliECSECluster RecordType = "addAliECSEdgeCluster" - RecordTypeAddAliACKECluster RecordType = "addAliACKEdgeCluster" // TODO remove - RecordTypeAddAliCSECluster RecordType = "addAliCSEdgeCluster" - RecordTypeAddAliCSManagedCluster RecordType = "addAliCSManagedEdgeCluster" - RecordTypeUpgradeEdgeCluster RecordType = "upgradeEdgeCluster" - RecordTypeOfflineEdgeCluster RecordType = "offlineEdgeCluster" - RecordTypeCreateAliCloudMysql RecordType = "createAliCloudMysql" - RecordTypeCreateAliCloudMysqlDB RecordType = "createAliCloudMysqlDB" - RecordTypeCreateAliCloudRedis RecordType = "createAliCloudRedis" - RecordTypeCreateAliCloudOss RecordType = "createAliCloudOss" - RecordTypeCreateAliCloudOns RecordType = "createAliCloudOns" - RecordTypeCreateAliCloudOnsTopic RecordType = "createAliCloudOnsTopic" - RecordTypeCreateAliCloudGateway RecordType = "createAliCloudGateway" + RecordTypeAddNodes RecordType = "addNodes" + RecordTypeAddEssNodes RecordType = "addEssNodes" + RecordTypeAddAliNodes RecordType = "addAliNodes" + RecordTypeRmNodes RecordType = "rmNodes" + RecordTypeDeleteNodes RecordType = "deleteNodes" + RecordTypeDeleteEssNodes RecordType = "deleteEssNodes" + RecordTypeDeleteEssNodesCronJob RecordType = "deleteEssNodesCronJob" + RecordTypeSetLabels RecordType = "setLabels" + RecordTypeAddAliECSECluster RecordType = "addAliECSEdgeCluster" + RecordTypeAddAliACKECluster RecordType = "addAliACKEdgeCluster" // TODO remove + RecordTypeAddAliCSECluster RecordType = "addAliCSEdgeCluster" + RecordTypeAddAliCSManagedCluster RecordType = "addAliCSManagedEdgeCluster" + RecordTypeImportKubernetesCluster RecordType = "importKubernetesCluster" + RecordTypeUpgradeEdgeCluster RecordType = "upgradeEdgeCluster" + RecordTypeOfflineEdgeCluster RecordType = "offlineEdgeCluster" + RecordTypeCreateAliCloudMysql RecordType = "createAliCloudMysql" + RecordTypeCreateAliCloudMysqlDB RecordType = "createAliCloudMysqlDB" + RecordTypeCreateAliCloudRedis RecordType = "createAliCloudRedis" + RecordTypeCreateAliCloudOss RecordType = "createAliCloudOss" + RecordTypeCreateAliCloudOns RecordType = "createAliCloudOns" + RecordTypeCreateAliCloudOnsTopic RecordType = "createAliCloudOnsTopic" + RecordTypeCreateAliCloudGateway RecordType = "createAliCloudGateway" ) func (r RecordType) String() string { diff --git a/modules/cmp/endpoints/cluster.go b/modules/cmp/endpoints/cluster.go index 06ff4b39639..270b8b2845a 100644 --- a/modules/cmp/endpoints/cluster.go +++ b/modules/cmp/endpoints/cluster.go @@ -26,6 +26,7 @@ import ( "github.com/erda-project/erda/apistructs" "github.com/erda-project/erda/modules/cmp/impl/ess" "github.com/erda-project/erda/pkg/http/httpserver" + "github.com/erda-project/erda/pkg/http/httputil" "github.com/erda-project/erda/pkg/strutil" ) @@ -191,7 +192,6 @@ func (e *Endpoints) OfflineEdgeCluster(ctx context.Context, r *http.Request, var }, }) } - // permission check p := apistructs.PermissionCheckRequest{ UserID: userid, @@ -240,12 +240,23 @@ func (e *Endpoints) ClusterInfo(ctx context.Context, r *http.Request, vars map[s clusternames := r.URL.Query().Get("clusterName") clusternameList := strutil.Split(clusternames, ",", true) + orgIDHeader := r.Header.Get(httputil.OrgHeader) + orgID, err := strconv.Atoi(orgIDHeader) + if err != nil { + return mkResponse(apistructs.ImportClusterResponse{ + Header: apistructs.Header{ + Success: false, + Error: apistructs.ErrorResponse{Msg: err.Error()}, + }, + }) + } + if len(clusternameList) == 0 { errstr := "empty clusterName arg" return httpserver.ErrResp(200, "1", errstr) } - result, err := e.clusters.ClusterInfo(ctx, clusternameList) + result, err := e.clusters.ClusterInfo(ctx, uint64(orgID), clusternameList) if err != nil { errstr := fmt.Sprintf("failed to get clusterinfo: %s, %v", clusternames, err) return httpserver.ErrResp(200, "2", errstr) @@ -259,7 +270,7 @@ func (e *Endpoints) ClusterInfo(ctx context.Context, r *http.Request, vars map[s func (e *Endpoints) ClusterUpdate(ctx context.Context, r *http.Request, vars map[string]string) (httpserver.Responser, error) { header := r.Header - var req apistructs.ClusterUpdateRequest + var req apistructs.CMPClusterUpdateRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { errstr := fmt.Sprintf("failed to parse request body: %v", err) return httpserver.ErrResp(200, "2", errstr) @@ -272,7 +283,7 @@ func (e *Endpoints) ClusterUpdate(ctx context.Context, r *http.Request, vars map } } - err := e.bdl.UpdateCluster(req, header) + err := e.clusters.UpdateCluster(req, header) if err != nil { errstr := fmt.Sprintf("failed to update clusterinfo: %v", err) return httpserver.ErrResp(200, "2", errstr) @@ -283,7 +294,7 @@ func (e *Endpoints) ClusterUpdate(ctx context.Context, r *http.Request, vars map }) } -func (e *Endpoints) handleUpdateReq(req *apistructs.ClusterUpdateRequest) string { +func (e *Endpoints) handleUpdateReq(req *apistructs.CMPClusterUpdateRequest) string { var as *ess.Ess var isEdit bool clusterInfo, err := e.bdl.GetCluster(req.Name) @@ -409,3 +420,127 @@ func (e *Endpoints) validateOpsConfig(opsConf *apistructs.OpsConfig) error { func (e Endpoints) isEmpty(str string) bool { return strings.Replace(str, " ", "", -1) == "" } + +func (e *Endpoints) ImportCluster(ctx context.Context, r *http.Request, vars map[string]string) (resp httpserver.Responser, err error) { + var req apistructs.ImportCluster + + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + errStr := fmt.Sprintf("failed to unmarshal to apistructs.ImportCluster: %v", err) + return mkResponse(apistructs.ImportClusterResponse{ + Header: apistructs.Header{ + Success: false, + Error: apistructs.ErrorResponse{Msg: errStr}, + }, + }) + } + + logrus.Debugf("cluster init retry reuqest body: %v", req) + + i, resp := e.GetIdentity(r) + if resp != nil { + return resp, nil + } + + if err = e.clusters.ImportClusterWithRecord(i.UserID, &req); err != nil { + return mkResponse(apistructs.BaseResponse{ + Success: false, + Err: &apistructs.BaseResponseErr{ + Msg: err.Error(), + }, + }) + } + + return mkResponse(apistructs.ImportClusterResponse{ + Header: apistructs.Header{Success: true}, + }) +} + +func (e *Endpoints) InitClusterRetry(ctx context.Context, r *http.Request, vars map[string]string) (resp httpserver.Responser, err error) { + var req apistructs.ClusterInitRetry + + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + errStr := fmt.Sprintf("failed to unmarshal to apistructs.ImportCluster: %v", err) + return mkResponse(apistructs.ImportClusterResponse{ + Header: apistructs.Header{ + Success: false, + Error: apistructs.ErrorResponse{Msg: errStr}, + }, + }) + } + + logrus.Debugf("cluster init retry reuqest body: %v", req) + + orgIDHeader := r.Header.Get(httputil.OrgHeader) + orgID, err := strconv.Atoi(orgIDHeader) + if err != nil { + return mkResponse(apistructs.ImportClusterResponse{ + Header: apistructs.Header{ + Success: false, + Error: apistructs.ErrorResponse{Msg: err.Error()}, + }, + }) + } + + if err = e.clusters.ClusterInitRetry(uint64(orgID), &req); err != nil { + return mkResponse(apistructs.BaseResponse{ + Success: false, + Err: &apistructs.BaseResponseErr{ + Msg: err.Error(), + }, + }) + } + return mkResponse(apistructs.ImportClusterResponse{ + Header: apistructs.Header{Success: true}, + }) +} + +func (e *Endpoints) InitCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + clusterName := r.URL.Query().Get("clusterName") + accessKey := r.URL.Query().Get("accessKey") + + if accessKey != "" { + content, err := e.clusters.RenderInitContent(clusterName, accessKey) + if err != nil { + return err + } + + w.Write([]byte(content)) + + return nil + } + + reqUrl, err := e.clusters.RenderInitCmd(clusterName) + if err != nil { + return err + } + + resp := apistructs.InitClusterResponse{ + Header: apistructs.Header{Success: true}, + Data: reqUrl, + } + + respData, err := json.Marshal(resp) + if err != nil { + return err + } + + w.Header().Set("Content-Type", "application/json") + w.Write(respData) + + return nil +} + +func (e *Endpoints) ClusterHook(ctx context.Context, r *http.Request, vars map[string]string) (resp httpserver.Responser, err error) { + req := apistructs.ClusterEvent{} + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + errstr := fmt.Sprintf("decode clusterhook request fail: %v", err) + logrus.Error(errstr) + return httpserver.HTTPResponse{Status: http.StatusBadRequest, Content: errstr}, nil + } + if err := e.clusters.Hook(&req); err != nil { + errstr := fmt.Sprintf("failed to handle cluster event: %v", err) + logrus.Error(errstr) + return httpserver.HTTPResponse{Status: http.StatusInternalServerError, Content: errstr}, nil + } + return httpserver.HTTPResponse{Status: http.StatusOK}, nil +} diff --git a/modules/cmp/endpoints/common.go b/modules/cmp/endpoints/common.go index 7a22927b4d6..eb49ae9bac6 100644 --- a/modules/cmp/endpoints/common.go +++ b/modules/cmp/endpoints/common.go @@ -29,7 +29,7 @@ import ( "github.com/erda-project/erda/pkg/http/httpserver" ) -// Permission check +// PermissionCheck Permission check func (e *Endpoints) PermissionCheck(userID, orgID, projectID, action string) error { if orgID == "" { return e.IsManager(userID, apistructs.SysScope, "") @@ -89,7 +89,7 @@ func (e *Endpoints) IsManager(userID string, scopeType apistructs.ScopeType, sco return err } -// Create cloud resource +// InitRecord Create cloud resource func (e *Endpoints) InitRecord(r dbclient.Record) (*dbclient.Record, httpserver.Responser) { recordID, err := e.dbclient.RecordsWriter().Create(&dbclient.Record{ RecordType: r.RecordType, diff --git a/modules/cmp/endpoints/endpoints.go b/modules/cmp/endpoints/endpoints.go index 7c4ad565383..47e3690a494 100644 --- a/modules/cmp/endpoints/endpoints.go +++ b/modules/cmp/endpoints/endpoints.go @@ -75,6 +75,12 @@ func WithBundle(bdl *bundle.Bundle) Option { } } +func WithOrgResource(o *org_resource.OrgResource) Option { + return func(e *Endpoints) { + e.orgResource = o + } +} + // Routes Return routes func (e *Endpoints) Routes() []httpserver.Endpoint { return []httpserver.Endpoint{ @@ -86,11 +92,15 @@ func (e *Endpoints) Routes() []httpserver.Endpoint { {Path: "/api/records", Method: http.MethodGet, Handler: auth(i18nPrinter(e.Query))}, {Path: "/api/recordtypes", Method: http.MethodGet, Handler: auth(i18nPrinter(e.RecordTypeList))}, {Path: "/api/node-logs", Method: http.MethodGet, Handler: auth(i18nPrinter(e.Logs))}, + {Path: "/api/cluster/actions/import", Method: http.MethodPost, Handler: auth(i18nPrinter(e.ImportCluster))}, + {Path: "/api/cluster/actions/init-retry", Method: http.MethodPost, Handler: auth(i18nPrinter(e.InitClusterRetry))}, {Path: "/api/cluster/actions/upgrade", Method: http.MethodPost, Handler: auth(i18nPrinter(e.UpgradeEdgeCluster))}, {Path: "/api/cluster/actions/batch-upgrade", Method: http.MethodPost, Handler: auth(i18nPrinter(e.BatchUpgradeEdgeCluster))}, {Path: "/api/cluster", Method: http.MethodDelete, Handler: auth(i18nPrinter(e.OfflineEdgeCluster))}, {Path: "/api/cluster", Method: http.MethodGet, Handler: auth(i18nPrinter(e.ClusterInfo))}, + {Path: "/api/cluster/init-command", Method: http.MethodGet, WriterHandler: e.InitCluster}, {Path: "/api/org-cluster-info", Method: http.MethodGet, Handler: auth(i18nPrinter(e.OrgClusterInfo))}, + {Path: "/api/clusterhook", Method: http.MethodPost, Handler: auth(i18nPrinter(e.ClusterHook))}, // officer apis {Path: "/api/clusters/{clusterName}/registry/readonly", Method: http.MethodGet, Handler: e.RegistryReadonly}, diff --git a/modules/cmp/endpoints/records.go b/modules/cmp/endpoints/records.go index d9f955e2c69..e4292070c43 100644 --- a/modules/cmp/endpoints/records.go +++ b/modules/cmp/endpoints/records.go @@ -34,6 +34,10 @@ func (e *Endpoints) RecordTypeList(ctx context.Context, r *http.Request, vars ma Success: true, }, Data: []apistructs.RecordTypeData{ + { + RecordType: i18n.Sprintf(string(dbclient.RecordTypeImportKubernetesCluster)), + RawRecordType: string(dbclient.RecordTypeImportKubernetesCluster), + }, { RecordType: i18n.Sprintf(string(dbclient.RecordTypeRmNodes)), RawRecordType: string(dbclient.RecordTypeRmNodes), diff --git a/modules/cmp/i18n/i18n.go b/modules/cmp/i18n/i18n.go index a17bef0a8ff..774f9c1e3bc 100644 --- a/modules/cmp/i18n/i18n.go +++ b/modules/cmp/i18n/i18n.go @@ -26,6 +26,7 @@ func InitI18N() { message.SetString(language.SimplifiedChinese, "addAliCSManagedEdgeCluster", "添加阿里云容器服务标准托管集群") message.SetString(language.SimplifiedChinese, "upgradeEdgeCluster", "升级边缘集群") message.SetString(language.SimplifiedChinese, "offlineEdgeCluster", "集群下线") + message.SetString(language.SimplifiedChinese, "importKubernetesCluster", "导入Kubernetes集群") message.SetString(language.SimplifiedChinese, "buyNodes", "购买云资源") message.SetString(language.SimplifiedChinese, "addNodes", "添加机器") message.SetString(language.SimplifiedChinese, "addEssNodes", "弹性扩容") diff --git a/modules/cmp/impl/clusters/cluster_hook.go b/modules/cmp/impl/clusters/cluster_hook.go new file mode 100644 index 00000000000..445e46a4408 --- /dev/null +++ b/modules/cmp/impl/clusters/cluster_hook.go @@ -0,0 +1,63 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package clusters + +import ( + "fmt" + + "github.com/sirupsen/logrus" + + "github.com/erda-project/erda/apistructs" +) + +// Hook deal k8sClient object in mem +func (c *Clusters) Hook(clusterEvent *apistructs.ClusterEvent) error { + if clusterEvent == nil { + return fmt.Errorf("nil clusterEvent object") + } + + clusterName := clusterEvent.Content.Name + + switch clusterEvent.Action { + case apistructs.ClusterActionCreate: + logrus.Debugf("cluster %s action before create, current clients map: %v", + clusterName, c.k8s.GetCacheClients()) + if err := c.k8s.CreateClient(clusterEvent.Content.Name); err != nil { + logrus.Errorf("cluster %s action create error: %v", clusterName, err) + return err + } + logrus.Debugf("cluster %s action after create, current clients map: %v", + clusterName, c.k8s.GetCacheClients()) + return nil + case apistructs.ClusterActionUpdate: + logrus.Debugf("cluster %s action before update, current clients map: %v", + clusterName, c.k8s.GetCacheClients()) + if err := c.k8s.UpdateClient(clusterEvent.Content.Name); err != nil { + logrus.Errorf("cluster %s action update error: %v", clusterName, err) + return err + } + logrus.Debugf("cluster %s action after update, current clients map: %v", + clusterName, c.k8s.GetCacheClients()) + return nil + case apistructs.ClusterActionDelete: + logrus.Debugf("cluster %s action before delete, current clients map: %v", + clusterName, c.k8s.GetCacheClients()) + c.k8s.RemoveClient(clusterEvent.Content.Name) + logrus.Debugf("cluster %s action after delete, current clients map: %v", + clusterName, c.k8s.GetCacheClients()) + return nil + default: + return fmt.Errorf("invaild cluster event action: %s", clusterEvent.Action) + } +} diff --git a/modules/cmp/impl/clusters/clusterinfo.go b/modules/cmp/impl/clusters/clusterinfo.go index 62862514f27..05dd85cef04 100644 --- a/modules/cmp/impl/clusters/clusterinfo.go +++ b/modules/cmp/impl/clusters/clusterinfo.go @@ -15,50 +15,205 @@ package clusters import ( "context" + "encoding/json" "fmt" + "os" + "strings" "github.com/sirupsen/logrus" "golang.org/x/text/message" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "github.com/erda-project/erda/apistructs" + "github.com/erda-project/erda/modules/cmp/conf" "github.com/erda-project/erda/pkg/strutil" ) -func (c *Clusters) ClusterInfo(ctx context.Context, clusterNames []string) ([]map[string]map[string]apistructs.NameValue, error) { +const ( + statusPending = "pending" + statusOnline = "online" + statusOffline = "offline" + statusInitializing = "initializing" + statusInitializeError = "initialize error" + statusUnknown = "unknown" + diceOperator = "/apis/dice.terminus.io/v1beta1/namespaces/default/dices/dice" + erdaOperator = "/apis/erda.terminus.io/v1beta1/namespaces/default/erdas/erda" +) + +var ( + checkCRDs = []string{erdaOperator, diceOperator} +) + +func (c *Clusters) ClusterInfo(ctx context.Context, orgID uint64, clusterNames []string) ([]map[string]map[string]apistructs.NameValue, error) { i18n := ctx.Value("i18nPrinter").(*message.Printer) - resultList := []map[string]map[string]apistructs.NameValue{} + resultList := make([]map[string]map[string]apistructs.NameValue, 0) + for _, clusterName := range clusterNames { - clusterinfo, err := c.bdl.QueryClusterInfo(clusterName) + clusterMetaData, err := c.bdl.GetCluster(clusterName) if err != nil { - errstr := fmt.Sprintf("failed to queryclusterinfo: %v, cluster: %v", err, clusterName) - logrus.Errorf(errstr) + logrus.Error(err) continue } - masterNum := len(strutil.Split(clusterinfo.Get(apistructs.MASTER_ADDR), ",", true)) - lbNum := len(strutil.Split(clusterinfo.Get(apistructs.LB_ADDR), ",", true)) + baseInfo := map[string]apistructs.NameValue{ + "manageType": {Name: i18n.Sprintf("manage type"), Value: parseManageType(clusterMetaData.ManageConfig)}, + "clusterName": {Name: i18n.Sprintf("cluster name"), Value: clusterName}, + "initJobClusterName": {Name: i18n.Sprintf("init job cluster name"), Value: os.Getenv("DICE_CLUSTER_NAME")}, + } + + urlInfo := map[string]apistructs.NameValue{} + + if ci, err := c.bdl.QueryClusterInfo(clusterName); err != nil { + errStr := fmt.Sprintf("failed to queryclusterinfo: %v, cluster: %v", err, clusterName) + logrus.Errorf(errStr) + } else { + baseInfo["clusterType"] = apistructs.NameValue{Name: i18n.Sprintf("cluster type"), Value: ci.Get(apistructs.DICE_CLUSTER_TYPE)} + baseInfo["clusterVersion"] = apistructs.NameValue{Name: i18n.Sprintf("cluster version"), Value: ci.Get(apistructs.DICE_VERSION)} + baseInfo["rootDomain"] = apistructs.NameValue{Name: i18n.Sprintf("root domain"), Value: ci.Get(apistructs.DICE_ROOT_DOMAIN)} + baseInfo["edgeCluster"] = apistructs.NameValue{Name: i18n.Sprintf("edge cluster"), Value: ci.Get(apistructs.DICE_IS_EDGE) == "true"} + baseInfo["masterNum"] = apistructs.NameValue{ + Name: i18n.Sprintf("master num"), + Value: len(strutil.Split(ci.Get(apistructs.MASTER_ADDR), ",", true)), + } + baseInfo["lbNum"] = apistructs.NameValue{ + Name: i18n.Sprintf("lb num"), + Value: len(strutil.Split(ci.Get(apistructs.LB_ADDR), ",", true)), + } + baseInfo["httpsEnabled"] = apistructs.NameValue{ + Name: i18n.Sprintf("https enabled"), + Value: strutil.Contains(ci.Get(apistructs.DICE_PROTOCOL), "https"), + } + + urlInfo["registry"] = apistructs.NameValue{Name: "registry", Value: ci.Get(apistructs.REGISTRY_ADDR)} + urlInfo["nexus"] = apistructs.NameValue{Name: "nexus", Value: ci.Get(apistructs.NEXUS_ADDR)} + urlInfo["masters"] = apistructs.NameValue{Name: "masters", Value: ci.Get(apistructs.MASTER_ADDR)} + urlInfo["lb"] = apistructs.NameValue{Name: "lb", Value: ci.Get(apistructs.LB_ADDR)} + } + + cs, err := c.k8s.GetInClusterClient() + if err != nil { + logrus.Error(err) + } else { + pod, err := cs.CoreV1().Pods(conf.ErdaNamespace()).List(context.Background(), metav1.ListOptions{ + LabelSelector: labels.Set(map[string]string{"job-name": generateInitJobName(orgID, clusterName)}).String(), + }) + if err == nil { + if len(pod.Items) > 0 { + containerInfoPart := strings.Split(pod.Items[0].Status.ContainerStatuses[0].ContainerID, "://") + if len(containerInfoPart) >= 2 { + baseInfo["clusterInitContainerID"] = apistructs.NameValue{ + Name: i18n.Sprintf("cluster init container id"), + Value: containerInfoPart[1], + } + } + } + } else { + logrus.Error(err) + } + } + + if kc, err := c.k8s.GetClient(clusterName); err != nil { + logrus.Errorf("get k8sclient error: %v", err) + result := map[string]map[string]apistructs.NameValue{ + "basic": baseInfo, + "URLs": urlInfo, + } + + resultList = append(resultList, result) + continue + } else { + nodes, err := kc.ClientSet.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + if err != nil { + logrus.Error(err) + } + baseInfo["nodeCount"] = apistructs.NameValue{Name: i18n.Sprintf("node count"), Value: len(nodes.Items)} + } + + if status, err := c.getClusterStatus(clusterMetaData); err != nil { + logrus.Errorf("get cluster status error: %v", err) + } else { + baseInfo["clusterStatus"] = apistructs.NameValue{Name: i18n.Sprintf("cluster status"), Value: status} + } result := map[string]map[string]apistructs.NameValue{ - "basic": { - "clusterName": apistructs.NameValue{Name: i18n.Sprintf("cluster name"), Value: clusterinfo.Get(apistructs.DICE_CLUSTER_NAME)}, - "clusterType": apistructs.NameValue{Name: i18n.Sprintf("cluster type"), Value: clusterinfo.Get(apistructs.DICE_CLUSTER_TYPE)}, - "clusterVersion": apistructs.NameValue{Name: i18n.Sprintf("cluster version"), Value: clusterinfo.Get(apistructs.DICE_VERSION)}, - "rootDomain": apistructs.NameValue{Name: i18n.Sprintf("root domain"), Value: clusterinfo.Get(apistructs.DICE_ROOT_DOMAIN)}, - "edgeCluster": apistructs.NameValue{Name: i18n.Sprintf("edge cluster"), Value: clusterinfo.Get(apistructs.DICE_IS_EDGE) == "true"}, - "masterNum": apistructs.NameValue{Name: i18n.Sprintf("master num"), Value: masterNum}, - "lbNum": apistructs.NameValue{Name: i18n.Sprintf("lb num"), Value: lbNum}, - "httpsEnabled": apistructs.NameValue{ - Name: i18n.Sprintf("https enabled"), - Value: strutil.Contains(clusterinfo.Get(apistructs.DICE_PROTOCOL), "https")}, - }, - "URLs": { - "registry": apistructs.NameValue{Name: "registry", Value: clusterinfo.Get(apistructs.REGISTRY_ADDR)}, - "nexus": apistructs.NameValue{Name: "nexus", Value: clusterinfo.Get(apistructs.NEXUS_ADDR)}, - "masters": apistructs.NameValue{Name: "masters", Value: clusterinfo.Get(apistructs.MASTER_ADDR)}, - "lb": apistructs.NameValue{Name: "lb", Value: clusterinfo.Get(apistructs.LB_ADDR)}, - }, + "basic": baseInfo, + "URLs": urlInfo, } + resultList = append(resultList, result) } return resultList, nil } + +func (c *Clusters) getClusterStatus(meta *apistructs.ClusterInfo) (string, error) { + // if manage config is nil, cluster import with inet or other + if meta.ManageConfig == nil { + return statusUnknown, nil + } + + switch meta.ManageConfig.Type { + case apistructs.ManageProxy: + if meta.ManageConfig.Token == "" || meta.ManageConfig.Address == "" { + return statusPending, nil + } + case apistructs.ManageToken: + if meta.ManageConfig.Token == "" || meta.ManageConfig.Address == "" { + return statusOffline, nil + } + case apistructs.ManageCert: + if meta.ManageConfig.CertData == "" && meta.ManageConfig.KeyData == "" { + return statusOffline, nil + } + } + + client, err := c.k8s.GetClient(meta.Name) + if err != nil { + return statusUnknown, err + } + + ec := &apistructs.DiceCluster{} + var res []byte + + for _, selfLink := range checkCRDs { + res, err = client.ClientSet.RESTClient().Get(). + AbsPath(selfLink). + DoRaw(context.Background()) + if err != nil { + logrus.Error(err) + continue + } + break + } + + if err = json.Unmarshal(res, &ec); err != nil { + return statusUnknown, nil + } + + switch ec.Status.Phase { + case apistructs.ClusterPhaseRunning: + return statusOnline, nil + case apistructs.ClusterPhaseNone, apistructs.ClusterPhaseCreating, apistructs.ClusterPhaseInitJobs, + apistructs.ClusterPhasePending, apistructs.ClusterPhaseUpdating: + return statusInitializing, nil + case apistructs.ClusterPhaseFailed: + return statusInitializeError, nil + default: + return statusUnknown, nil + } +} + +func parseManageType(mc *apistructs.ManageConfig) string { + if mc == nil { + return "create" + } + + switch mc.Type { + case apistructs.ManageProxy: + return "agent" + case apistructs.ManageToken, apistructs.ManageCert: + return "import" + default: + return "create" + } +} diff --git a/modules/cmp/impl/clusters/import_cluster.go b/modules/cmp/impl/clusters/import_cluster.go new file mode 100644 index 00000000000..b5707597721 --- /dev/null +++ b/modules/cmp/impl/clusters/import_cluster.go @@ -0,0 +1,561 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package clusters + +import ( + "bytes" + "context" + "encoding/base64" + "fmt" + "math/rand" + "net/http" + "os" + "strconv" + "strings" + "text/template" + "time" + + "github.com/sirupsen/logrus" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + decoder "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" + + "github.com/erda-project/erda/apistructs" + "github.com/erda-project/erda/modules/cmp/conf" + "github.com/erda-project/erda/modules/cmp/dbclient" + "github.com/erda-project/erda/pkg/discover" + "github.com/erda-project/erda/pkg/http/httputil" +) + +const ( + KubeconfigType = "KUBECONFIG" + SAType = "SERVICEACCOUNT" + ProxyType = "PROXY" + caKey = "ca.crt" + tokenKey = "token" + ModuleClusterInit = "cluster-init" +) + +var ( + initRetryTimeout = 30 * time.Second +) + +type RenderDeploy struct { + ClusterName string + RootDomain string + PlateFormVersion string + CustomDomain string + InitJobImage string + ErdaHelmChartVersion string +} + +// importCluster import cluster +func (c *Clusters) importCluster(userID string, req *apistructs.ImportCluster) error { + var err error + + mc, err := ParseManageConfigFromCredential(req.CredentialType, req.Credential) + if err != nil { + return err + } + + // create cluster request to cluster-manager and core-service + if err = c.bdl.CreateClusterWithOrg(userID, req.OrgID, &apistructs.ClusterCreateRequest{ + Name: req.ClusterName, + DisplayName: req.DisplayName, + Description: req.Description, + Type: req.ClusterType, + SchedulerConfig: &req.ScheduleConfig, + WildcardDomain: req.WildcardDomain, + ManageConfig: mc, + }, http.Header{httputil.InternalHeader: []string{"cmp"}}); err != nil { + return err + } + + if mc.Type == apistructs.ManageProxy { + return nil + } + + ci, err := c.bdl.GetCluster(req.ClusterName) + if err != nil { + return err + } + + status, err := c.getClusterStatus(ci) + if err != nil { + return err + } + + if !(status == statusOffline || status == statusUnknown) { + return nil + } + + cs, err := c.k8s.GetInClusterClient() + if err != nil { + return err + } + + if err = c.checkNamespace(); err != nil { + return err + } + + targetClient, err := c.k8s.GetClient(req.ClusterName) + if err != nil { + return err + } + + orgDto, err := c.bdl.GetOrg(req.OrgID) + if err != nil { + return err + } + + nodes, err := targetClient.ClientSet.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + if err != nil { + return err + } + + for _, node := range nodes.Items { + node.Labels[fmt.Sprintf("dice/org-%s", orgDto.Name)] = "true" + if _, err = targetClient.ClientSet.CoreV1().Nodes().Update(context.Background(), &node, + metav1.UpdateOptions{}); err != nil { + return err + } + } + + // check init job, if already exist, return + if _, err = cs.BatchV1().Jobs(conf.ErdaNamespace()).Get(context.Background(), generateInitJobName(req.OrgID, req.ClusterName), + metav1.GetOptions{}); err == nil { + return nil + } + + // create init job + if _, err = cs.BatchV1().Jobs(conf.ErdaNamespace()).Create(context.Background(), c.generateClusterInitJob(req.OrgID, req.ClusterName, false), + metav1.CreateOptions{}); err != nil { + return err + } + + return err +} + +// ImportClusterWithRecord import cluster with record +func (c *Clusters) ImportClusterWithRecord(userID string, req *apistructs.ImportCluster) error { + var ( + err error + detailInfo string + status = dbclient.StatusTypeSuccess + ) + + if err = c.importCluster(userID, req); err != nil { + detailInfo = err.Error() + status = dbclient.StatusTypeFailed + } + + _, recordError := c.db.RecordsWriter().Create(&dbclient.Record{ + RecordType: dbclient.RecordTypeImportKubernetesCluster, + UserID: userID, + OrgID: strconv.FormatUint(req.OrgID, 10), + ClusterName: req.ClusterName, + Status: status, + Detail: detailInfo, + }) + + logrus.Errorf("recorde import cluster error: %v", recordError) + + return err +} + +func (c *Clusters) ClusterInitRetry(orgID uint64, req *apistructs.ClusterInitRetry) error { + cs, err := c.k8s.GetInClusterClient() + if err != nil { + return err + } + + if err = c.checkNamespace(); err != nil { + return err + } + + ctx, cancel := context.WithTimeout(context.Background(), initRetryTimeout) + defer cancel() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("retry init job timeout, please try again") + default: + // delete old init job + if err = cs.BatchV1().Jobs(conf.ErdaNamespace()).Delete(context.Background(), generateInitJobName(orgID, + req.ClusterName), metav1.DeleteOptions{}); err != nil { + // if delete error is job not found, try again + if !k8serrors.IsNotFound(err) { + time.Sleep(500 * time.Millisecond) + continue + } + // create job, if create error, tip retry again + if _, err = cs.BatchV1().Jobs(conf.ErdaNamespace()).Create(context.Background(), + c.generateClusterInitJob(orgID, req.ClusterName, true), metav1.CreateOptions{}); err != nil { + return fmt.Errorf("create retry job error: %v, please try again", err) + } + return nil + } + } + } +} + +func (c *Clusters) checkNamespace() error { + cs, err := c.k8s.GetInClusterClient() + if err != nil { + return err + } + + // check namespace + _, err = cs.CoreV1().Namespaces().Get(context.Background(), conf.ErdaNamespace(), metav1.GetOptions{}) + if err != nil { + if !k8serrors.IsNotFound(err) { + return err + } + if _, err = cs.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: conf.ErdaNamespace(), + }, + }, metav1.CreateOptions{}); err != nil { + return err + } + } + + return nil +} + +// ParseKubeconfig parse kubeconfig to manage config +func ParseKubeconfig(kubeconfig []byte) (*apistructs.ManageConfig, error) { + var mc apistructs.ManageConfig + + config, err := clientcmd.Load(kubeconfig) + if err != nil { + return nil, err + } + + // TODO: front support multi contexts select + if len(config.Contexts) != 1 { + return nil, fmt.Errorf("please provide specified cluster context") + } + + var clusterCtx *api.Context + + for _, clusterCtx = range config.Contexts { + break + } + + if clusterCtx == nil { + return nil, fmt.Errorf("get context error") + } + + cluster := config.Clusters[clusterCtx.Cluster] + if len(cluster.Server) == 0 { + return nil, fmt.Errorf("cluster server address it empty") + } + + mc.Address = cluster.Server + + if len(cluster.CertificateAuthorityData) != 0 { + mc.CertData = base64.StdEncoding.EncodeToString(cluster.CertificateAuthorityData) + } + + authInfo := config.AuthInfos[clusterCtx.AuthInfo] + + if len(authInfo.ClientKeyData) != 0 && len(authInfo.ClientCertificateData) != 0 { + mc.Type = apistructs.ManageCert + mc.CertData = base64.StdEncoding.EncodeToString(authInfo.ClientCertificateData) + mc.KeyData = base64.StdEncoding.EncodeToString(authInfo.ClientKeyData) + return &mc, nil + } + + if len(authInfo.Token) != 0 { + mc.Type = apistructs.ManageToken + mc.Token = authInfo.Token + } + + // TODO: support username and password + + return nil, fmt.Errorf("illegal kubeconfig") +} + +func (c *Clusters) RenderInitCmd(clusterName string) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + var ( + cluster *apistructs.ClusterInfo + err error + ) + + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("get cluster init command timeout") + default: + cluster, err = c.bdl.GetCluster(clusterName) + if err != nil { + time.Sleep(500 * time.Millisecond) + continue + } + + if cluster.ManageConfig.Type != apistructs.ManageProxy { + return "", fmt.Errorf("only support proxy manage type") + } + + cmd := fmt.Sprintf("kubectl apply -f '$REQUEST_PREFIX?clusterName=%s&accessKey=%s'", clusterName, cluster.ManageConfig.AccessKey) + return cmd, nil + } + } +} + +func (c *Clusters) RenderInitContent(clusterName string, accessKey string) (string, error) { + cluster, err := c.bdl.GetCluster(clusterName) + if err != nil { + return "", fmt.Errorf("get cluster error:%v", err) + } + if cluster.ManageConfig == nil { + return "", fmt.Errorf("manage config is nil") + } + + if cluster.ManageConfig.AccessKey != accessKey { + return "", fmt.Errorf("accesskey is error") + } + + cCluster := os.Getenv(apistructs.ComClusterKey) + if cCluster == "" { + return "", fmt.Errorf("can't get platform info") + } + + ci, err := c.bdl.QueryClusterInfo(cCluster) + if err != nil { + return "", err + } + + version := ci.Get("DICE_VERSION") + rootDomain := ci.Get("DICE_ROOT_DOMAIN") + + rd := RenderDeploy{ + ClusterName: clusterName, + RootDomain: rootDomain, + PlateFormVersion: version, + CustomDomain: cluster.WildcardDomain, + InitJobImage: renderReleaseImageAddr(ModuleClusterInit, version), + ErdaHelmChartVersion: conf.ErdaHelmChartVersion(), + } + + tmpl := template.Must(template.New("render").Parse(ProxyDeployTemplate)) + buf := new(bytes.Buffer) + + if err = tmpl.Execute(buf, rd); err != nil { + return "", err + } + + return buf.String(), nil + +} + +func ParseSecretes(address string, secret []byte) (*apistructs.ManageConfig, error) { + var mc apistructs.ManageConfig + + if address != "" { + mc.Address = address + } else { + return nil, fmt.Errorf("please provide non-empty address") + } + + s := corev1.Secret{} + + reader := bytes.NewReader(secret) + + if err := decoder.NewYAMLOrJSONDecoder(reader, 1024).Decode(&s); err != nil { + return nil, fmt.Errorf("illegal secret format: %v", err) + } + + if _, ok := s.Data[caKey]; ok { + mc.CaData = base64.StdEncoding.EncodeToString(s.Data[caKey]) + } + + if token, ok := s.Data[tokenKey]; !ok || len(s.Data[tokenKey]) == 0 { + return nil, fmt.Errorf("secrets must provide token") + } else { + mc.Token = string(token) + mc.Type = apistructs.ManageToken + return &mc, nil + } +} + +func ParseManageConfigFromCredential(credentialType string, credential apistructs.ICCredential) (*apistructs.ManageConfig, error) { + mc := &apistructs.ManageConfig{ + CredentialSource: credentialType, + } + + res, err := base64.StdEncoding.DecodeString(credential.Content) + if err != nil { + return nil, fmt.Errorf("decode credntial content error: %v", err) + } + + switch strings.ToUpper(credentialType) { + case KubeconfigType: + mc, err = ParseKubeconfig(res) + if err != nil { + return nil, fmt.Errorf("parse kubeconfig error: %v", err) + } + case SAType: + mc, err = ParseSecretes(credential.Address, res) + if err != nil { + return nil, fmt.Errorf("parse serviceAccount credntial info error: %v", err) + } + case ProxyType: + mc.Type = apistructs.ManageProxy + mc.AccessKey = generateAccessKey(64) + default: + return nil, fmt.Errorf("credntial type '%s' is not support", credentialType) + } + + mc.CredentialSource = credentialType + + return mc, nil +} + +// generateClusterInitJob generate cluster init job +func (c *Clusters) generateClusterInitJob(orgID uint64, clusterName string, reInstall bool) *batchv1.Job { + jobName := generateInitJobName(orgID, clusterName) + var backOffLimit int32 + + compClusterName := os.Getenv(apistructs.ComClusterKey) + if compClusterName == "" { + return nil + } + + cci, err := c.bdl.QueryClusterInfo(compClusterName) + if err != nil { + return nil + } + + eci, err := c.bdl.GetCluster(clusterName) + if err != nil { + return nil + } + + platformDomain := cci.Get("DICE_ROOT_DOMAIN") + platformVersion := cci.Get("DICE_VERSION") + + envs := []corev1.EnvVar{ + { + Name: "ERDA_CHART_VERSION", + Value: conf.ErdaHelmChartVersion(), + }, + { + Name: "TARGET_CLUSTER", + Value: clusterName, + }, + { + Name: "INSTALL_MODE", + Value: "remote", + }, + { + Name: "REPO_MODE", + Value: "local", + }, + { + Name: "HELM_NAMESPACE", + Value: metav1.NamespaceDefault, + }, + { + Name: "ERDA_BASE_VALUES", + Value: fmt.Sprintf("configmap.clustername=%s,configmap.domain=%s,configmap.version=%s", + clusterName, eci.WildcardDomain, platformVersion), + }, + { + Name: "ERDA_VALUES", + Value: fmt.Sprintf("domain=%s,clusterName=%s,clusterDomain=%s", + platformDomain, clusterName, eci.WildcardDomain), + }, + { + Name: "CLUSTER_MANAGER_ADDR", + Value: discover.ClusterManager(), + }, + { + Name: "REINSTALL", + Value: strconv.FormatBool(reInstall), + }, + } + + return &batchv1.Job{ + TypeMeta: metav1.TypeMeta{ + Kind: "Job", + APIVersion: "batch/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: jobName, + Namespace: conf.ErdaNamespace(), + }, + Spec: batchv1.JobSpec{ + BackoffLimit: &backOffLimit, + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: "Never", + Containers: []corev1.Container{ + { + Name: jobName, + Image: renderReleaseImageAddr(ModuleClusterInit, platformVersion), + ImagePullPolicy: "Always", + Command: []string{"sh", "-c", fmt.Sprintf("/app/%s", ModuleClusterInit)}, + Env: envs, + }, + }, + }, + }, + }, + } +} + +// generateAccessKey generate accessKey +func generateAccessKey(customLen int) string { + res := make([]string, customLen) + rand.Seed(time.Now().UnixNano()) + for start := 0; start < customLen; start++ { + switch rand.Intn(3) { + // rand lower + case 0: + randInt := rand.Intn(26) + 65 + res = append(res, string(rune(randInt))) + // rand upper + case 1: + randInt := rand.Intn(26) + 97 + res = append(res, string(rune(randInt))) + // rand number + case 2: + randInt := rand.Intn(10) + res = append(res, strconv.Itoa(randInt)) + } + } + + return strings.Join(res, "") +} + +// renderReleaseImageAddr render release image with module name and version +// e.g. registry.erda.cloud/erda:v1.1 +func renderReleaseImageAddr(module string, version string) string { + return fmt.Sprintf("%s/%s:v%s", conf.ReleaseRepo(), module, version) +} + +// generateInitJobName generate init job name with orgID and clusterName +func generateInitJobName(orgID uint64, clusterName string) string { + return fmt.Sprintf("erda-cluster-init-%d-%s", orgID, clusterName) +} diff --git a/modules/cmp/impl/clusters/offline_edge_cluster.go b/modules/cmp/impl/clusters/offline_edge_cluster.go index 1aee6cc352b..d479cedfca1 100644 --- a/modules/cmp/impl/clusters/offline_edge_cluster.go +++ b/modules/cmp/impl/clusters/offline_edge_cluster.go @@ -59,13 +59,13 @@ func (c *Clusters) OfflineEdgeCluster(req apistructs.OfflineEdgeClusterRequest, Path("/api/projects/actions/refer-cluster"). Param("cluster", req.ClusterName).Do().JSON(&projectRefer) if err != nil { - errstr := fmt.Sprintf("failed to call cmdb /api/projects/actions/refer-cluster: %v", err) + errstr := fmt.Sprintf("failed to call core-services /api/projects/actions/refer-cluster: %v", err) logrus.Errorf(errstr) err := errors.New(errstr) return recordID, err } if !resp.IsOK() || !projectRefer.Success { - errstr := fmt.Sprintf("call cmdb /api/projects/actions/refer-cluster, statuscode: %d, resp: %+v", resp.StatusCode(), projectRefer) + errstr := fmt.Sprintf("call core-services /api/projects/actions/refer-cluster, statuscode: %d, resp: %+v", resp.StatusCode(), projectRefer) logrus.Errorf(errstr) err := errors.New(errstr) return recordID, err @@ -102,19 +102,23 @@ func (c *Clusters) OfflineEdgeCluster(req apistructs.OfflineEdgeClusterRequest, } // Offline cluster by call cmd /api/clusters/ if status == dbclient.StatusTypeSuccess { + if _, err = c.bdl.DereferenceCluster(req.OrgID, req.ClusterName, userid); err != nil { + return recordID, err + } + deletecluster := cmdbDeleteClusterResp{} - resp, err := httpclient.New().Delete(discover.CMDB()). + resp, err := httpclient.New().Delete(discover.ClusterManager()). Header("Internal-Client", "cmp"). Path(fmt.Sprintf("/api/clusters/%s", req.ClusterName)). Do().JSON(&deletecluster) if err != nil { - errstr := fmt.Sprintf("failed to call cmdb /api/clusters/%s : %v", req.ClusterName, err) + errstr := fmt.Sprintf("failed to call cluster-manager /api/clusters/%s : %v", req.ClusterName, err) logrus.Errorf(errstr) err := errors.New(errstr) return recordID, err } if !resp.IsOK() || !deletecluster.Success { - errstr := fmt.Sprintf("call cmdb /api/clusters/%s, statuscode: %d, resp: %+v", + errstr := fmt.Sprintf("call cluster-manager /api/clusters/%s, statuscode: %d, resp: %+v", req.ClusterName, resp.StatusCode(), deletecluster) logrus.Errorf(errstr) err := errors.New(errstr) diff --git a/modules/cmp/impl/clusters/proxy-deploy.go b/modules/cmp/impl/clusters/proxy-deploy.go new file mode 100644 index 00000000000..96dbeeccc2d --- /dev/null +++ b/modules/cmp/impl/clusters/proxy-deploy.go @@ -0,0 +1,86 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package clusters + +// TODO: instead template conf load + +var ProxyDeployTemplate = ` +--- +apiVersion: v1 +kind: Namespace +metadata: + name: erda-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: erda + namespace: erda-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: erda-crb +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: erda + namespace: erda-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + labels: + job-name: erda-cluster-init + name: erda-cluster-init + namespace: erda-system +spec: + backoffLimit: 0 + selector: + matchLabels: + job-name: erda-cluster-init + template: + metadata: + labels: + job-name: erda-cluster-init + spec: + serviceAccountName: erda + restartPolicy: Never + containers: + - name: init + env: + - name: "DEBUG" + value: "true" + - name: "ERDA_CHART_VERSION" + value: "{{.ErdaHelmChartVersion}}" + - name: "INSTALL_MODE" + value: "local" + - name: "REPO_MODE" + value: "local" + - name: "HELM_NAMESPACE" + value: "default" + - name: "ERDA_BASE_VALUES" + value: "configmap.clustername={{.ClusterName}},configmap.domain={{.RootDomain}}" + - name: "ERDA_VALUES" + value: "domain={{.CustomDomain}},clusterName={{.ClusterName}},clusterDomain={{.RootDomain}}" + command: + - sh + - -c + - /app/cluster-init + image: {{.InitJobImage}} + imagePullPolicy: Always +` diff --git a/modules/cmp/impl/clusters/update_cluster.go b/modules/cmp/impl/clusters/update_cluster.go new file mode 100644 index 00000000000..4062c60f6c8 --- /dev/null +++ b/modules/cmp/impl/clusters/update_cluster.go @@ -0,0 +1,59 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package clusters + +import ( + "net/http" + + "github.com/erda-project/erda/apistructs" + "github.com/erda-project/erda/pkg/http/httputil" +) + +func (c *Clusters) UpdateCluster(req apistructs.CMPClusterUpdateRequest, header http.Header) error { + var ( + mc *apistructs.ManageConfig + err error + ) + + cluster, err := c.bdl.GetCluster(req.ClusterUpdateRequest.Name) + if err != nil { + return err + } + + mc = cluster.ManageConfig + + // if credential content is empty, use latest credential data. + if req.Credential.Content != "" { + // parse manage config from credential info + mc, err = ParseManageConfigFromCredential(req.CredentialType, req.Credential) + if err != nil { + return err + } + } + + newSchedulerConfig := cluster.SchedConfig + newSchedulerConfig.CPUSubscribeRatio = req.SchedulerConfig.CPUSubscribeRatio + + return c.bdl.UpdateCluster(apistructs.ClusterUpdateRequest{ + Name: cluster.Name, + DisplayName: req.DisplayName, + Type: cluster.Type, + Description: req.Description, + WildcardDomain: req.WildcardDomain, + SchedulerConfig: newSchedulerConfig, + ManageConfig: mc, + }, map[string][]string{ + httputil.InternalHeader: {"cmp"}, + }) +} diff --git a/modules/cmp/impl/clusters/upgrade_edge_cluster.go b/modules/cmp/impl/clusters/upgrade_edge_cluster.go index df8b5876967..ad995a90526 100644 --- a/modules/cmp/impl/clusters/upgrade_edge_cluster.go +++ b/modules/cmp/impl/clusters/upgrade_edge_cluster.go @@ -29,15 +29,17 @@ import ( "github.com/erda-project/erda/apistructs" "github.com/erda-project/erda/bundle" "github.com/erda-project/erda/modules/cmp/dbclient" + "github.com/erda-project/erda/modules/cmp/services/kubernetes" ) type Clusters struct { db *dbclient.DBClient bdl *bundle.Bundle + k8s *kubernetes.Kubernetes } func New(db *dbclient.DBClient, bdl *bundle.Bundle) *Clusters { - return &Clusters{db: db, bdl: bdl} + return &Clusters{db: db, bdl: bdl, k8s: &kubernetes.Kubernetes{}} } // status: diff --git a/modules/cmp/initialize.go b/modules/cmp/initialize.go index 01080519539..d34054b5a11 100644 --- a/modules/cmp/initialize.go +++ b/modules/cmp/initialize.go @@ -16,9 +16,12 @@ package cmp import ( "context" + "fmt" "os" + "strings" "time" + "github.com/go-redis/redis" "github.com/sirupsen/logrus" "github.com/erda-project/erda-infra/base/version" @@ -31,6 +34,7 @@ import ( "github.com/erda-project/erda/modules/cmp/endpoints/kubernetes" "github.com/erda-project/erda/modules/cmp/i18n" aliyun_resources "github.com/erda-project/erda/modules/cmp/impl/aliyun-resources" + org_resource "github.com/erda-project/erda/modules/cmp/impl/org-resource" "github.com/erda-project/erda/pkg/database/dbengine" "github.com/erda-project/erda/pkg/discover" "github.com/erda-project/erda/pkg/dumpstack" @@ -38,6 +42,7 @@ import ( "github.com/erda-project/erda/pkg/http/httpserver" "github.com/erda-project/erda/pkg/jsonstore" "github.com/erda-project/erda/pkg/strutil" + "github.com/erda-project/erda/pkg/ucauth" ) func initialize() error { @@ -70,6 +75,8 @@ func initialize() error { } func do() (*httpserver.Server, error) { + var redisCli *redis.Client + db := dbclient.Open(dbengine.MustOpen()) i18n.InitI18N() @@ -84,6 +91,28 @@ func do() (*httpserver.Server, error) { return nil, err } + if conf.LocalMode() { + redisCli = redis.NewClient(&redis.Options{ + Addr: conf.RedisAddr(), + Password: conf.RedisPwd(), + }) + } else { + redisCli = redis.NewFailoverClient(&redis.FailoverOptions{ + MasterName: conf.RedisMasterName(), + SentinelAddrs: strings.Split(conf.RedisSentinelAddrs(), ","), + Password: conf.RedisPwd(), + }) + } + if _, err := redisCli.Ping().Result(); err != nil { + return nil, err + } + + // init uc client + uc := ucauth.NewUCClient(discover.UC(), conf.UCClientID(), conf.UCClientSecret()) + if conf.OryEnabled() { + uc = ucauth.NewUCClient(conf.OryKratosPrivateAddr(), conf.OryCompatibleClientID(), conf.OryCompatibleClientSecret()) + } + // init Bundle bundleOpts := []bundle.Option{ bundle.WithHTTPClient( @@ -100,7 +129,14 @@ func do() (*httpserver.Server, error) { } bdl := bundle.New(bundleOpts...) - ep, err := initEndpoints(db, js, cachedJs, bdl) + o := org_resource.New( + org_resource.WithDBClient(db), + org_resource.WithUCClient(uc), + org_resource.WithBundle(bdl), + org_resource.WithRedisClient(redisCli), + ) + + ep, err := initEndpoints(db, js, cachedJs, bdl, o) if err != nil { return nil, err } @@ -124,7 +160,7 @@ func do() (*httpserver.Server, error) { return server, nil } -func initEndpoints(db *dbclient.DBClient, js, cachedJS jsonstore.JsonStore, bdl *bundle.Bundle) (*endpoints.Endpoints, error) { +func initEndpoints(db *dbclient.DBClient, js, cachedJS jsonstore.JsonStore, bdl *bundle.Bundle, o *org_resource.OrgResource) (*endpoints.Endpoints, error) { // compose endpoints ep := endpoints.New( @@ -132,6 +168,7 @@ func initEndpoints(db *dbclient.DBClient, js, cachedJS jsonstore.JsonStore, bdl js, cachedJS, endpoints.WithBundle(bdl), + endpoints.WithOrgResource(o), ) // Sync org resource task status @@ -175,4 +212,19 @@ func registerWebHook(bdl *bundle.Bundle) { if err := bdl.CreateWebhook(ev); err != nil { logrus.Warnf("failed to register pipeline tasks event, (%v)", err) } + + clusterEv := apistructs.CreateHookRequest{ + Name: "cmp-clusterhook", + Events: []string{"cluster"}, + URL: fmt.Sprintf("http://%s/api/clusterhook", discover.CMP()), + Active: true, + HookLocation: apistructs.HookLocation{ + Org: "-1", + Project: "-1", + Application: "-1", + }, + } + if err := bdl.CreateWebhook(clusterEv); err != nil { + logrus.Warnf("failed to register cluster event, (%v)", err) + } } diff --git a/modules/cmp/services/kubernetes/kubernetes.go b/modules/cmp/services/kubernetes/kubernetes.go new file mode 100644 index 00000000000..6fbf64cd151 --- /dev/null +++ b/modules/cmp/services/kubernetes/kubernetes.go @@ -0,0 +1,108 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package kubernetes + +import ( + "sync" + "time" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + + "github.com/erda-project/erda/pkg/k8sclient" +) + +var ( + InClusterClient *kubernetes.Clientset + defaultTimeout = 2 * time.Second +) + +type Kubernetes struct { + sync.RWMutex + clients map[string]*k8sclient.K8sClient +} + +func (k *Kubernetes) GetCacheClients() map[string]*k8sclient.K8sClient { + return k.clients +} + +func (k *Kubernetes) GetInClusterClient() (*kubernetes.Clientset, error) { + if InClusterClient != nil { + return InClusterClient, nil + } + rc, err := rest.InClusterConfig() + if err != nil { + return nil, err + } + + rc.QPS = 100 + rc.Burst = 100 + + cs, err := kubernetes.NewForConfig(rc) + if err != nil { + return nil, err + } + + return cs, nil +} + +func (k *Kubernetes) CreateClient(clusterName string) error { + nClient, err := k8sclient.New(clusterName) + if err != nil { + return err + } + + k.writeMap(clusterName, nClient) + + return nil +} + +func (k *Kubernetes) GetClient(clusterName string) (*k8sclient.K8sClient, error) { + client, ok := k.readMap(clusterName) + if !ok { + nClient, err := k8sclient.NewWithTimeOut(clusterName, defaultTimeout) + if err != nil { + return nil, err + } + k.writeMap(clusterName, nClient) + return nClient, nil + } + return client, nil +} + +func (k *Kubernetes) UpdateClient(clusterName string) error { + k.RemoveClient(clusterName) + return k.CreateClient(clusterName) +} + +func (k *Kubernetes) RemoveClient(clusterName string) { + delete(k.clients, clusterName) +} + +func (k *Kubernetes) readMap(clusterName string) (*k8sclient.K8sClient, bool) { + k.RLock() + v, ok := k.clients[clusterName] + k.RUnlock() + return v, ok +} + +func (k *Kubernetes) writeMap(clusterName string, client *k8sclient.K8sClient) { + if k.clients == nil { + k.clients = make(map[string]*k8sclient.K8sClient, 0) + } + + k.Lock() + k.clients[clusterName] = client + k.Unlock() +} diff --git a/modules/openapi/api/apis/cmdb/cmdb_cluster_create.go b/modules/openapi/api/apis/cmdb/cmdb_cluster_create.go deleted file mode 100644 index 3f2c9be051a..00000000000 --- a/modules/openapi/api/apis/cmdb/cmdb_cluster_create.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2021 Terminus, Inc. -// -// This program is free software: you can use, redistribute, and/or modify -// it under the terms of the GNU Affero General Public License, version 3 -// or later ("AGPL"), as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package cmdb - -import ( - "github.com/erda-project/erda/apistructs" - "github.com/erda-project/erda/modules/openapi/api/apis" - "github.com/erda-project/erda/modules/openapi/api/spec" -) - -var CMDB_CLUSTER_CREATE = apis.ApiSpec{ - Path: "/api/clusters", - BackendPath: "/api/clusters", - Host: "cmdb.marathon.l4lb.thisdcos.directory:9093", - Scheme: "http", - Method: "POST", - CheckLogin: true, - CheckToken: true, - IsOpenAPI: true, - RequestType: apistructs.ClusterCreateRequest{}, - ResponseType: apistructs.ClusterCreateResponse{}, - Doc: "summary: 创建集群", - Audit: func(ctx *spec.AuditContext) error { - var request apistructs.ClusterCreateRequest - if err := ctx.BindRequestData(&request); err != nil { - return err - } - - return ctx.CreateAudit(&apistructs.Audit{ - ScopeType: apistructs.OrgScope, - ScopeID: uint64(ctx.OrgID), - TemplateName: apistructs.ImportClusterTemplate, - Context: map[string]interface{}{ - "clusterName": request.Name, - }, - }) - }, -} diff --git a/modules/openapi/api/apis/cmp/cmp_cluster_import.go b/modules/openapi/api/apis/cmp/cmp_cluster_import.go new file mode 100644 index 00000000000..5143ada453f --- /dev/null +++ b/modules/openapi/api/apis/cmp/cmp_cluster_import.go @@ -0,0 +1,30 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmp + +import ( + "github.com/erda-project/erda/modules/openapi/api/apis" +) + +var CMP_CLUSTER_IMPORT = apis.ApiSpec{ + Path: "/api/clusters", + BackendPath: "/api/cluster/actions/import", + Host: "cmp.marathon.l4lb.thisdcos.directory:9027", + Scheme: "http", + Method: "POST", + CheckLogin: true, + CheckToken: true, + IsOpenAPI: true, + Doc: "summary: 创建集群", +} diff --git a/modules/openapi/api/apis/cmp/cmp_cluster_init_command.go b/modules/openapi/api/apis/cmp/cmp_cluster_init_command.go new file mode 100644 index 00000000000..3559916aa4f --- /dev/null +++ b/modules/openapi/api/apis/cmp/cmp_cluster_init_command.go @@ -0,0 +1,27 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmp + +import ( + "github.com/erda-project/erda/modules/openapi/api/apis" +) + +var CMP_CLUSTER_INIT_COMMAND = apis.ApiSpec{ + Path: "/api/cluster/init-command", + BackendPath: "/api/cluster/init-command", + Host: "cmp.marathon.l4lb.thisdcos.directory:9027", + Scheme: "http", + Method: "GET", + Doc: "summary: 获取集群初始化命令", +} diff --git a/pkg/helm/getter.go b/pkg/helm/getter.go new file mode 100644 index 00000000000..e06208b0344 --- /dev/null +++ b/pkg/helm/getter.go @@ -0,0 +1,72 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package helm + +import ( + "os" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" +) + +// RESTClientGetterImpl impl genericclioptions.RESTClientGetter +type RESTClientGetterImpl struct { + rc *rest.Config +} + +// NewRESTClientGetterImpl new RESTClientGetterImpl +func NewRESTClientGetterImpl(rc *rest.Config) *RESTClientGetterImpl { + return &RESTClientGetterImpl{ + rc: rc, + } +} + +func (r *RESTClientGetterImpl) ToRESTConfig() (*rest.Config, error) { + return r.rc, nil +} + +func (r *RESTClientGetterImpl) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + if dc, err := discovery.NewDiscoveryClientForConfig(r.rc); err != nil { + return nil, err + } else { + return memory.NewMemCacheClient(dc), nil + } +} + +func (r *RESTClientGetterImpl) ToRESTMapper() (meta.RESTMapper, error) { + dc, err := r.ToDiscoveryClient() + if err != nil { + return nil, err + } + + mapper := restmapper.NewDeferredDiscoveryRESTMapper(dc) + + return restmapper.NewShortcutExpander(mapper, dc), nil +} + +func (r *RESTClientGetterImpl) ToRawKubeConfigLoader() clientcmd.ClientConfig { + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig + + overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} + + // e.g. helm.sh/helm/v3/pkg/cli/environment.go + overrides.Context.Namespace = os.Getenv(EnvHelmNamespace) + + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) +} diff --git a/pkg/helm/helm.go b/pkg/helm/helm.go new file mode 100644 index 00000000000..70e48ecdacd --- /dev/null +++ b/pkg/helm/helm.go @@ -0,0 +1,383 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package helm + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" + + "github.com/gofrs/flock" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/cli" + clivalues "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/release" + "helm.sh/helm/v3/pkg/repo" + "helm.sh/helm/v3/pkg/storage/driver" + "helm.sh/helm/v3/pkg/strvals" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/erda-project/erda/pkg/filehelper" +) + +const ( + EnvHelmNamespace = "HELM_NAMESPACE" + EnvHelmDriver = "HELM_DRIVER" + EnvHelmDebug = "HELM_DEBUG" + EnvLocalChartPath = "LOCAL_CHART_PATH" + EnvLocalChartDiscoverDir = "LOCAL_CHART_DISCOVER_DIR" + DefaultChartSuffix = ".tgz" +) + +type Helm interface { + AddOrUpdateRepo(repoEntry *repo.Entry) error + GetReleaseHistory(releaseName string) ([]*release.Release, error) + InstallRelease(releaseName, chartName, version string, values ...string) error + UninstallRelease(releaseName string) error + UpgradeRelease(releaseName, localRepoName, targetVersion string) error +} + +type Client struct { + setting *cli.EnvSettings + ac *action.Configuration + getter *RESTClientGetterImpl + driver string + namespace string + // specified local chart path store in local + localChartPath string + // specified local char directory, will discover chart by specified chartName and chartVersion + // e.g. chartName(non-repoName)-version.tgz, localChartDiscoverDir have a higher priority + localChartDiscoverDir string +} + +type Option func(client *Client) + +// New new Helm Interface +func New(options ...Option) (Helm, error) { + h := Client{ + setting: cli.New(), + driver: os.Getenv(EnvHelmDriver), + } + + h.loadEnvironment() + + for _, op := range options { + op(&h) + } + + var ac action.Configuration + g := h.setting.RESTClientGetter() + + if h.getter != nil { + g = h.getter + } + + err := ac.Init(g, h.setting.Namespace(), h.driver, debug) + if err != nil { + return nil, err + } + + h.ac = &ac + + return &h, nil +} + +// WithLocalChartDiscoverDir with local chart discover dir +func WithLocalChartDiscoverDir(path string) Option { + return func(client *Client) { + client.localChartDiscoverDir = path + } +} + +// WithRESTClientGetter with custom rest client getter, use rest.Config to visit Kubernetes +func WithRESTClientGetter(getter *RESTClientGetterImpl) Option { + return func(client *Client) { + client.getter = getter + } +} + +// loadEnvironment load helm environment +func (c *Client) loadEnvironment() { + if os.Getenv(EnvHelmDebug) == "true" || os.Getenv("DEBUG") == "true" { + logrus.SetLevel(logrus.DebugLevel) + } + + if ns := os.Getenv(EnvHelmNamespace); ns != "" { + c.namespace = ns + } else { + c.namespace = metav1.NamespaceDefault + } + + if path := os.Getenv(EnvLocalChartPath); path != "" { + c.localChartPath = path + } + + if dir := os.Getenv(EnvLocalChartDiscoverDir); dir != "" { + c.localChartDiscoverDir = dir + } +} + +// GetReleaseHistory check release installed or not +func (c *Client) GetReleaseHistory(releaseName string) ([]*release.Release, error) { + logrus.Infof("[%s] get release on target cluster", releaseName) + + // use HELM_NAMESPACE find release + hc := action.NewHistory(c.ac) + + releases, err := hc.Run(releaseName) + if err != nil { + if err == driver.ErrReleaseNotFound { + return releases, nil + } + logrus.Errorf("[%s] history client run error: %v", releaseName, err) + return nil, err + } + + return releases, nil +} + +// InstallRelease install release +func (c *Client) InstallRelease(releaseName, chartName, version string, values ...string) error { + logrus.Infof("install release, name: %s, version: %s, chartName: %s", releaseName, version, chartName) + logrus.Infof("helm repository cache path: %s", c.setting.RepositoryCache) + + if res, err := c.GetReleaseHistory(releaseName); err != nil { + return err + } else { + if len(res) != 0 { + return fmt.Errorf("[%s] release already exist on target cluster, version: %s", + releaseName, res[len(res)-1].Chart.Metadata.Version) + } + } + + ic := action.NewInstall(c.ac) + + ic.ReleaseName = releaseName + ic.Version = version + ic.Namespace = c.namespace + + chartReq, err := c.getChart(chartName, version, &ic.ChartPathOptions) + if err != nil { + return fmt.Errorf("[%s] get chart error: %v", releaseName, err) + } + + var vals map[string]interface{} + + // if values setting, merge values to vals + if len(values) != 0 { + cvOptions := &clivalues.Options{} + vals, err = cvOptions.MergeValues(getter.All(c.setting)) + if err != nil { + return err + } + + if err = strvals.ParseInto(values[0], vals); err != nil { + return err + } + + } + + if _, err = ic.Run(chartReq, vals); err != nil { + return fmt.Errorf("[%s] install error: %v", releaseName, err) + } + + logrus.Infof("[%s] release install success", releaseName) + + return nil +} + +// getChart get chart +func (c *Client) getChart(chartName, version string, chartPathOptions *action.ChartPathOptions) (*chart.Chart, error) { + var ( + lc *chart.Chart + err error + ) + + if c.localChartPath != "" { + lc, err = loader.LoadFile(c.localChartPath) + } else if c.localChartDiscoverDir != "" { + chartPart := strings.Split(chartName, "/") + if len(chartPart) > 2 { + return nil, fmt.Errorf("not support chartName format") + } + + if len(chartPart) == 2 { + chartName = chartPart[1] + } + + lc, err = loader.LoadFile(fmt.Sprintf("%s/%s-%s%s", c.localChartDiscoverDir, chartName, + version, DefaultChartSuffix)) + } else { + option, err := chartPathOptions.LocateChart(chartName, c.setting) + if err != nil { + return nil, fmt.Errorf("located charts %s error: %v", chartName, err) + } + + lc, err = loader.Load(option) + } + + if err != nil { + return nil, fmt.Errorf("load chart path options error: %v", err) + } + + return lc, nil +} + +// UninstallRelease uninstall release which deployed +func (c *Client) UninstallRelease(releaseName string) error { + // use HELM_NAMESPACE find release + uc := action.NewUninstall(c.ac) + + resp, err := uc.Run(releaseName) + if resp != nil { + logrus.Debugf("[%s] uninstall release %+v,response: %v", releaseName, resp.Release, resp.Info) + } + if err != nil { + return fmt.Errorf("[%s] run uninstall client error: %v", releaseName, err) + } + + logrus.Infof("[%s] uninstall release success", releaseName) + + return nil +} + +// UpgradeRelease upgrade release version +func (c *Client) UpgradeRelease(releaseName, localRepoName, targetVersion string) error { + // use HELM_NAMESPACE find release + uc := action.NewUpgrade(c.ac) + r, err := c.GetReleaseHistory(releaseName) + if err != nil { + return err + } + + if len(r) == 0 { + return fmt.Errorf("[%s] release doesn't install", releaseName) + } + + if r[len(r)-1].Chart.Metadata.Version == targetVersion { + return fmt.Errorf("[%s] version %s already installed", releaseName, r[len(r)-1].Chart.Metadata.Version) + } + + uc.Version = targetVersion + + chartName := fmt.Sprintf("%s/%s", localRepoName, r[len(r)-1].Chart.Name()) + chartReq, err := c.getChart(chartName, targetVersion, &uc.ChartPathOptions) + if err != nil { + return fmt.Errorf("[%s] get chart error: %v", releaseName, err) + } + + if _, err = uc.Run(releaseName, chartReq, nil); err != nil { + return fmt.Errorf("[%s] release upgrade from version %s to %s error: %v", releaseName, + r[len(r)-1].Chart.Metadata.Version, targetVersion, err) + } + + logrus.Infof("[%s] release upgrade from version %s to %s success", releaseName, + r[len(r)-1].Chart.Metadata.Version, targetVersion) + + return nil +} + +// AddOrUpdateRepo Add or update repo from repo config +func (c *Client) AddOrUpdateRepo(repoEntry *repo.Entry) error { + logrus.Infof("load repo info: %+v", repoEntry) + + rfPath := c.setting.RepositoryConfig + + if _, err := os.Stat(rfPath); err != nil { + if !os.IsNotExist(err) { + return err + } + if err = filehelper.CreateFile(rfPath, "", os.ModePerm); err != nil { + return err + } + } + + // repo config lock + rfLock := flock.New(strings.Replace(rfPath, filepath.Ext(rfPath), ".lock", 1)) + rfLockCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + locked, err := rfLock.TryLockContext(rfLockCtx, time.Second) + if err != nil { + return nil + } + + if locked { + defer func() { + err = rfLock.Unlock() + if err != nil { + logrus.Errorf("unlock repo file error: %v", err) + } + }() + } + + rfContent, err := ioutil.ReadFile(rfPath) + if err != nil { + return fmt.Errorf("repo file read error, path: %s, error: %v", rfPath, err) + } + + rf := repo.File{} + + if err = yaml.Unmarshal(rfContent, &rf); err != nil { + return err + } + + logrus.Debugf("load repo file: %+v", rf) + + isNewRepo := true + + // if has repo already exists, tip and update repo. + if rf.Has(repoEntry.Name) { + logrus.Infof("[%s] repo already exists", repoEntry.Name) + isNewRepo = false + } + + cr, err := repo.NewChartRepository(repoEntry, getter.All(c.setting)) + if err != nil { + return err + } + + logrus.Infof("[%s] start download index file", repoEntry.Name) + if _, err = cr.DownloadIndexFile(); err != nil { + return fmt.Errorf("[%s] download index file error: %v", repoEntry.Name, err) + } + + if !isNewRepo { + logrus.Infof("[%s] repo update success, path: %s", repoEntry.Name, rfPath) + return nil + } + + // Update new repo to repo config file. + rf.Update(repoEntry) + if err := rf.WriteFile(c.setting.RepositoryConfig, 0644); err != nil { + return fmt.Errorf("write repo file %s error: %v", rfPath, err) + } + + logrus.Infof("change repo success, path: %s", rfPath) + + return nil +} + +func debug(format string, v ...interface{}) { + logrus.Debugf(format, v...) +} diff --git a/pkg/helm/manager.go b/pkg/helm/manager.go new file mode 100644 index 00000000000..3563437e654 --- /dev/null +++ b/pkg/helm/manager.go @@ -0,0 +1,184 @@ +// Copyright (c) 2021 Terminus, Inc. +// +// This program is free software: you can use, redistribute, and/or modify +// it under the terms of the GNU Affero General Public License, version 3 +// or later ("AGPL"), as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package helm + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/sirupsen/logrus" + "helm.sh/helm/v3/pkg/release" +) + +const ( + ActionInstall = iota + ActionUpgrade + ActionUninstall +) + +var ( + defaultTimeOut = 90 * time.Second + defaultCheckTime = 20 * time.Second +) + +type Manager struct { + Charts []*ChartSpec + HelmClient Helm + LocalRepoName string + TimeOut time.Duration +} + +type ChartSpec struct { + ReleaseName string + ChartName string + Version string + Action int + // overwrite values.yaml from chart, only use for install action + // like: key=value,key.nKey.value; you can use ParseValues convert map to values + Values string +} + +func (m *Manager) Execute() error { + for _, chart := range m.Charts { + // check release spec result + isCompleted, err := m.checkDeployed(chart) + if err != nil { + return err + } + // release is spec status, skip execute + if isCompleted { + continue + } + // execute action + if err = m.ActionExecute(chart); err != nil { + return err + } + + if err = m.controller(chart); err != nil { + return err + } + + <-time.After(defaultCheckTime) + } + return nil +} + +func (m *Manager) controller(chart *ChartSpec) error { + timeOut := defaultTimeOut + if m.TimeOut != 0 { + timeOut = m.TimeOut + } + + ctx, cancel := context.WithTimeout(context.Background(), timeOut) + defer cancel() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("[%s] check status time out", chart.ReleaseName) + default: + res, err := m.checkDeployed(chart) + if err != nil { + return err + } + if res { + return nil + } + continue + } + } +} + +func (m *Manager) ActionExecute(chart *ChartSpec) error { + switch chart.Action { + case ActionInstall: + return m.HelmClient.InstallRelease(chart.ReleaseName, m.transChartName(chart.ChartName), chart.Version, + chart.Values) + case ActionUpgrade: + return m.HelmClient.UpgradeRelease(chart.ReleaseName, m.LocalRepoName, chart.Version) + case ActionUninstall: + return m.HelmClient.UninstallRelease(chart.ReleaseName) + default: + return fmt.Errorf("not supported action") + } +} + +// checkDeployed check release deployed +func (m *Manager) checkDeployed(chart *ChartSpec) (bool, error) { + logrus.Infof("[%s] check release status", chart.ChartName) + // Get release deploy history + releases, err := m.HelmClient.GetReleaseHistory(chart.ReleaseName) + if err != nil { + return false, err + } + + var lr *release.Release + + // release had exist on target cluster + if len(releases) != 0 { + lr = releases[len(releases)-1] + } else { + if chart.Action == ActionUninstall { + logrus.Infof("[%s] check chart uninstall success", chart.ChartName) + return true, nil + } + } + + if lr == nil { + return false, nil + } + + // check status by action type + switch chart.Action { + case ActionInstall: + if lr.Chart.Metadata.Version != chart.Version { + return false, fmt.Errorf("[%s] had installed version %s", chart.ReleaseName, lr.Chart.Metadata.Version) + } + if lr.Info.Status != "deployed" { + logrus.Infof("[%s] check status is %s", chart.ChartName, lr.Info.Status) + return false, nil + } + logrus.Infof("[%s] check chart install success", chart.ChartName) + return true, nil + case ActionUpgrade: + if lr.Chart.Metadata.Version != chart.Version { + return false, nil + } + if lr.Info.Status != "deployed" { + logrus.Infof("[%s] check status is %s", chart.ChartName, lr.Info.Status) + return false, nil + } + logrus.Infof("[%s] check chart upgrade success", chart.ChartName) + return true, nil + case ActionUninstall: + return false, nil + } + + return true, nil +} + +func (m *Manager) transChartName(chartName string) string { + return fmt.Sprintf("%s/%s", m.LocalRepoName, chartName) +} + +func ParseValues(preValues map[string]string) string { + values := make([]string, 0) + for k, v := range preValues { + values = append(values, fmt.Sprintf("%s=%s", k, v)) + } + + return strings.Join(values, ",") +} diff --git a/pkg/k8sclient/client.go b/pkg/k8sclient/client.go index 41abdc5318d..41b0687d42b 100644 --- a/pkg/k8sclient/client.go +++ b/pkg/k8sclient/client.go @@ -14,6 +14,8 @@ package k8sclient import ( + "time" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -31,18 +33,23 @@ type K8sClient struct { // New new K8sClient with clusterName. func New(clusterName string) (*K8sClient, error) { - b := bundle.New(bundle.WithClusterManager()) - - ci, err := b.GetCluster(clusterName) + rc, err := GetRestConfig(clusterName) if err != nil { return nil, err } - rc, err := config.ParseManageConfig(clusterName, ci.ManageConfig) + return NewForRestConfig(rc, scheme.LocalSchemeBuilder...) +} + +// NewWithTimeOut new k8sClient with timeout +func NewWithTimeOut(clusterName string, timeout time.Duration) (*K8sClient, error) { + rc, err := GetRestConfig(clusterName) if err != nil { return nil, err } + rc.Timeout = timeout + return NewForRestConfig(rc, scheme.LocalSchemeBuilder...) } @@ -72,3 +79,20 @@ func NewForRestConfig(c *rest.Config, schemes ...func(scheme *runtime.Scheme) er return &kc, nil } + +// GetRestConfig get rest config with clusterName +func GetRestConfig(clusterName string) (*rest.Config, error) { + b := bundle.New(bundle.WithClusterManager()) + + ci, err := b.GetCluster(clusterName) + if err != nil { + return nil, err + } + + rc, err := config.ParseManageConfig(clusterName, ci.ManageConfig) + if err != nil { + return nil, err + } + + return rc, nil +} diff --git a/pkg/k8sclient/config/config.go b/pkg/k8sclient/config/config.go index 92f0c167a4c..ba4c6a17170 100644 --- a/pkg/k8sclient/config/config.go +++ b/pkg/k8sclient/config/config.go @@ -16,7 +16,6 @@ package config import ( "encoding/base64" "fmt" - "net/http" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" @@ -44,6 +43,10 @@ func ParseManageConfig(clusterName string, c *apistructs.ManageConfig) (*rest.Co // GetDialerRestConfig get cluster dialer rest.Config func GetDialerRestConfig(clusterName string, c *apistructs.ManageConfig) (*rest.Config, error) { + if c.Address == "" { + return nil, fmt.Errorf("proxy must spcified address") + } + rc, err := GetRestConfig(c) if err != nil { return nil, err @@ -51,12 +54,7 @@ func GetDialerRestConfig(clusterName string, c *apistructs.ManageConfig) (*rest. rc.TLSClientConfig.NextProtos = []string{"http/1.1"} rc.UserAgent = rest.DefaultKubernetesUserAgent() + " cluster " + clusterName - rc.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { - if ht, ok := rt.(*http.Transport); ok { - ht.DialContext = clusterdialer.DialContext(clusterName) - } - return rt - } + rc.Dial = clusterdialer.DialContext(clusterName) return rc, nil } diff --git a/pkg/k8sclient/scheme/register.go b/pkg/k8sclient/scheme/register.go index 2f5d74ede1c..f13ace28503 100644 --- a/pkg/k8sclient/scheme/register.go +++ b/pkg/k8sclient/scheme/register.go @@ -22,6 +22,7 @@ import ( istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1" istiorbacv1alpha1 "istio.io/client-go/pkg/apis/rbac/v1alpha1" istiosecv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "k8s.io/apimachinery/pkg/runtime" k8sschema "k8s.io/client-go/kubernetes/scheme" @@ -40,4 +41,5 @@ var LocalSchemeBuilder = runtime.SchemeBuilder{ istiorbacv1alpha1.AddToScheme, istiosecv1beta1.AddToScheme, flinkoperatoryv1beta1.AddToScheme, + apiextensions.AddToScheme, }