Skip to content

Commit f83d74f

Browse files
Add cluster promotion commands (#361)
* Add cluster promotion commands These commands will allow users to perform all the main CRUD for cluster promotions * clean up file input
1 parent 557968d commit f83d74f

13 files changed

Lines changed: 515 additions & 67 deletions

File tree

cmd/plural/clusters.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/pluralsh/plural/pkg/api"
7+
"github.com/pluralsh/plural/pkg/manifest"
8+
"github.com/pluralsh/plural/pkg/utils"
9+
"github.com/urfave/cli"
10+
)
11+
12+
func (p *Plural) clusterCommands() []cli.Command {
13+
return []cli.Command{
14+
{
15+
Name: "list",
16+
Usage: "lists clusters accessible to your user",
17+
Action: latestVersion(p.listClusters),
18+
},
19+
{
20+
Name: "view",
21+
Usage: "shows info for a cluster",
22+
Flags: []cli.Flag{
23+
cli.StringFlag{
24+
Name: "id",
25+
Usage: "the id of the source cluster",
26+
},
27+
},
28+
Action: latestVersion(p.showCluster),
29+
},
30+
{
31+
Name: "depend",
32+
Usage: "have a cluster wait for promotion on another cluster",
33+
Flags: []cli.Flag{
34+
cli.StringFlag{
35+
Name: "source-id",
36+
Usage: "the id of the source cluster",
37+
},
38+
cli.StringFlag{
39+
Name: "dest-id",
40+
Usage: "the id of the cluster waiting for promotion",
41+
},
42+
},
43+
Action: latestVersion(p.dependCluster),
44+
},
45+
{
46+
Name: "promote",
47+
Usage: "promote pending upgrades to your cluster",
48+
Action: latestVersion(p.promoteCluster),
49+
},
50+
}
51+
}
52+
53+
func (p *Plural) listClusters(c *cli.Context) error {
54+
p.InitPluralClient()
55+
clusters, err := p.Client.Clusters()
56+
if err != nil {
57+
return err
58+
}
59+
60+
headers := []string{"ID", "Name", "Provider", "Git Url", "Owner"}
61+
return utils.PrintTable(clusters, headers, func(c *api.Cluster) ([]string, error) {
62+
return []string{c.Id, c.Name, c.Provider, c.GitUrl, c.Owner.Email}, nil
63+
})
64+
}
65+
66+
func (p *Plural) showCluster(c *cli.Context) error {
67+
p.InitPluralClient()
68+
id := c.String("id")
69+
if id == "" {
70+
clusters, err := p.Client.Clusters()
71+
if err != nil {
72+
return err
73+
}
74+
75+
project, err := manifest.FetchProject()
76+
if err != nil {
77+
return err
78+
}
79+
for _, cluster := range clusters {
80+
if cluster.Name == project.Cluster && cluster.Owner.Email == project.Owner.Email {
81+
id = cluster.Id
82+
break
83+
}
84+
}
85+
}
86+
cluster, err := p.Client.Cluster(id)
87+
if err != nil {
88+
return err
89+
}
90+
91+
fmt.Printf("Cluster %s:\n\n", cluster.Id)
92+
93+
utils.PrintAttributes(map[string]string{
94+
"Id": cluster.Id,
95+
"Name": cluster.Name,
96+
"Provider": cluster.Provider,
97+
"Git Url": cluster.GitUrl,
98+
"Owner": cluster.Owner.Email,
99+
})
100+
101+
fmt.Println("")
102+
if len(cluster.UpgradeInfo) > 0 {
103+
fmt.Printf("Pending Upgrades:\n\n")
104+
headers := []string{"Repository", "Count"}
105+
return utils.PrintTable(cluster.UpgradeInfo, headers, func(c *api.UpgradeInfo) ([]string, error) {
106+
return []string{c.Installation.Repository.Name, fmt.Sprintf("%d", c.Count)}, nil
107+
})
108+
}
109+
110+
fmt.Println("No pending upgrades")
111+
return nil
112+
}
113+
114+
func (p *Plural) dependCluster(c *cli.Context) error {
115+
p.InitPluralClient()
116+
source, dest := c.String("source-id"), c.String("dest-id")
117+
if err := p.Client.CreateDependency(source, dest); err != nil {
118+
return err
119+
}
120+
121+
utils.Highlight("Cluster %s will now delegate upgrades to %s", dest, source)
122+
return nil
123+
}
124+
125+
func (p *Plural) promoteCluster(c *cli.Context) error {
126+
p.InitPluralClient()
127+
if err := p.Client.PromoteCluster(); err != nil {
128+
return err
129+
}
130+
131+
utils.Success("Upgrades promoted!")
132+
return nil
133+
}

