Skip to content

Update collect to take input with specified format - #130

Open
davidallendj wants to merge 37 commits into
mainfrom
allend/collect-json-input
Open

Update collect to take input with specified format#130
davidallendj wants to merge 37 commits into
mainfrom
allend/collect-json-input

Conversation

@davidallendj

@davidallendj davidallendj commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Template

Thank you for your contribution! Please ensure the following before submitting:

Checklist

  • My code follows the style guidelines of this project
  • I have added/updated comments where needed
  • I have added tests that prove my fix is effective or my feature works
  • I have run make test (or equivalent) locally and all tests pass
  • DCO Sign-off: All commits are signed off (git commit -s) with my real name and email
  • [] REUSE Compliance:
    • Each new/modified source file has SPDX copyright and license headers
    • Any non-commentable files include a <filename>.license sidecar
    • All referenced licenses are present in the LICENSES/ directory

Description

This PR changes the collect command to take JSON or YAML as input from the scan command. This allows for the entire discovery process to be completed as a single command without hitting the file system.

Examples:

# scan -> collect
magellan scan --subnet 172.18.0.0/24 --port 5000 -l info -i -F json | magellan collect -f json --show-output -i

# scan -> collect -> send
magellan scan --subnet 172.18.0.0/24 --port 5000 -l info -i -F json | magellan collect -f json --show-output -i | magellan send https://smd.example.com

# collect -> send
magellan collect pdu x3000m0 x3000m1 -u admin -p password | magellan send https://smd.example.com

Fixes #128

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

For more info, see Contributing Guidelines.

@davidallendj
davidallendj force-pushed the allend/collect-json-input branch from e59ee6e to 92bdb3b Compare April 6, 2026 22:24

@synackd synackd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing with real BMCs.

Scanning:

$ ./magellan scan --subnet 172.16.0.0/24 -l info -i -F json --insecure
{"level":"warn","error":"RegisterFlagCompletionFunc: flag 'format' does not exist","time":"2026-05-14T13:45:41-06:00","message":"failed to register completion function"}
[
  {
    "host": "https://172.16.0.105",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.948173759-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.104",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947999177-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.102",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947644981-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.101",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947476248-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.103",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947691662-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.199",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.948031377-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.198",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947765703-06:00",
    "service_type": "Redfish"
  }
]

Scanning piping to collect:

$ ./magellan scan --subnet 172.16.0.0/24 -l info -i -F json --insecure | ./magellan collect -f json --show-output -i
{"level":"warn","error":"RegisterFlagCompletionFunc: flag 'format' does not exist","time":"2026-05-14T13:46:07-06:00","message":"failed to register completion function"}
{"level":"warn","error":"RegisterFlagCompletionFunc: flag 'format' does not exist","time":"2026-05-14T13:46:07-06:00","message":"failed to register completion function"}
{"level":"error","error":"no file found","time":"2026-05-14T13:46:07-06:00","caller":"/opt/shared/magellan/cmd/collect.go:61","message":"failed to get scanned results from cache"}
{"level":"error","error":"no assets found","time":"2026-05-14T13:46:07-06:00","caller":"/opt/shared/magellan/cmd/collect.go:178","message":"failed to collect data"}
null

Comment thread cmd/collect.go
@davidallendj

Copy link
Copy Markdown
Collaborator Author

Testing with real BMCs.

Scanning:

$ ./magellan scan --subnet 172.16.0.0/24 -l info -i -F json --insecure
{"level":"warn","error":"RegisterFlagCompletionFunc: flag 'format' does not exist","time":"2026-05-14T13:45:41-06:00","message":"failed to register completion function"}
[
  {
    "host": "https://172.16.0.105",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.948173759-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.104",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947999177-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.102",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947644981-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.101",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947476248-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.103",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947691662-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.199",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.948031377-06:00",
    "service_type": "Redfish"
  },
  {
    "host": "https://172.16.0.198",
    "port": 443,
    "protocol": "tcp",
    "state": true,
    "timestamp": "2026-05-14T13:45:41.947765703-06:00",
    "service_type": "Redfish"
  }
]

Scanning piping to collect:

