open-nomad/command/node_meta_read.go
Michael Schurter 35d65c7c7e
Dynamic Node Metadata (#15844)
Fixes #14617
Dynamic Node Metadata allows Nomad users, and their jobs, to update Node metadata through an API. Currently Node metadata is only reloaded when a Client agent is restarted.

Includes new UI for editing metadata as well.

---------

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>
2023-02-07 14:42:25 -08:00

143 lines
3.3 KiB
Go

package command
import (
"fmt"
"sort"
"strings"
"github.com/posener/complete"
)
type NodeMetaReadCommand struct {
Meta
}
func (c *NodeMetaReadCommand) Help() string {
helpText := `
Usage: nomad node meta read [-json] [-node-id ...]
Read a node's metadata. This command only works on client agents. The node
status command can be used to retrieve node metadata from any agent.
Changes via the "node meta apply" subcommand are batched and may take up to
10 seconds to propagate to the servers and affect scheduling. This command
will always return the most recent node metadata while the "node status"
command can be used to view the metadata that is currently being used for
scheduling.
General Options:
` + generalOptionsUsage(usageOptsDefault|usageOptsNoNamespace) + `
Node Meta Options:
-node-id
Reads metadata from the specified node. If not specified the node receiving
the request will be used by default.
-json
Output the node metadata in its JSON format.
-t
Format and display node metadata using a Go template.
Example:
$ nomad node meta read -node-id 3b58b0a6
`
return strings.TrimSpace(helpText)
}
func (c *NodeMetaReadCommand) Synopsis() string {
return "Read node metadata"
}
func (c *NodeMetaReadCommand) Name() string { return "node meta read" }
func (c *NodeMetaReadCommand) Run(args []string) int {
var nodeID, tmpl string
var json bool
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.StringVar(&nodeID, "node-id", "", "")
flags.StringVar(&tmpl, "t", "", "")
flags.BoolVar(&json, "json", false, "")
if err := flags.Parse(args); err != nil {
return 1
}
// Get the HTTP client
client, err := c.Meta.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 1
}
// Lookup nodeID
if nodeID != "" {
nodeID, err = lookupNodeID(client.Nodes(), nodeID)
if err != nil {
c.Ui.Error(err.Error())
return 1
}
}
meta, err := client.Nodes().Meta().Read(nodeID, nil)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error reading dynamic node metadata: %s", err))
return 1
}
if json || len(tmpl) > 0 {
out, err := Format(json, tmpl, meta)
if err != nil {
c.Ui.Error(err.Error())
return 1
}
c.Ui.Output(out)
return 0
}
c.Ui.Output(c.Colorize().Color("[bold]All Meta[reset]"))
c.Ui.Output(formatNodeMeta(meta.Meta))
// Print dynamic meta
c.Ui.Output(c.Colorize().Color("\n[bold]Dynamic Meta[reset]"))
keys := make([]string, 0, len(meta.Dynamic))
for k := range meta.Dynamic {
keys = append(keys, k)
}
sort.Strings(keys)
var rows []string
for _, k := range keys {
v := "<unset>"
if meta.Dynamic[k] != nil {
v = *meta.Dynamic[k]
}
rows = append(rows, fmt.Sprintf("%s|%s", k, v))
}
c.Ui.Output(formatKV(rows))
// Print static meta
c.Ui.Output(c.Colorize().Color("\n[bold]Static Meta[reset]"))
c.Ui.Output(formatNodeMeta(meta.Static))
return 0
}
func (c *NodeMetaReadCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-node-id": complete.PredictAnything,
"-json": complete.PredictNothing,
"-t": complete.PredictAnything,
})
}
func (c *NodeMetaReadCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictNothing
}