Skip to content

Implements a new generate-config subcommand that auto-generates examp…#13385

Open
nmn3m wants to merge 4 commits intok3s-io:mainfrom
nmn3m:13071-generate-config
Open

Implements a new generate-config subcommand that auto-generates examp…#13385
nmn3m wants to merge 4 commits intok3s-io:mainfrom
nmn3m:13071-generate-config

Conversation

@nmn3m
Copy link

@nmn3m nmn3m commented Dec 27, 2025

Proposed Changes

This PR implements a new generate-config subcommand that auto-generates example configuration files for k3s server and agent nodes, addressing the need for better discoverability of configuration options.

The implementation provides:

  • A k3s generate-config command that generates fully commented YAML configuration files
  • Support for both server and agent config types via --type flag
  • Ability to show current values from existing configs via --from-config flag
  • Output to stdout or file via --output flag
  • All configuration options organized by category (listener, cluster, networking, etc.)
  • Each option includes its help text as a comment with default values where applicable

New files:

  • pkg/cli/cmds/generate_config.go - Command definition
  • pkg/cli/generateconfig/generate_config.go - Implementation logic

Modified files:

  • pkg/cli/cmds/agent.go - Exported AgentFlags variable to match ServerFlags pattern
  • cmd/k3s/main.go - Registered command in multicall binary
  • main.go - Registered command in standalone binary

Types of Changes

New Feature - Adds a new CLI subcommand for generating example configuration files

Verification

The changes can be verified by:

  1. Generate server config to stdout:

    k3s generate-config --type server
  2. Generate agent config to a file:

    k3s generate-config --type agent --output /tmp/agent-config.yaml
  3. Generate config with current values from existing file:

    k3s generate-config --type server --from-config /etc/rancher/k3s/config.yaml
  4. Verify help text:

    k3s generate-config --help
  5. Test invalid input:

    k3s generate-config --type invalid
    # Should return error: invalid config type "invalid", must be 'server' or 'agent'

Expected output includes all available k3s configuration options organized by category with comments explaining each option's purpose and default values.

Testing

  • No automated tests added as this is a CLI utility command that generates static output based on flag definitions. The command uses reflection to read existing flag metadata and doesn't modify any runtime behavior.

Linked Issues

Addresses #13071

User-Facing Change

Added new `generate-config` subcommand to generate example k3s configuration files with all available options and their descriptions. Users can now run `k3s generate-config --type server` or `k3s generate-config --type agent` to create fully documented config.yaml templates.

Further Comments

Design Decision: --from-config vs --config

The implementation uses --from-config instead of reusing the existing --config flag. This is intentional because k3s uses configfilearg.MustParse() which automatically parses any file specified by --config and converts YAML keys to CLI arguments. Since generate-config doesn't accept server/agent flags (like --token, --cluster-cidr, etc.), using --config would cause parsing errors when trying to apply those flags to the generate-config command.

Example of the problem if we used --config:

# config.yaml contains: token: import1234
k3s generate-config --config config.yaml
# Error: flag provided but not defined: -token

Using --from-config keeps the flags separate and allows the command to read existing configs for reference without triggering automatic parsing.

Implementation Approach

The solution uses reflection to extract flag metadata (name, usage, default values) from the existing ServerFlags and AgentFlags arrays. This ensures the generated configs stay automatically synchronized with any future flag additions or modifications - no manual maintenance required.

To enable this, AgentFlags was exported in agent.go to match the existing ServerFlags pattern, maintaining consistency across the codebase.

@nmn3m nmn3m requested a review from a team as a code owner December 27, 2025 18:51
@nmn3m nmn3m force-pushed the 13071-generate-config branch from 63e2138 to 90e4874 Compare December 27, 2025 18:52
Copy link
Member

@brandond brandond 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 contribution!

There a couple moderate changes I'd like to see here:

  • Use templates and fmt.Fprintf when using a stringbuilder, instead of printing to a string and then writing the string to the builder.
  • Do not use reflection unless absolutely necessary. urfave/cli has a bunch of interfaces to get most if not all of the information you are trying to extract from flags. Use them. Reflection should be a last resort. We manage to wrap all the K3s flags in RKE2 without needing to do any reflection; you should be able to do the same here.

