Skip to content

Commit

Permalink
feat: add ability to read payload from stdin
Browse files Browse the repository at this point in the history
  • Loading branch information
synackd committed Nov 16, 2024
1 parent d8dffde commit e09a76b
Show file tree
Hide file tree
Showing 20 changed files with 239 additions and 202 deletions.
21 changes: 8 additions & 13 deletions cmd/bss-boot-params-add.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ var bootParamsAddCmd = &cobra.Command{
Args: cobra.NoArgs,
Short: "Add new boot parameters for one or more components",
Long: `Add new boot parameters for one or more components. At least one of --kernel,
--initrd, or --params must be specified as well as at least one of --xname, --mac, or --nid.
Alternatively, pass -f to pass a file (optionally specifying --payload-format, JSON by default),
but the rules above still apply for the payload.
--initrd, or --params must be specified as well as at least one of --xname,
--mac, or --nid. Alternatively, pass -f to pass a file (optionally specifying
--payload-format, JSON by default), but the rules above still apply for the
payload. If the specified file path is -, the data is read from standard input.
This command sends a POST to BSS. An access token is required.`,
Example: ` ochami bss boot params add \
Expand All @@ -31,7 +32,9 @@ This command sends a POST to BSS. An access token is required.`,
ochami bss boot params add --mac 00:de:ad:be:ef:00,00:c0:ff:ee:00:00 --params 'quiet nosplash'
ochami bss boot params add --mac 00:de:ad:be:ef:00 --mac 00:c0:ff:ee:00:00 --kernel https://example.com/kernel
ochami bss boot params add -f payload.json
ochami bss boot params add -f payload.yaml --payload-format yaml`,
ochami bss boot params add -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami bss boot params add -f -
echo '<yaml_data>' | ochami bss boot params add -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// cmd.LocalFlags().NFlag() doesn't seem to work, so we check every flag
if len(args) == 0 &&
Expand Down Expand Up @@ -70,15 +73,7 @@ This command sends a POST to BSS. An access token is required.`,
bp := bssTypes.BootParams{}

// Read payload from file first, allowing overwrites from flags
if cmd.Flag("payload").Changed {
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &bp)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
}
handlePayload(cmd, &bp)

