// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package command import ( "encoding/json" "fmt" "io" "os" "strings" "github.com/hashicorp/hcl/v2/hclsimple" "github.com/hashicorp/nomad/api" "github.com/posener/complete" ) type NodePoolApplyCommand struct { Meta } func (c *NodePoolApplyCommand) Name() string { return "node pool apply" } func (c *NodePoolApplyCommand) Synopsis() string { return "Create or update a node pool" } func (c *NodePoolApplyCommand) Help() string { helpText := ` Usage: nomad node pool apply [options] Apply is used to create or update a node pool. The specification file is read from stdin by specifying "-", otherwise a path to the file is expected. If ACLs are enabled, this command requires a token with the 'write' capability in a 'node_pool' policy that matches the node pool being targeted. General Options: ` + generalOptionsUsage(usageOptsDefault) + ` Apply Options: -json Parse the input as a JSON node pool specification. ` return strings.TrimSpace(helpText) } func (c *NodePoolApplyCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ "-json": complete.PredictNothing, }) } func (c *NodePoolApplyCommand) AutocompleteArgs() complete.Predictor { return complete.PredictOr( complete.PredictFiles("*.hcl"), complete.PredictFiles("*.json"), ) } func (c *NodePoolApplyCommand) Run(args []string) int { var jsonInput bool flags := c.Meta.FlagSet(c.Name(), FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&jsonInput, "json", false, "") if err := flags.Parse(args); err != nil { return 1 } // Check that we only have one argument. args = flags.Args() if len(args) != 1 { c.Ui.Error("This command takes one argument: ") c.Ui.Error(commandErrorText(c)) return 1 } // Read input content. path := args[0] var content []byte var err error switch path { case "-": content, err = io.ReadAll(os.Stdin) if err != nil { c.Ui.Error(fmt.Sprintf("Failed to read stdin: %v", err)) return 1 } // Set .hcl extension so the decoder doesn't fail. if !jsonInput { path = "stdin.nomad.hcl" } default: content, err = os.ReadFile(path) if err != nil { c.Ui.Error(fmt.Sprintf("Failed to read file %q: %v", path, err)) return 1 } } // Parse input. var poolSpec nodePoolSpec if jsonInput { err = json.Unmarshal(content, &poolSpec.NodePool) } else { err = hclsimple.Decode(path, content, nil, &poolSpec) } if err != nil { c.Ui.Error(fmt.Sprintf("Failed to parse input content: %v", err)) return 1 } // Make API request. client, err := c.Meta.Client() if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) return 1 } _, err = client.NodePools().Register(poolSpec.NodePool, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error applying node pool: %s", err)) return 1 } c.Ui.Output(fmt.Sprintf("Successfully applied node pool %q!", poolSpec.NodePool.Name)) return 0 } type nodePoolSpec struct { NodePool *api.NodePool `hcl:"node_pool,block"` }