github.com/pluralsh/plural-cli@v0.9.5/cmd/plural/clusters.go (about) 1 package plural 2 3 import ( 4 "fmt" 5 6 "github.com/urfave/cli" 7 "sigs.k8s.io/yaml" 8 9 "github.com/pluralsh/plural-cli/pkg/api" 10 "github.com/pluralsh/plural-cli/pkg/bootstrap" 11 "github.com/pluralsh/plural-cli/pkg/bootstrap/aws" 12 "github.com/pluralsh/plural-cli/pkg/bootstrap/validation" 13 "github.com/pluralsh/plural-cli/pkg/cluster" 14 "github.com/pluralsh/plural-cli/pkg/config" 15 "github.com/pluralsh/plural-cli/pkg/exp" 16 "github.com/pluralsh/plural-cli/pkg/kubernetes" 17 "github.com/pluralsh/plural-cli/pkg/machinepool" 18 "github.com/pluralsh/plural-cli/pkg/manifest" 19 "github.com/pluralsh/plural-cli/pkg/utils" 20 ) 21 22 func (p *Plural) clusterCommands() []cli.Command { 23 return []cli.Command{ 24 { 25 Name: "list", 26 Usage: "lists clusters accessible to your user", 27 Action: latestVersion(p.listClusters), 28 }, 29 { 30 Name: "transfer", 31 Usage: "transfers ownership of the current cluster to another", 32 Action: latestVersion(rooted(p.transferOwnership)), 33 Flags: []cli.Flag{ 34 cli.StringFlag{ 35 Name: "email", 36 Usage: "the email of the new owner", 37 }, 38 }, 39 }, 40 { 41 Name: "view", 42 Usage: "shows info for a cluster", 43 Flags: []cli.Flag{ 44 cli.StringFlag{ 45 Name: "id", 46 Usage: "the id of the source cluster", 47 }, 48 }, 49 Action: latestVersion(p.showCluster), 50 }, 51 { 52 Name: "depend", 53 Usage: "have a cluster wait for promotion on another cluster", 54 Flags: []cli.Flag{ 55 cli.StringFlag{ 56 Name: "source-id", 57 Usage: "the id of the source cluster", 58 }, 59 cli.StringFlag{ 60 Name: "dest-id", 61 Usage: "the id of the cluster waiting for promotion", 62 }, 63 }, 64 Action: latestVersion(p.dependCluster), 65 }, 66 { 67 Name: "promote", 68 Usage: "promote pending upgrades to your cluster", 69 Action: latestVersion(p.promoteCluster), 70 }, 71 { 72 Name: "wait", 73 Usage: "waits on a cluster until it becomes ready", 74 ArgsUsage: "NAMESPACE NAME", 75 Action: latestVersion(initKubeconfig(requireArgs(handleClusterWait, []string{"NAMESPACE", "NAME"}))), 76 Category: "Debugging", 77 }, 78 { 79 Name: "mpwait", 80 Usage: "waits on a machine pool until it becomes ready", 81 ArgsUsage: "NAMESPACE NAME", 82 Action: latestVersion(initKubeconfig(requireArgs(handleMPWait, []string{"NAMESPACE", "NAME"}))), 83 Category: "Debugging", 84 }, 85 { 86 Name: "migrate", 87 Usage: "migrate to Cluster API", 88 Action: latestVersion(rooted(initKubeconfig(p.handleMigration))), 89 Category: "Publishing", 90 Hidden: !exp.IsFeatureEnabled(exp.EXP_PLURAL_CAPI), 91 }, 92 { 93 Name: "aws-auth", 94 Usage: "fetches the current state of your aws auth config map", 95 Subcommands: awsAuthCommands(), 96 }, 97 } 98 } 99 100 func (p *Plural) handleMigration(_ *cli.Context) error { 101 p.InitPluralClient() 102 if err := validation.ValidateMigration(p); err != nil { 103 return err 104 } 105 106 project, err := manifest.FetchProject() 107 if err != nil { 108 return err 109 } 110 111 if project.ClusterAPI { 112 utils.Success("Cluster already migrated.\n") 113 return nil 114 } 115 116 return bootstrap.MigrateCluster(RunPlural) 117 } 118 119 func awsAuthCommands() []cli.Command { 120 return []cli.Command{ 121 { 122 Name: "fetch", 123 Usage: "gets the current state of your aws auth configmap", 124 Action: handleAwsAuth, 125 }, 126 { 127 Name: "update", 128 Usage: "adds a user or role to the aws auth configmap", 129 Flags: []cli.Flag{ 130 cli.StringFlag{Name: "role-arn"}, 131 cli.StringFlag{Name: "user-arn"}, 132 }, 133 Action: handleModifyAwsAuth, 134 }, 135 } 136 } 137 138 func handleAwsAuth(c *cli.Context) error { 139 auth, err := aws.FetchAuth() 140 if err != nil { 141 return err 142 } 143 144 res, err := yaml.Marshal(auth) 145 if err != nil { 146 return err 147 } 148 149 fmt.Println(string(res)) 150 return nil 151 } 152 153 func handleModifyAwsAuth(c *cli.Context) error { 154 role, user := c.String("role-arn"), c.String("user-arn") 155 156 if role != "" { 157 return aws.AddRole(role) 158 } 159 160 if user != "" { 161 return aws.AddUser(user) 162 } 163 164 return fmt.Errorf("you must specify at least one of role-arn or user-arn") 165 } 166 167 func handleClusterWait(c *cli.Context) error { 168 namespace := c.Args().Get(0) 169 name := c.Args().Get(1) 170 kubeConf, err := kubernetes.KubeConfig() 171 if err != nil { 172 return err 173 } 174 175 return cluster.Wait(kubeConf, namespace, name) 176 } 177 178 func handleMPWait(c *cli.Context) error { 179 namespace := c.Args().Get(0) 180 name := c.Args().Get(1) 181 kubeConf, err := kubernetes.KubeConfig() 182 if err != nil { 183 return err 184 } 185 186 return machinepool.WaitAll(kubeConf, namespace, name) 187 } 188 189 func (p *Plural) listClusters(c *cli.Context) error { 190 p.InitPluralClient() 191 clusters, err := p.Client.Clusters() 192 if err != nil { 193 return err 194 } 195 196 headers := []string{"ID", "Name", "Provider", "Git Url", "Owner"} 197 return utils.PrintTable(clusters, headers, func(c *api.Cluster) ([]string, error) { 198 return []string{c.Id, c.Name, c.Provider, c.GitUrl, c.Owner.Email}, nil 199 }) 200 } 201 202 func (p *Plural) transferOwnership(c *cli.Context) error { 203 p.InitPluralClient() 204 email := c.String("email") 205 man, err := manifest.FetchProject() 206 if err != nil { 207 return err 208 } 209 210 if err := p.TransferOwnership(man.Cluster, email); err != nil { 211 return api.GetErrorResponse(err, "TransferOwnership") 212 } 213 214 man.Owner.Email = email 215 if err := man.Flush(); err != nil { 216 return err 217 } 218 219 if err := p.assumeServiceAccount(config.Read(), man); err != nil { 220 return err 221 } 222 223 utils.Highlight("rebuilding bootstrap and console to sync your cluster with the new owner:\n") 224 225 for _, app := range []string{"bootstrap", "console"} { 226 installation, err := p.GetInstallation(app) 227 if err != nil { 228 return api.GetErrorResponse(err, "GetInstallation") 229 } else if installation == nil { 230 continue 231 } 232 233 if err := p.doBuild(installation, false); err != nil { 234 return err 235 } 236 } 237 238 utils.Highlight("deploying rebuilt applications\n") 239 if err := p.deploy(c); err != nil { 240 return err 241 } 242 243 utils.Success("Ownership successfully transferred to %s", email) 244 return nil 245 } 246 247 func (p *Plural) showCluster(c *cli.Context) error { 248 p.InitPluralClient() 249 id := c.String("id") 250 if id == "" { 251 clusters, err := p.Client.Clusters() 252 if err != nil { 253 return err 254 } 255 256 project, err := manifest.FetchProject() 257 if err != nil { 258 return err 259 } 260 for _, cluster := range clusters { 261 if cluster.Name == project.Cluster && cluster.Owner.Email == project.Owner.Email { 262 id = cluster.Id 263 break 264 } 265 } 266 } 267 cluster, err := p.Client.Cluster(id) 268 if err != nil { 269 return err 270 } 271 272 fmt.Printf("Cluster %s:\n\n", cluster.Id) 273 274 utils.PrintAttributes(map[string]string{ 275 "Id": cluster.Id, 276 "Name": cluster.Name, 277 "Provider": cluster.Provider, 278 "Git Url": cluster.GitUrl, 279 "Owner": cluster.Owner.Email, 280 }) 281 282 fmt.Println("") 283 if len(cluster.UpgradeInfo) > 0 { 284 fmt.Printf("Pending Upgrades:\n\n") 285 headers := []string{"Repository", "Count"} 286 return utils.PrintTable(cluster.UpgradeInfo, headers, func(c *api.UpgradeInfo) ([]string, error) { 287 return []string{c.Installation.Repository.Name, fmt.Sprintf("%d", c.Count)}, nil 288 }) 289 } 290 291 fmt.Println("No pending upgrades") 292 return nil 293 } 294 295 func (p *Plural) dependCluster(c *cli.Context) error { 296 p.InitPluralClient() 297 source, dest := c.String("source-id"), c.String("dest-id") 298 if err := p.Client.CreateDependency(source, dest); err != nil { 299 return err 300 } 301 302 utils.Highlight("Cluster %s will now delegate upgrades to %s", dest, source) 303 return nil 304 } 305 306 func (p *Plural) promoteCluster(c *cli.Context) error { 307 p.InitPluralClient() 308 if err := p.Client.PromoteCluster(); err != nil { 309 return err 310 } 311 312 utils.Success("Upgrades promoted!") 313 return nil 314 }