$ ./magellan scan --subnet 172.16.0.0/24 -l info -i -F json --insecure | ./magellan collect -f json --show-output -i
{"level":"warn","error":"RegisterFlagCompletionFunc: flag 'format' does not exist","time":"2026-05-14T13:46:07-06:00","message":"failed to register completion function"}
{"level":"warn","error":"RegisterFlagCompletionFunc: flag 'format' does not exist","time":"2026-05-14T13:46:07-06:00","message":"failed to register completion function"}
{"level":"error","error":"no file found","time":"2026-05-14T13:46:07-06:00","caller":"/opt/shared/magellan/cmd/collect.go:61","message":"failed to get scanned results from cache"}
{"level":"error","error":"no assets found","time":"2026-05-14T13:46:07-06:00","caller":"/opt/shared/magellan/cmd/collect.go:178","message":"failed to collect data"}
null

I think this may be happening because the --cache-path flag is set to a non-empty string by default.

This is where the check happens:
https://github.com/OpenCHAMI/magellan/blob/allend/collect-json-input/cmd/collect.go#L58

And here is where the flag default is set:
https://github.com/OpenCHAMI/magellan/blob/allend/collect-json-input/cmd/root.go#L93

I can run it by setting --cache "" but I'm running to another problem that I'm working to address.

./magellan scan --subnet 172.16.0.0/24 -l info -i -F json | ./magellan collect -f json --show-output -i --cache "" -l debug

@davidallendj
davidallendj force-pushed the allend/collect-json-input branch from cbe75b6 to 7b1e8d4 Compare June 1, 2026 20:32
@davidallendj

Copy link
Copy Markdown
Collaborator Author

@synackd It should be working now. I had to add some missing logic back to cmd/collect.go and update some of the CLI flags. I don't think I like having to explicitly set --cache "" for this to work though...

This is the command I'm using to test currently:

./magellan scan --subnet 172.16.0.0/24 -l info -i -F json | ./magellan collect -f json --show-output -i --cache "" -l debug

@synackd

synackd commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

That command line worked for me. What if we added a check to see that stdin was open and, if so, used that instead of a cache unless explicitly told to do so?

@synackd synackd changed the title Update collect take input with specified format Update collect take input with specified format Jun 1, 2026
@synackd synackd changed the title Update collect take input with specified format Update collect to take input with specified format Jun 1, 2026
@synackd

synackd commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

That command line worked for me. What if we added a check to see that stdin was open and, if so, used that instead of a cache unless explicitly told to do so?

@davidallendj Just wanted to check in again with this to see if this was something we wanted to add in this PR.

@davidallendj

Copy link
Copy Markdown
Collaborator Author

That command line worked for me. What if we added a check to see that stdin was open and, if so, used that instead of a cache unless explicitly told to do so?

@davidallendj Just wanted to check in again with this to see if this was something we wanted to add in this PR.

Yes, I think we should. I just haven't gotten back around to add it. If you already have it implemented though, feel free to push to this branch and we can get this merged.

@synackd

synackd commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Understood. I didn't attempt it in order to avoid possibly duplicating your work. All yours. 🙂

@alexlovelltroy

Copy link
Copy Markdown
Member

@synackd seems to have approved. Is that true?

@synackd

synackd commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

I believe we are waiting for @davidallendj to implement this:

That command line worked for me. What if we added a check to see that stdin was open and, if so, used that instead of a cache unless explicitly told to do so?

@davidallendj Just wanted to check in again with this to see if this was something we wanted to add in this PR.

Yes, I think we should. I just haven't gotten back around to add it. If you already have it implemented though, feel free to push to this branch and we can get this merged.

@davidallendj

Copy link
Copy Markdown
Collaborator Author

Sorry this took so long. It was taking a minute to get some of the behaviors correct, but both of these cases should work like expected and --cache "" is no longer required.

./magellan scan --subnet 172.18.0.0/24 -l info -i --port 5000
./magellan collect -f json --show-output -i -l debug
./magellan scan --subnet 172.18.0.0/24 -l info -i -F json --port 5000 | ./magellan collect -f json --show-output -i -l debug

@davidallendj
davidallendj force-pushed the allend/collect-json-input branch 2 times, most recently from f817c9a to 98aa0e6 Compare July 22, 2026 23:02
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
davidallendj and others added 13 commits July 22, 2026 17:03
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: Polly Labs <pollychen.lab@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
This reverts commit bcb1a01.

Signed-off-by: David J. Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>
@davidallendj
davidallendj force-pushed the allend/collect-json-input branch from 98aa0e6 to 1a4a3f2 Compare July 22, 2026 23:03
@synackd

synackd commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Just tested again with:

  1. Piping scan output into collect:
