Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support reading JSON data from STDIN #1905

Merged
merged 1 commit into from
Oct 21, 2020

Conversation

hiyosi
Copy link
Contributor

@hiyosi hiyosi commented Oct 10, 2020

Signed-off-by: Tomoya Usami tousami@zlab.co.jp

Pull Request check list

  • Commit conforms to CONTRIBUTING.md?
  • Proper tests/regressions included?
  • Documentation updated?

Affected functionality

Server CLI: entry create/update

Description of change

entry create/update commands accept JSON data from STDIN.

Which issue this PR fixes

#1864

@hiyosi
Copy link
Contributor Author

hiyosi commented Oct 10, 2020

parameter

$ kubectl exec -n spire spire-server-0 -- bin/spire-server entry create -spiffeID spiffe://example.org/web -parentID spiffe://example.org/my-server -selector k8s:ns:web -selector k8s:sa:web
Entry ID      : 15acd155-28e9-4a06-8263-ac0ad09c7e2c
SPIFFE ID     : spiffe://example.org/web
Parent ID     : spiffe://example.org/my-server
Revision      : 0
TTL           : default
Selector      : k8s:ns:web
Selector      : k8s:sa:web

file

$ kubectl exec -n spire spire-server-0 -- bin/spire-server entry create -data test-entry.json
Entry ID      : 4780c252-6635-47c9-a870-6628a557e292
SPIFFE ID     : spiffe://example.org/app
Parent ID     : spiffe://example.org/my-server
Revision      : 0
TTL           : default
Selector      : k8s:ns:app
Selector      : k8s:sa:app

stdin

cat test-registration.json | kubectl exec -i -n spire spire-server-0 -- bin/spire-server entry create -data -
Entry ID      : 79da91cf-ae13-4bb8-aae8-c92166f74642
SPIFFE ID     : spiffe://example.org/db
Parent ID     : spiffe://example.org/my-server
Revision      : 0
TTL           : default
Selector      : k8s:ns:db
Selector      : k8s:sa:db

update

cat update-registration.json | kubectl exec -i -n spire spire-server-0 -- bin/spire-server entry update -data -
Entry ID      : c7f606a5-4457-4234-9c6f-cb72eda9efc4
SPIFFE ID     : spiffe://example.org/db
Parent ID     : spiffe://example.org/my-server
Revision      : 1
TTL           : default
Selector      : k8s:ns:db
Selector      : k8s:sa:db
Admin         : true

@hiyosi hiyosi force-pushed the entry_json_from_stdin branch 2 times, most recently from 42bf8d7 to aa95332 Compare October 10, 2020 02:31
Copy link
Contributor

@blaggacao blaggacao left a comment

Choose a reason for hiding this comment

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

From my side just some minor wording suggestions. Thank you for the work!

Otherwise LGTM

