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

Add a --output=reg|json option to rdctl list-settings #5006

Merged
merged 17 commits into from
Jul 5, 2023

Conversation

ericpromislow
Copy link
Contributor

Fixes #4562

Options are --output=reg[,hklm|hkcu][,defaults|locked]

defaults are hklm and defaults

Output is written to stdout

To run unit tests:

cd src/go/rdctl/pkg/reg
go test .

@jandubois
Copy link
Member

The E2E test is failing:

-   "stdout": StringContaining "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Rancher Desktop\\Profile\\defaults]",
...
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Profiles\\Rancher Desktop\\defaults]

The Profiles substring is in a different place.

Note that the expected string specifies the "legacy" location from the 1.8 release.

The actual string in the output does not use the correct current location, which uses Policies in place of Profiles:

[HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Rancher Desktop\\defaults]

Copy link
Member

@jandubois jandubois left a comment

Choose a reason for hiding this comment

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

Please generate the correct current profile locations in the *.reg files, and fix the E2E test to match.

@ericpromislow
Copy link
Contributor Author

I moved the e2e tests to bats tests in preferences/list-settings-output.bats , but the assert-output
test gives a false pass at

If I add some nonsense to any line after the first line of the heredoc, the test still passes. The docs in bats/bats-assert/README.md talk about displaying failures for multi-line strings in multi-line format, but I'm not seeing that happen.

@ericpromislow ericpromislow marked this pull request as draft June 21, 2023 20:48
@ericpromislow ericpromislow marked this pull request as ready for review June 21, 2023 21:10
@ericpromislow
Copy link
Contributor Author

Please generate the correct current profile locations in the *.reg files, and fix the E2E test to match.

Done. This is why we have reviews.

Copy link
Contributor

@mook-as mook-as left a comment

Choose a reason for hiding this comment

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

Do we need to output version in the registry? I can see it going either way…