./magellan scan --subnet 172.16.0.0/24 -l info -i -F json | ./magellan collect -f json --show-output -i -l debug
  1. Using default cache path:
./magellan scan --subnet 172.16.0.0/24 -l info -i
./magellan collect --show-output -i
  1. Using non-default cache path:
./magellan scan --subnet 172.16.0.0/24 -l info -i --cache ./assets.db
./magellan collect --show-output -i --cache ./assets.db

These all worked as expected.

@synackd synackd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One possible code fix and several documentation updates.

Comment thread cmd/collect.go Outdated
Comment thread README.md
Comment thread man/magellan-collect.1.sc
Comment thread cmd/send.go
Comment thread cmd/list.go
Comment thread cmd/crawl.go
Comment thread cmd/send.go
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>

@synackd synackd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I retested all of the mentioned test cases and they worked as expected. However, I found an error when testing YAML with piping commands. There is some other weird behavior I found as well as well as some small documentation updates that are needed.

Comment thread cmd/collect.go Outdated
Comment thread README.md Outdated
Comment thread cmd/collect.go Outdated
Comment thread cmd/collect.go Outdated
Comment thread cmd/collect.go Outdated
Comment thread cmd/scan.go Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Signed-off-by: David Allen <davidallendj@gmail.com>
@davidallendj
davidallendj requested a review from synackd July 27, 2026 19:05
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>

@synackd synackd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like most things are fixed, but found one more potential issue. I think after that and #130 (comment) we should be good. Will test after changes are pushed.

Comment thread cmd/send.go Outdated
Signed-off-by: David Allen <davidallendj@gmail.com>
Signed-off-by: David Allen <davidallendj@gmail.com>

@synackd synackd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly one code fix with some more documentation fixes.

Comment thread cmd/send.go
Comment on lines 198 to 215
} else {
// input should be a valid JSON
var (
data JSONArray
input = []byte(arg)
err error
)
if !json.Valid(input) {
log.Error().Msgf("argument %d not a valid JSON", i)
continue
}
err = json.Unmarshal(input, &data)
if err != nil {
log.Error().Err(err).Msgf("failed to unmarshal input for argument %d", i)
}
return data
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use format.UnmarshalData() instead of the JSON unmarshaller so inline YAML data passed with -d/--data will honor -f yaml, e.g:

			} else {
				// input should be valid data in the selected input format
				var (
					data  JSONArray
					input = []byte(arg)
					err   error
				)
				err = format.UnmarshalData(input, &data, inputFormat)
				if err != nil {
					log.Error().Err(err).Msgf("failed to unmarshal %s input for argument %d", inputFormat, i)
				}
				return data
			}

Comment thread cmd/scan.go
magellan scan --subnet 10.0.0.0/16 -i

// same as above example but output is in JSON without caching
magellan scan --subnet 10.0.0.0/16 -i -f json --disable-cache

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be -F?

Comment thread cmd/send.go
magellan send -d @inventory.json https://smd.openchami.cluster

// send data from multiple files (must specify -f/--format if not JSON)
// send data from multiple files (must specify -F/--output-format if not JSON)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be -f?

Comment thread man/magellan-scan.1.sc
Comment on lines -31 to +34
// assumes subnet without CIDR has a subnet-mask of 255.255.0.0++
// assumes subnet without CIDR has a subnet-mask of 255.255.0.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll want to keep the ++ otherwise the command will be on the same line as the comment.

Comment thread man/magellan-scan.1.sc
magellan scan --subnet 10.0.0.0/16 -i

// same as above example but output is in JSON without caching
magellan scan --subnet 10.0.0.0/16 -i -f json --disable-cache

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this use -F since we are outputting?

Comment thread cmd/send.go
sendCmd.Flags().StringArrayVarP(&sendDataArgs, "data", "d", []string{}, "Set the data to send to specified host (prepend @ for files)")
sendCmd.Flags().VarP(&sendInputFormat, "format", "F", "Set the default data input format (json|yaml) can be overridden by file extension")
sendCmd.Flags().BoolVarP(&forceUpdate, "force-update", "f", false, "Set flag to force update data sent to SMD")
sendCmd.Flags().VarP(&sendInputFormat, "input-format", "f", "Set the default data input format (json|yaml) can be overridden by file extension")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magellan send -d @nodes.yaml -F yaml https://smd.example.com

-F -> -f to match this flag

Signed-off-by: David Allen <davidallendj@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Allow collect to take JSON or YAML as input

4 participants