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,
}