func init() {
rootCmd.AddCommand(listSettingsCmd)
listSettingsCmd.Flags().StringVarP(&outputSettings, "output", "", "", "output format: json|reg[,hive][,type], default json")
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a bit confusing to parse. Would it be possible to make hive and type their own parameters (that are ignored unless --output=reg) instead? I'm imagining something like rdctl list-settings --output=reg --hive=hkcu --locked.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This sounds better, except it should be an error if --hive and/or --locked or--defaults are specified and --output=reg isn't. @jandubois ?

As for the version field, I still think doing a conversion would be more useful than having to manually edit (or process) a generated reg file to pull out only the lines the user cares about.

src/go/rdctl/cmd/listSettings.go Outdated Show resolved Hide resolved
src/go/rdctl/pkg/reg/reg.go Show resolved Hide resolved
// an array of lines representing the current value
// boolean: true if the current entry is empty
// error
func convertToRegFormat(pathParts []string, v reflect.Value, jsonTag string) ([]string, bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The doc block for this function is… very atypical for golang. Would it be possible to format it better so that it's more readable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked up godoc, and don't see a conventional way to document either the parameters or the return values, so I expanded it a bit.

/**
* @param hiveType: "hklm" or "hkcu"
* @param profileType: "defaults" or "locked"
* @param settingsBodyAsJSON - options marshaled as JSON
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be clearer if we made the caller do the unmarshalling, I think. If we make this generic (that's an option now, or we use interface{}), we might even be able to test with structs that are limited by the settings format.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I misunderstood this comment, but after spending a bit of time on it I disagree.

The problem with this approach is that it makes writing tests onerous without a code-generation tool.

It's easy to both write and read a block of JSON code for a specific test, and verify the output. But if I have to create a structure, I'll have to assign each constant value to a variable, and then assign pointers to each variable that we care about. It's time-consuming to do that, and tedious for anyone to read the code.

The result is the same whether we do the unmarshaling in the caller or in the JsonToReg function, but overall
it's simpler and clearer to do the unmarshaling in the latter.

Talking about generalizing the types of structures we can pass to JsonToReg is YAGNI right now. Right now I don't reflect arrays of strings correctly, getting a ucs2 encoding of "<interface {} Value> <interface {} Value> <interface {} Value>" instead of the expected "abc" "def" "ghi", but that's because when I see an array in the reflector, I'm assuming it's an array of strings.

Also the generic converter now intermixes scalars and nested structs, which breaks the registry format, because all the scalar entries have to appear immediately after their containing struct's header. No point trying to figure out why this is happening unless and until we decide to generalize the converter.

Note that the unmarshaled struct will still need to have JSON tags in order to generate registry values.

Comment on lines +139 to +154
fullHiveType, ok := map[string]string{"hklm": "HKEY_LOCAL_MACHINE", "hkcu": "HKEY_CURRENT_USER"}[hiveType]
if !ok {
return nil, fmt.Errorf("unrecognized hiveType of '%s', must be 'hklm' or 'hkcu'", hiveType)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be good to allow case-insensitivity here (and for the other flag). But again, we should parse this elsewhere and just get passed in clean options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I implemented what was spec'ed in the issue. Jan opened it up for comments, and I was ok with it -- we should discuss this there, possibly in a separate issue, rather than holding up this work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made the right-side parts of --section= and --reg-hive case-insensitive, but all the help etc. will be in terms of the lower-case forms.

src/go/rdctl/pkg/reg/reg.go Outdated Show resolved Hide resolved
src/go/rdctl/pkg/reg/reg.go Show resolved Hide resolved
src/go/rdctl/pkg/reg/reg.go Outdated Show resolved Hide resolved
src/go/rdctl/pkg/reg/reg.go Show resolved Hide resolved
@ericpromislow ericpromislow force-pushed the 4562-add-reg-output-option branch 2 times, most recently from 11afc64 to 4dec4e4 Compare June 24, 2023 00:03
src/go/rdctl/cmd/listSettings.go Outdated Show resolved Hide resolved
Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

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

check-spelling found more than 10 potential problems in the proposed changes. Check the Files changed tab for more details.

src/go/rdctl/pkg/reg/reg.go Fixed Show fixed Hide fixed
src/go/rdctl/pkg/reg/reg_test.go Fixed Show fixed Hide fixed
src/go/rdctl/pkg/reg/reg_test.go Fixed Show fixed Hide fixed
src/go/rdctl/pkg/reg/reg_test.go Fixed Show fixed Hide fixed
src/go/rdctl/pkg/reg/reg_test.go Fixed Show fixed Hide fixed
Copy link
Contributor

@mook-as mook-as left a comment

Choose a reason for hiding this comment

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

Thanks for the changes! Just some relatively trivial things left.

src/go/rdctl/cmd/listSettings.go Outdated Show resolved Hide resolved
func init() {
rootCmd.AddCommand(listSettingsCmd)
listSettingsCmd.Flags().StringVarP(&outputSettingsFlags.Format, "output", "", jsonFormat, fmt.Sprintf("output format: %s|%s, default %s", jsonFormat, regFormat, jsonFormat))
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think you need to list the default here:

  --output string     output format: json|reg, default json (default "json")

func init() {
rootCmd.AddCommand(listSettingsCmd)
listSettingsCmd.Flags().StringVarP(&outputSettingsFlags.Format, "output", "", jsonFormat, fmt.Sprintf("output format: %s|%s, default %s", jsonFormat, regFormat, jsonFormat))
listSettingsCmd.Flags().StringVarP(&outputSettingsFlags.RegistryHive, "reg-hive", "", "", fmt.Sprintf("registry hive: %s|%s, default %s", reg.HklmRegistryHive, reg.HkcuRegistryHive, reg.HklmRegistryHive))
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, we're not setting defaults here because they don't apply to JSON (same with profile type)? Can't we just set a default here, and ignore the value if we're using JSON?

Copy link
Contributor Author

@ericpromislow ericpromislow Jul 4, 2023

Choose a reason for hiding this comment

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

I'd rather treat rdctl list-settings --output=json --reg-hive=hklm as an error because the output won't meet the user's expectations (whatever they might be).

src/go/rdctl/cmd/listSettings.go Outdated Show resolved Hide resolved
This is used to convert current settings into Windows registry file format.

* Generate a full options struct in golang representing all possible
  preference fields, including:
  * arrays
  * maps
  * fields used only for other platforms.

This is needed for this branch in order to convert JSON documents
containing the above constructs into reg-files, even if those features
aren't supported on the current platform.

This does not add support for specifying array or map values to
`rdctl set` or `rdctl start`, but is a pre-rec for those features.

* Reg files need to have scalar values appearing before nested structs.

  Otherwise, if scalar values appear after a nested struct is written out,
  it looks like the scalar belongs to the last nested struct, not the one
  it actually belongs to.

Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Basically, len(returnedLines) == 0 === isEmpty

Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
…=reg.

Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
- Add windows-registry-specific type terminology to `allow.txt`
- Stop using nonsense words in tests.

Signed-off-by: Eric Promislow <epromislow@suse.com>
…section`.

Noted that the allowed values for `--output` are case-*sensitive*.

The difference is that it's helpful if the user can use the same case that the
registry uses, namely all-caps for `--reg-hive` (e.g. HKLM_LOCAL_MACHINE`),
and capitalized for `--section` (like 'Defaults').  `reg` and `json` are
names of output-formats that we are proposing.

Also I don't convert the names to all-lower-case until I know we're using
them, so I have the original case if I need to put the entered string
in an error message.

Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
…tivity.

Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
Signed-off-by: Eric Promislow <epromislow@suse.com>
@ericpromislow ericpromislow merged commit dd3e089 into main Jul 5, 2023
14 checks passed
@ericpromislow ericpromislow deleted the 4562-add-reg-output-option branch July 5, 2023 17:12
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.

Add REG output option to rdctl settings
3 participants