cmd/plural/plural.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,11 @@ func (p *Plural) getCommands() []cli.Command {
306306
Subcommands: shellCommands(),
307307
Category: "Workspace",
308308
},
309+
{
310+
Name: "clusters",
311+
Usage: "commands related to managing plural clusters",
312+
Subcommands: p.clusterCommands(),
313+
},
309314
{
310315
Name: "repos",
311316
Usage: "view and manage plural repositories",

go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ require (
4444
github.com/olekukonko/tablewriter v0.0.5
4545
github.com/packethost/packngo v0.29.0
4646
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
47-
github.com/pluralsh/gqlclient v1.3.9
47+
github.com/pluralsh/gqlclient v1.3.10
4848
github.com/pluralsh/plural-operator v0.5.3
4949
github.com/pluralsh/polly v0.0.6
5050
github.com/rodaine/hclencoder v0.0.1
@@ -55,7 +55,7 @@ require (
5555
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
5656
go.mercari.io/hcledit v0.0.8
5757
golang.org/x/crypto v0.5.0
58-
golang.org/x/mod v0.6.0
58+
golang.org/x/mod v0.9.0
5959
golang.org/x/oauth2 v0.5.0
6060
gopkg.in/yaml.v2 v2.4.0
6161
helm.sh/helm/v3 v3.11.0
@@ -250,9 +250,9 @@ require (
250250
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
251251
golang.org/x/net v0.6.0 // indirect
252252
golang.org/x/sync v0.1.0 // indirect
253-
golang.org/x/sys v0.5.0 // indirect
253+
golang.org/x/sys v0.6.0 // indirect
254254
golang.org/x/term v0.5.0
255-
golang.org/x/text v0.7.0
255+
golang.org/x/text v0.8.0
256256
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
257257
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
258258
google.golang.org/api v0.110.0

go.sum

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
897897
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
898898
github.com/pluralsh/controller-reconcile-helper v0.0.4 h1:1o+7qYSyoeqKFjx+WgQTxDz4Q2VMpzprJIIKShxqG0E=
899899
github.com/pluralsh/controller-reconcile-helper v0.0.4/go.mod h1:AfY0gtteD6veBjmB6jiRx/aR4yevEf6K0M13/pGan/s=
900-
github.com/pluralsh/gqlclient v1.3.9 h1:cJ6Vu+N1pI5z46JS2o13fh4Oc9CbnTljwu3HTTQCPN8=
901-
github.com/pluralsh/gqlclient v1.3.9/go.mod h1:VHjVCSOaD9lzOI3u7tOuaQY7vrLdiAKPSbeihaWYX28=
900+
github.com/pluralsh/gqlclient v1.3.10 h1:B5Rd4cjAfTllMc4oPMR/PEebxdVb0gIyPm+VT3lvzEM=
901+
github.com/pluralsh/gqlclient v1.3.10/go.mod h1:z1qHnvPeqIN/a+5OzFs40e6HI6tDxzh1+yJuEpvqGy4=
902902
github.com/pluralsh/oauth v0.9.2 h1:tM9hBK4tCnJUeCOgX0ctxBBCS3hiCDPoxkJLODtedmQ=
903903
github.com/pluralsh/oauth v0.9.2/go.mod h1:aTUw/75rzcsbvW+/TLvWtHVDXFIdtFrDtUncOq9vHyM=
904904
github.com/pluralsh/plural-operator v0.5.3 h1:GaPL3LgimfzKZNHt7zXzqYZpb0hgyW9noHYnkA+rqNs=
@@ -1190,8 +1190,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
11901190
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
11911191
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
11921192
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
1193-
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
1194-
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
1193+
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
1194+
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
11951195
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
11961196
golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
11971197
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1375,8 +1375,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
13751375
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13761376
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13771377
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1378-
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
1379-
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1378+
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
1379+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13801380
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
13811381
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
13821382
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1395,8 +1395,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
13951395
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
13961396
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
13971397
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
1398-
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
1399-
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
1398+
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
1399+
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
14001400
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
14011401
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
14021402
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

pkg/api/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ type Client interface {
7979
ListKeyBackups() ([]*KeyBackup, error)
8080
GetHelp(prompt string) (string, error)
8181
DestroyCluster(domain, name, provider string) error
82+
CreateDependency(source, dest string) error
83+
PromoteCluster() error
84+
Clusters() ([]*Cluster, error)
85+
Cluster(id string) (*Cluster, error)
8286
}
8387

8488
type client struct {

pkg/api/cluster.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package api
22

33
import (
44
"github.com/pluralsh/gqlclient"
5+
"github.com/samber/lo"
56
)
67

78
func (client *client) DestroyCluster(domain, name, provider string) error {
@@ -12,3 +13,69 @@ func (client *client) DestroyCluster(domain, name, provider string) error {
1213

1314
return nil
1415
}
16+
17+
func (client *client) CreateDependency(source, dest string) error {
18+
_, err := client.pluralClient.CreateDependency(client.ctx, source, dest)
19+
return err
20+
}
21+
22+
func (client *client) PromoteCluster() error {
23+
_, err := client.pluralClient.PromoteCluster(client.ctx)
24+
return err
25+
}
26+
27+
func (client *client) Clusters() ([]*Cluster, error) {
28+
resp, err := client.pluralClient.Clusters(client.ctx, nil)
29+
if err != nil {
30+
return nil, err
31+
}
32+
clusters := make([]*Cluster, 0)
33+
for _, edge := range resp.Clusters.Edges {
34+
node := edge.Node
35+
clusters = append(clusters, &Cluster{
36+
Id: node.ID,
37+
Name: node.Name,
38+
Provider: string(node.Provider),
39+
GitUrl: lo.FromPtr(node.GitURL),
40+
Owner: &User{
41+
Id: node.Owner.ID,
42+
Name: node.Owner.Name,
43+
Email: node.Owner.Email,
44+
},
45+
})
46+
}
47+
48+
return clusters, nil
49+
}
50+
51+
func (client *client) Cluster(id string) (*Cluster, error) {
52+
resp, err := client.pluralClient.ClusterInfo(client.ctx, id)
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
node := resp.Cluster
58+
upgradeInfo := make([]*UpgradeInfo, 0)
59+
for _, info := range node.UpgradeInfo {
60+
upgradeInfo = append(upgradeInfo, &UpgradeInfo{
61+
Count: lo.FromPtr(info.Count),
62+
Installation: &Installation{
63+
Repository: convertRepository(info.Installation.Repository),
64+
},
65+
})
66+
}
67+
68+
cluster := &Cluster{
69+
Id: node.ID,
70+
Name: node.Name,
71+
Provider: string(node.Provider),
72+
GitUrl: lo.FromPtr(node.GitURL),
73+
Owner: &User{
74+
Id: node.Owner.ID,
75+
Name: node.Owner.Name,
76+
Email: node.Owner.Email,
77+
},
78+
UpgradeInfo: upgradeInfo,
79+
}
80+
return cluster, nil
81+
}

pkg/api/models.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,21 @@ type KeyBackup struct {
332332
InsertedAt string
333333
}
334334

335+
type Cluster struct {
336+
Id string
337+
Name string
338+
Provider string
339+
UpgradeInfo []*UpgradeInfo
340+
Source string
341+
GitUrl string
342+
Owner *User
343+
}
344+
345+
type UpgradeInfo struct {
346+
Count int64
347+
Installation *Installation
348+
}
349+
335350
const CrdFragment = `
336351
fragment CrdFragment on Crd {
337352
id

pkg/api/recipes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type RecipeInput struct {
1414
Description string
1515
Provider string
1616
Restricted bool
17+
Primary bool
1718
Tests []RecipeTestInput `yaml:"tests" json:"tests,omitempty"`
1819
Sections []RecipeSectionInput
1920
Dependencies []DependencyInput

pkg/api/repos.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,21 @@ func (client *client) GetRepository(repo string) (*Repository, error) {
7676
return nil, err
7777
}
7878

79+
return convertRepository(resp.Repository), nil
80+
}
81+
82+
func convertRepository(repo *gqlclient.RepositoryFragment) *Repository {
7983
return &Repository{
80-
Id: resp.Repository.ID,
81-
Name: resp.Repository.Name,
82-
Description: utils.ConvertStringPointer(resp.Repository.Description),
83-
Icon: utils.ConvertStringPointer(resp.Repository.Icon),
84-
DarkIcon: utils.ConvertStringPointer(resp.Repository.DarkIcon),
85-
Notes: utils.ConvertStringPointer(resp.Repository.Notes),
84+
Id: repo.ID,
85+
Name: repo.Name,
86+
Description: utils.ConvertStringPointer(repo.Description),
87+
Icon: utils.ConvertStringPointer(repo.Icon),
88+
DarkIcon: utils.ConvertStringPointer(repo.DarkIcon),
89+
Notes: utils.ConvertStringPointer(repo.Notes),
8690
Publisher: &Publisher{
87-
Name: resp.Repository.Publisher.Name,
91+
Name: repo.Publisher.Name,
8892
},
89-
}, nil
93+
}
9094
}
9195

9296
func (client *client) CreateRepository(name, publisher string, input *gqlclient.RepositoryAttributes) error {

pkg/bundle/configuration.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,15 @@ func Configure(ctx map[string]interface{}, item *api.ConfigurationItem, context
178178
if value := getEnvVar(repo, item.Name); value != "" {
179179
res = value
180180
} else {
181-
prompt, opts := fileSurvey(def)
181+
prompt, opts := fileSurvey(def, item)
182182
if err := survey.AskOne(prompt, &res, opts...); err != nil {
183183
return err
184184
}
185185
}
186+
if res == "" {
187+
return
188+
}
189+
186190
path, err := homedir.Expand(res)
187191
if err != nil {
188192
return err

0 commit comments

Comments
 (0)