package cmd import ( "fmt" "github.com/sirupsen/logrus" "github.com/rancher/cli/cliclient" managementClient "github.com/rancher/rancher/pkg/client/generated/management/v3" "github.com/urfave/cli" ) type NodeData struct { ID string Node managementClient.Node Name string Pool string } func NodeCommand() cli.Command { return cli.Command{ Name: "nodes", Aliases: []string{"node"}, Usage: "Operations on nodes", Action: defaultAction(nodeLs), Subcommands: []cli.Command{ { Name: "ls", Usage: "List nodes", Description: "\nLists all nodes in the current cluster.", ArgsUsage: "None", Action: nodeLs, Flags: []cli.Flag{ cli.StringFlag{ Name: "format", Usage: "'json', 'yaml' or Custom format: '{{.Node.ID}} {{.Node.Name}}'", }, quietFlag, }, }, { Name: "delete", Aliases: []string{"rm"}, Usage: "Delete a node by ID", ArgsUsage: "[NODEID NODENAME]", Action: nodeDelete, }, }, } } func nodeLs(ctx *cli.Context) error { c, err := GetClient(ctx) if err != nil { return err } collection, err := getNodesList(ctx, c, c.UserConfig.FocusedCluster()) if err != nil { return err } nodePools, err := getNodePools(ctx, c) if err != nil { return err } writer := NewTableWriter([][]string{ {"ID", "ID"}, {"NAME", "Name"}, {"STATE", "Node.State"}, {"POOL", "Pool"}, {"DESCRIPTION", "Node.Description"}, }, ctx) defer writer.Close() for _, item := range collection.Data { writer.Write(&NodeData{ ID: item.ID, Node: item, Name: getNodeName(item), Pool: getNodePoolName(item, nodePools), }) } return writer.Err() } func nodeDelete(ctx *cli.Context) error { if ctx.NArg() == 0 { return cli.ShowSubcommandHelp(ctx) } c, err := GetClient(ctx) if err != nil { return err } for _, arg := range ctx.Args() { resource, err := Lookup(c, arg, "node") if err != nil { return err } node, err := getNodeByID(ctx, c, resource.ID) if err != nil { return err } if _, ok := node.Links["remove"]; !ok { logrus.Warnf("node %v is externally managed and must be deleted "+ "through the provider", getNodeName(node)) continue } err = c.ManagementClient.Node.Delete(&node) if err != nil { return err } } return nil } func getNodesList( ctx *cli.Context, c *cliclient.MasterClient, clusterID string, ) (*managementClient.NodeCollection, error) { filter := defaultListOpts(ctx) filter.Filters["clusterId"] = clusterID collection, err := c.ManagementClient.Node.List(filter) if err != nil { return nil, err } return collection, nil } func getNodeByID( ctx *cli.Context, c *cliclient.MasterClient, nodeID string, ) (managementClient.Node, error) { nodeCollection, err := getNodesList(ctx, c, c.UserConfig.FocusedCluster()) if err != nil { return managementClient.Node{}, err } for _, node := range nodeCollection.Data { if node.ID == nodeID { return node, nil } } return managementClient.Node{}, fmt.Errorf("no node found with the ID [%s], run "+ "`rancher nodes` to see available nodes", nodeID) } func getNodeName(node managementClient.Node) string { if node.Name != "" { return node.Name } else if node.NodeName != "" { return node.NodeName } else if node.RequestedHostname != "" { return node.RequestedHostname } return node.ID } func getNodePools( ctx *cli.Context, c *cliclient.MasterClient, ) (*managementClient.NodePoolCollection, error) { filter := defaultListOpts(ctx) filter.Filters["clusterId"] = c.UserConfig.FocusedCluster() collection, err := c.ManagementClient.NodePool.List(filter) if err != nil { return nil, err } return collection, nil } func getNodePoolName(node managementClient.Node, pools *managementClient.NodePoolCollection) string { for _, pool := range pools.Data { if node.NodePoolID == pool.ID { return pool.HostnamePrefix } } return "" }