Comment on lines +59 to +71
// generateYAMLWithComments creates a YAML string with comments
func generateYAMLWithComments(flags []cli.Flag, existingConfig interface{}, currentValues map[string]interface{}, configType string) string {
var sb strings.Builder

sb.WriteString(fmt.Sprintf("# Example k3s %s configuration file\n", configType))
sb.WriteString("#\n")
sb.WriteString("# This file contains all available configuration options with their descriptions.\n")
sb.WriteString("# Uncomment and modify the options you want to use.\n")
sb.WriteString("#\n")
sb.WriteString(fmt.Sprintf("# Place this file at /etc/rancher/k3s/config.yaml or use --config to specify a different location.\n"))
sb.WriteString("#\n\n")

categories := groupFlagsByCategory(flags)
Copy link
Member

@brandond brandond Jan 14, 2026

Choose a reason for hiding this comment

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

Make this header a template string, and render it into the stringbuilder.

Suggested change
// generateYAMLWithComments creates a YAML string with comments
func generateYAMLWithComments(flags []cli.Flag, existingConfig interface{}, currentValues map[string]interface{}, configType string) string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("# Example k3s %s configuration file\n", configType))
sb.WriteString("#\n")
sb.WriteString("# This file contains all available configuration options with their descriptions.\n")
sb.WriteString("# Uncomment and modify the options you want to use.\n")
sb.WriteString("#\n")
sb.WriteString(fmt.Sprintf("# Place this file at /etc/rancher/k3s/config.yaml or use --config to specify a different location.\n"))
sb.WriteString("#\n\n")
categories := groupFlagsByCategory(flags)
const yamlHeader = `
{{- /* */ -}}
# Example {{ .Program }} {{ .Command }} configuration file
# This file contains all available configuration options with their descriptions.
# Uncomment and modify the options you want to use.
# Place this file at /etc/rancher/{{ .Program }}/config.yaml or use --config to specify a different location.
#
`
type cmdInfo struct {
Program string
Command string
}
// generateYAMLWithComments creates a YAML string with comments
func generateYAMLWithComments(flags []cli.Flag, existingConfig interface{}, currentValues map[string]interface{}, configType string) (string, error) {
var sb strings.Builder
tmpl, err := template.New("config").Parse(yamlHeader")
if err != nil {
return "", err
}
if err = tmpl.Execute(&sb, cmdInfo{Program: version.Program, Command: configType}); err != nil {
return "", err
}
}
categories := groupFlagsByCategory(flags)

Comment on lines +83 to +85
sb.WriteString(fmt.Sprintf("# %s\n", strings.Repeat("=", 80)))
sb.WriteString(fmt.Sprintf("# %s\n", categoryName))
sb.WriteString(fmt.Sprintf("# %s\n\n", strings.Repeat("=", 80)))
Copy link
Member

Choose a reason for hiding this comment

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

Print directly into the stringbuilder - that's how its meant to be used.

Suggested change
sb.WriteString(fmt.Sprintf("# %s\n", strings.Repeat("=", 80)))
sb.WriteString(fmt.Sprintf("# %s\n", categoryName))
sb.WriteString(fmt.Sprintf("# %s\n\n", strings.Repeat("=", 80)))
fmt.Fprintf(&sb, "# %s\n", strings.Repeat("=", 80))
fmt.Fprintf(&sb, "# %s\n", categoryName)
fmt.Fprintf(&sb, "# %s\n\n", strings.Repeat("=", 80))

Copy link
Member

@brandond brandond left a comment

Choose a reason for hiding this comment

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

as described above

@nmn3m nmn3m force-pushed the 13071-generate-config branch 2 times, most recently from 4f97322 to 286a4ce Compare January 14, 2026 23:42
@nmn3m
Copy link
Author

nmn3m commented Jan 14, 2026

@brandond , Thanks for your feedback, I solved all review comments.

@nmn3m nmn3m requested a review from brandond January 14, 2026 23:44
@brandond
Copy link
Member

@nmn3m are you still working on this? I believe this can be done with no or at least much less use of reflect.

@nmn3m nmn3m force-pushed the 13071-generate-config branch from 286a4ce to a264c81 Compare January 28, 2026 15:40
@nmn3m
Copy link
Author

nmn3m commented Jan 28, 2026

@nmn3m are you still working on this? I believe this can be done with no or at least much less use of reflect.

I fixed all mentioned parts, thanks

@nmn3m nmn3m requested a review from brandond January 28, 2026 15:43
nmn3m added 3 commits January 28, 2026 19:39
…le configuration files for k3s server and agent nodes

Signed-off-by: Nour <nurmn3m@gmail.com>
…faces for flag helpers

Signed-off-by: Nour <nurmn3m@gmail.com>
…g helpers

Signed-off-by: Nour <nurmn3m@gmail.com>
@codecov
Copy link

codecov bot commented Jan 28, 2026

Codecov Report

❌ Patch coverage is 0% with 167 lines in your changes missing coverage. Please review.
✅ Project coverage is 21.48%. Comparing base (f061615) to head (edf8b27).

Files with missing lines Patch % Lines
pkg/cli/generateconfig/generate_config.go 0.00% 159 Missing ⚠️
pkg/cli/cmds/generate_config.go 0.00% 7 Missing ⚠️
pkg/cli/cmds/agent.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #13385      +/-   ##
==========================================
+ Coverage   21.46%   21.48%   +0.01%     
==========================================
  Files         190      192       +2     
  Lines       15479    15576      +97     
==========================================
+ Hits         3323     3346      +23     
- Misses      11703    11770      +67     
- Partials      453      460       +7     
Flag Coverage Δ
unittests 21.48% <0.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@brandond
Copy link
Member

brandond commented Jan 28, 2026

Please address linter issues - interface{} should be any in particular.

Are you writing this code by hand, or using AI tools?

Signed-off-by: Nour <nurmn3m@gmail.com>
@nmn3m
Copy link
Author

nmn3m commented Jan 29, 2026

Please address linter issues - interface{} should be any in particular.

Are you writing this code by hand, or using AI tools?

I mix between writing by hand , reviewing and fixing with AI.
I solve the mention point.

Copy link
Member

@brandond brandond left a comment

Choose a reason for hiding this comment

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

  1. Looks like you need a go mod tidy and check in the resulting changes. Are you testing this locally with make validate?
  2. Please add the new command to cmd/server/main.go as well.

@brandond
Copy link
Member

brandond commented Mar 7, 2026

@nmn3m are you able to make the requested changes to this PR?

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.

2 participants