@@ -233,7 +218,7 @@ func (CreateCLI) newConfig(args []string) (*CreateConfig, error) {
f.StringVar(&c.SpiffeID, "spiffeID", "", "The SPIFFE ID that this record represents")
f.IntVar(&c.TTL, "ttl", 0, "The lifetime, in seconds, for SVIDs issued based on this registration entry")

f.StringVar(&c.Path, "data", "", "Path to a file containing registration JSON (optional)")
f.StringVar(&c.Path, "data", "", "Path to a file containing registration JSON (optional). If set '-' as file path, read the JSON passed into stdin.")

This comment was marked as resolved.

@@ -219,7 +204,7 @@ func (UpdateCLI) newConfig(args []string) (*UpdateConfig, error) {
f.StringVar(&c.SpiffeID, "spiffeID", "", "The SPIFFE ID that this record represents")
f.IntVar(&c.TTL, "ttl", 0, "The lifetime, in seconds, for SVIDs issued based on this registration entry")

f.StringVar(&c.Path, "data", "", "Path to a file containing registration JSON (optional)")
f.StringVar(&c.Path, "data", "", "Path to a file containing registration JSON (optional). If set '-' as file path, read the JSON passed into stdin.")

This comment was marked as resolved.

@@ -229,7 +229,7 @@ Creates registration entries.
| Command | Action | Default |
|:-----------------|:-----------------------------------------------------------------------|:---------------|
| `-admin` | If set, the SPIFFE ID in this entry will be granted access to the Registration API | |
| `-data` | Path to a file containing registration data in JSON format (optional). | |
| `-data` | Path to a file containing registration data in JSON format (optional). If set '-' as file path, read the JSON passed into stdin. | |

This comment was marked as resolved.

@@ -248,7 +248,7 @@ Updates registration entries.
| Command | Action | Default |
|:-----------------|:-----------------------------------------------------------------------|:---------------|
| `-admin` | If true, the SPIFFE ID in this entry will be granted access to the Registration API | |
| `-data` | Path to a file containing registration data in JSON format (optional). | |
| `-data` | Path to a file containing registration data in JSON format (optional). If set '-' as file path, read the JSON passed into stdin. | |

This comment was marked as resolved.

@@ -91,6 +95,34 @@ func printEntry(e *common.RegistrationEntry) {
fmt.Println()
}

// ParseFile parses JSON represented RegistrationEntries
// if path is "" or "*" read JSON from STDIN
func ParseFile(in io.Reader, path string) ([]*common.RegistrationEntry, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Personally I think this can be made to:

func ParseFile(path string) ([]*common.RegistrationEntry, error) {
    return parseFile(os.Stdin, path)
}

func parseFile(stdin io.Reader, path string) ([]*common.RegistrationEntry, error) {
    ...
}

This provides a nice public API (the consumer doesn't need to pass os.Stdin, which is somewhat of an implementation detail), which also giving you the testability I believe you're looking for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Looks good!

6096a68

@@ -91,6 +95,34 @@ func printEntry(e *common.RegistrationEntry) {
fmt.Println()
}

// ParseFile parses JSON represented RegistrationEntries
// if path is "" or "*" read JSON from STDIN
Copy link
Contributor

Choose a reason for hiding this comment

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

Replace "*" with "-"

Also, I'm not confident we want to alias an empty path as stdin.. as it could mask user error.

Copy link
Contributor Author

@hiyosi hiyosi Oct 13, 2020

Choose a reason for hiding this comment

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

Yes, the empty path doesn't work well.
The comment seems to have just been forgotten to remove.

6096a68


var r io.Reader
if path == "-" {
r = in
Copy link
Contributor

Choose a reason for hiding this comment

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

this could be simplified to remove the else with something like:

r := stdin
if path != "-" {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r = f
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

6096a68

APTy
APTy previously approved these changes Oct 15, 2020
Copy link
Contributor

@APTy APTy left a comment

Choose a reason for hiding this comment

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

LGTM, but a few questions on the tests

@@ -91,6 +95,36 @@ func printEntry(e *common.RegistrationEntry) {
fmt.Println()
}

// ParseFile parses JSON represented RegistrationEntries
// if path is "-" read JSON from STDIN
func ParseFile(path string) ([]*common.RegistrationEntry, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this actually doesn't need to be a public method, since it's not used outside of this package

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, exactly.
587ac9c

assert.NoError(t, err)
// Replace os.Stdin temporary
orgStdin := os.Stdin
os.Stdin = fakeStdin
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer not to override the os.Stdin package global in tests.

One option is to use the dependency injection and test the parseFile(io.Reader, filename) function and leave ParseFile(filename) without directly testing it.

Another option is to set var stdin = os.Stdin and then replace the package local stdin var, which is much less invasive than mutating os.Stdin entirely.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

587ac9c
This commit changes the target and tests the parseFile(io.Reader, filename) function.

@@ -45,3 +49,93 @@ func selectorToFlag(t *testing.T, selectors []*common.Selector) StringsFlag {

return resp
}

func TestRegisterParseFile(t *testing.T) {
p := path.Join(util.ProjectRoot(), "test/fixture/registration/good.json")
Copy link
Contributor

Choose a reason for hiding this comment

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

is there any bad json we should test against?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

587ac9c
Invalid JSON is now also included in the test case.
Also refactored test functions.

@hiyosi hiyosi force-pushed the entry_json_from_stdin branch 4 times, most recently from 587ac9c to bd3d93e Compare October 19, 2020 23:22
APTy
APTy previously approved these changes Oct 20, 2020
Copy link
Contributor

@APTy APTy left a comment

Choose a reason for hiding this comment

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

LGTM!

@evan2645
Copy link
Member

Thank you for this feature @hiyosi!

We need to rebase the PR to get it merged in. Would you mind either rebasing/merging master or allowing us to do it? Thanks again!

Signed-off-by: Tomoya Usami <tousami@zlab.co.jp>

fixup! Support reading JSON data from STDIN

Signed-off-by: Tomoya Usami <tousami@zlab.co.jp>

fixup! fixup! Support reading JSON data from STDIN

Signed-off-by: Tomoya Usami <tousami@zlab.co.jp>
@hiyosi
Copy link
Contributor Author

hiyosi commented Oct 20, 2020

@APTy @evan2645 Done rebasing with master branch. Thanks!

@azdagron azdagron merged commit 8bf81b4 into spiffe:master Oct 21, 2020
@blaggacao
Copy link
Contributor

blaggacao commented Oct 21, 2020

@hiyosi Thank you very much for your effort! Supremely appreciated over here.

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.

None yet

5 participants