// Set the hosts the boot parameters are for
if cmd.Flag("xname").Changed {
Expand Down
27 changes: 12 additions & 15 deletions cmd/bss-boot-params-delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,22 @@ var bootParamsDeleteCmd = &cobra.Command{
Args: cobra.NoArgs,
Short: "Delete boot parameters for one or more components",
Long: `Delete boot parameters for one or more components. At least one of --kernel,
--initrd, --params, --xname, --mac, or --nid must be specified. This command can delete
boot parameters by config (kernel URI, initrd URI, or kernel command line) or by component
(--xname, --mac, or --nid). The user will be asked for confirmation before deletion unless
--force is passed. Alternatively, pass -f to pass a file (optionally specifying --payload-format,
JSON by default), but the rules above still apply for the payload.
--initrd, --params, --xname, --mac, or --nid must be specified.
This command can delete boot parameters by config (kernel URI,
initrd URI, or kernel command line) or by component (--xname,
--mac, or --nid). The user will be asked for confirmation before
deletion unless --force is passed. Alternatively, pass -f to pass
a file (optionally specifying --payload-format, JSON by default),
but the rules above still apply for the payload. If the specified
file path is -, the data is read from standard input.
This command sends a DELETE to BSS. An access token is required.`,
Example: ` ochami bss boot params delete --kernel https://example.com/kernel
ochami bss boot params delete --kernel https://example.com/kernel --initrd https://example.com/initrd
ochami bss boot params delete -f payload.json
ochami bss boot params delete -f payload.yaml --payload-format yaml`,
ochami bss boot params delete -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami bss boot params delete -f -
echo '<yaml_data>' | ochami bss boot params delete -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// cmd.LocalFlags().NFlag() doesn't seem to work, so we check every flag
if len(args) == 0 &&
Expand Down Expand Up @@ -67,15 +72,7 @@ This command sends a DELETE to BSS. An access token is required.`,
bp := bssTypes.BootParams{}

// Read payload from file first, allowing overwrites from flags
if cmd.Flag("payload").Changed {
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &bp)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
}
handlePayload(cmd, &bp)

// Set the hosts the boot parameters are for
if cmd.Flag("xname").Changed {
Expand Down
26 changes: 11 additions & 15 deletions cmd/bss-boot-params-set.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ var bootParamsSetCmd = &cobra.Command{
Args: cobra.NoArgs,
Short: "Set boot parameters for one or more components, overwriting any previous",
Long: `Set boot parameters for one or mote components, overwriting any previously-set
parameters. At least one of --kernel, --initrd, or --params is required to
tell ochami which boot data to set. Also, at least one of --xname, --mac,
or --nid is required to tell ochami which components need modification. Alternatively, pass -f
to pass a file (optionally specifying --payload-format, JSON by default), but the rules above
still apply for the payload.
parameters. At least one of --kernel, --initrd, or --params is
required to tell ochami which boot data to set. Also, at least
one of --xname, --mac, or --nid is required to tell ochami which
components need modification. Alternatively, pass -f to pass a
file (optionally specifying --payload-format, JSON by default),
but the rules above still apply for the payload. If the specified
file path is -, the data is read from standard input.
This command sends a PUT to BSS. An access token is required.`,
Example: ` ochami bss boot params set --xname x1000c1s7b0 --kernel https://example.com/kernel
ochami bss boot params set --xname x1000c1s7b0,x1000c1s7b1 --kernel https://example.com/kernel
ochami bss boot params set --xname x1000c1s7b0 --xname x1000c1s7b1 --kernel https://example.com/kernel
ochami bss boot params set --xname x1000c1s7b0 --nid 1 --mac 00:c0:ff:ee:00:00 --params 'quiet nosplash'
ochami bss boot params set -f payload.json
ochami bss boot params set -f payload.yaml --payload-format yaml`,
ochami bss boot params set -f payload.yaml --payload-format yaml
echo <json_data> | ochami bss boot params set -f -
echo <yaml_data> | ochami bss boot params set -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// cmd.LocalFlags().NFlag() doesn't seem to work, so we check every flag
if len(args) == 0 &&
Expand Down Expand Up @@ -69,15 +73,7 @@ This command sends a PUT to BSS. An access token is required.`,
bp := bssTypes.BootParams{}

// Read payload from file first, allowing overwrites from flags
if cmd.Flag("payload").Changed {
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &bp)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
}
handlePayload(cmd, &bp)

// Set the hosts the boot parameters are for
if cmd.Flag("xname").Changed {
Expand Down
22 changes: 9 additions & 13 deletions cmd/bss-boot-params-update.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@ var bootParamsUpdateCmd = &cobra.Command{
Args: cobra.NoArgs,
Short: "Update some or all boot parameters for one or more components",
Long: `Update some or all boot parameters for one or more components. At least one of
--kernel, initrd, or --params must be specified as well as at least one of --xname, --mac, or
--nid. Alternatively, pass -f to pass a file (optionally specifying --payload-format, JSON by
default), but the rules above still apply for the payload.
--kernel, initrd, or --params must be specified as well as at least
one of --xname, --mac, or --nid. Alternatively, pass -f to pass a
file (optionally specifying --payload-format, JSON by default), but
the rules above still apply for the payload. If the specified file
path is -, the data is read from standard input.
This command sends a PATCH to BSS. An access token is required.`,
Example: ` ochami bss boot params update --xname x1000c1s7b0 --kernel https://example.com/kernel
ochami bss boot params update --xname x1000c1s7b0,x1000c1s7b1 --kernel https://example.com/kernel
ochami bss boot params update --xname x1000c1s7b0 --xname x1000c1s7b1 --kernel https://example.com/kernel
ochami bss boot params update --xname x1000c1s7b0 --nid 1 --mac 00:c0:ff:ee:00:00 --params 'quiet nosplash'
ochami bss boot params update -f payload.json
ochami bss boot params update -f payload.yaml --payload-format yaml`,
ochami bss boot params update -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami bss boot params update -f -
echo '<yaml_data>' | ochami bss boot params update -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// cmd.LocalFlags().NFlag() doesn't seem to work, so we check every flag
if len(args) == 0 &&
Expand Down Expand Up @@ -67,15 +71,7 @@ This command sends a PATCH to BSS. An access token is required.`,
bp := bssTypes.BootParams{}

// Read payload from file first, allowing overwrites from flags
if cmd.Flag("payload").Changed {
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &bp)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
}
handlePayload(cmd, &bp)

// Set the hosts the boot parameters are for
if cmd.Flag("xname").Changed {
Expand Down
22 changes: 10 additions & 12 deletions cmd/cloud_init-config-add.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ var cloudInitConfigAddCmd = &cobra.Command{
Long: `Add one or more new cloud-init configs. Either a payload file
containing the data or the JSON data itself must be passed.
Data is represented by a JSON array of cloud-init configs,
even if only one is being passed.
even if only one is being passed. An alternative to using
-d would be to use -f and passing -, which will cause ochami
to read the data from standard input.
This command sends a POST to cloud-init.`,
Example: ` ochami cloud-init config add -f payload.json
ochami cloud-init config add -f payload.yaml --payload-format yaml
ochami cloud-init config add -d \
Example: ` ochami cloud-init config add -d \
'[ \
{ \
"name": "compute", \
Expand All @@ -44,7 +44,11 @@ This command sends a POST to cloud-init.`,
} \
} \
} \
]'`,
]'
ochami cloud-init config add -f payload.json
ochami cloud-init config add -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami cloud-init config add -f -
echo '<yaml_data>' | ochami cloud-init config add -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// Without a base URI, we cannot do anything
cloudInitBaseURI, err := getBaseURI(cmd)
Expand All @@ -70,13 +74,7 @@ This command sends a POST to cloud-init.`,
var ciData []citypes.CI
if cmd.Flag("payload").Changed {
// Use payload file if passed
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &ciData)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
handlePayload(cmd, &ciData)
} else if cmd.Flag("data").Changed {
// ...otherwise try to read raw JSON from CLI
rawJSON, err := cmd.Flags().GetString("data")
Expand Down
22 changes: 10 additions & 12 deletions cmd/cloud_init-config-set.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ var cloudInitConfigSetCmd = &cobra.Command{
Long: `Set cloud-init config for one or more ids, overwriting any previous.
Either a payload file containing the data or the JSON data itself
must be passed. Data is represented by a JSON array of cloud-init
configs, even if only one is being passed.
configs, even if only one is being passed. An alternative to using
-d would be to use -f and passing -, which will cause ochami
to read the data from standard input.
This command sends a PUT to cloud-init.`,
Example: ` ochami cloud-init config set -f payload.json
ochami cloud-init config set -f payload.yaml --payload-format yaml
ochami cloud-init config set -d \
Example: ` ochami cloud-init config set -d \
'[ \
{ \
"name": "compute", \
Expand All @@ -41,7 +41,11 @@ This command sends a PUT to cloud-init.`,
} \
} \
} \
]'`,
]'
ochami cloud-init config set -f payload.json
ochami cloud-init config set -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami cloud-init config set -f -
echo '<yaml_data>' | ochami cloud-init config set -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// Without a base URI, we cannot do anything
cloudInitBaseURI, err := getBaseURI(cmd)
Expand All @@ -67,13 +71,7 @@ This command sends a PUT to cloud-init.`,
var ciData []citypes.CI
if cmd.Flag("payload").Changed {
// Use payload file if passed
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &ciData)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
handlePayload(cmd, &ciData)
} else if cmd.Flag("data").Changed {
// ...otherwise try to read raw JSON from CLI
rawJSON, err := cmd.Flags().GetString("data")
Expand Down
11 changes: 3 additions & 8 deletions cmd/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ var discoverCmd = &cobra.Command{
Long: `Populate SMD with data. Currently, this command performs "fake" discovery,
whereby data from a payload file is used to create the SMD structures.
In this way, the command does not perform dynamic discovery like Magellan,
but statically populates SMD using a file.
but statically populates SMD using a file. If - is used as the argument to
-f, the payload data is read from standard input.
The format of the payload file is an array of node specifications. In YAML,
each node entry would look something like:
Expand Down Expand Up @@ -82,13 +83,7 @@ nodes:

// Read data from payload file
nodes := discover.NodeList{}
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err = client.ReadPayload(dFile, dFormat, &nodes)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
handlePayload(cmd, &nodes)
log.Logger.Debug().Msgf("read %d nodes", len(nodes.Nodes))
log.Logger.Debug().Msgf("nodes: %s", nodes)

Expand Down
14 changes: 14 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,3 +398,17 @@ func setTokenFromEnvVar(cmd *cobra.Command) {
log.Logger.Error().Msgf("Environment variable %s unset for reading token for cluster %q", envVarToRead, clusterName)
os.Exit(1)
}

// handlePayload unmarshals a payload file into data for command cmd if
// --payload and, optionally, --payload-format, are passed.
func handlePayload(cmd *cobra.Command, data any) {
if cmd.Flag("payload").Changed {
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, data)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
}
}
18 changes: 7 additions & 11 deletions cmd/smd-compep-delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ var compepDeleteCmd = &cobra.Command{
Use: "delete -f <payload_file> | --all | <xname>...",
Short: "Delete one or more component endpoints",
Long: `Delete one or more component endpoints. These can be specified by one or more xnames.
Alternatively, pass the xnames in an array of component endpoint data
via a file with -f. If - is passed to -f, the data is read from standard
input.
This command sends a DELETE to SMD. An access token is required.`,
Example: ` ochami smd compep delete x3000c1s7b56n0 x3000c1s7b56n1
ochami smd compep delete --all
ochami smd compep delete -f payload.json
ochami smd compep delete -f payload.yaml --payload-format yaml`,
ochami smd compep delete -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami smd compep delete -f -
echo '<yaml_data>' | ochami smd compep delete -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// With options, only one of:
// - A payload file with -f
Expand Down Expand Up @@ -83,16 +88,7 @@ This command sends a DELETE to SMD. An access token is required.`,
var xnameSlice []string
if cmd.Flag("payload").Changed {
// Use payload file if passed
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &ceSlice)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
for _, ce := range ceSlice {
xnameSlice = append(xnameSlice, ce.ID)
}
handlePayload(cmd, &ceSlice)
} else {
// ...otherwise, use passed CLI arguments
xnameSlice = args
Expand Down
18 changes: 7 additions & 11 deletions cmd/smd-component-add.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ var componentAddCmd = &cobra.Command{
Use: "add -f <payload_file> | (<xname> <node_id>)",
Short: "Add new component(s)",
Long: `Add new component(s). A name (xname) and node ID (int64) are required unless
-f is passed to read from a payload file. Specifying -f also is mutually exclusive with the
other flags of this command.
-f is passed to read from a payload file. Specifying -f also is
mutually exclusive with the other flags of this command. If - is
used as the argument to -f, the data is read from standard input.
This command sends a POST to SMD. An access token is required.`,
Example: ` ochami smd component add x3000c1s7b56n0 56
ochami smd component add --state Ready --enabled --role Compute --arch X86 x3000c1s7b56n0 56
ochami smd component add -f payload.json
ochami smd component add -f payload.yaml --payload-format yaml`,
ochami smd component add -f payload.yaml --payload-format yaml
echo '<json_data>' | ochami smd component add -f -
echo '<yaml_data>' | ochami smd component add -f - --payload-format yaml`,
Run: func(cmd *cobra.Command, args []string) {
// Check that all required args are passed
if len(args) == 0 && !cmd.Flag("payload").Changed {
Expand Down Expand Up @@ -61,14 +64,7 @@ This command sends a POST to SMD. An access token is required.`,

var compSlice client.ComponentSlice
if cmd.Flag("payload").Changed {
// Use payload file if passed
dFile := cmd.Flag("payload").Value.String()
dFormat := cmd.Flag("payload-format").Value.String()
err := client.ReadPayload(dFile, dFormat, &compSlice)
if err != nil {
log.Logger.Error().Err(err).Msg("unable to read payload for request")
os.Exit(1)
}
handlePayload(cmd, &compSlice)
} else {
// ...otherwise use CLI options
comp := client.Component{
Expand Down
Loading

0 comments on commit e09a76b

Please sign in to comment.