Skip to content

Commit

Permalink
feat: add ability to disable comments in talosctl gen config
Browse files Browse the repository at this point in the history
Fixes: #3384

Instead of doing simple `--no-comments` flag, decided to use more
granular approach which allows to either disable examples, or docstring,
or both.

Thus the command looks like this:

```bash
talosctl gen config --with-docs=false --with-examples=false <...>
```

Both are enabled by default to provide better UX for users learning
Talos.

Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
  • Loading branch information
Unix4ever authored and talos-bot committed Mar 29, 2021
1 parent a0dcfc3 commit 4b42ced
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 64 deletions.
3 changes: 2 additions & 1 deletion cmd/talosctl/cmd/mgmt/cluster/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/talos-systems/talos/pkg/images"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/encoder"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/bundle"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate"
Expand Down Expand Up @@ -436,7 +437,7 @@ func create(ctx context.Context) (err error) {
types = append([]machine.Type{machine.TypeInit}, types...)
}

if err = configBundle.Write(".", types...); err != nil {
if err = configBundle.Write(".", encoder.CommentsAll, types...); err != nil {
return err
}
}
Expand Down
68 changes: 41 additions & 27 deletions cmd/talosctl/cmd/mgmt/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import (
"github.com/talos-systems/talos/cmd/talosctl/pkg/mgmt/helpers"
"github.com/talos-systems/talos/pkg/images"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/encoder"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/bundle"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
"github.com/talos-systems/talos/pkg/machinery/constants"
)

var (
var genConfigCmdFlags struct {
additionalSANs []string
configVersion string
dnsDomain string
Expand All @@ -36,7 +37,9 @@ var (
outputDir string
registryMirrors []string
persistConfig bool
)
withExamples bool
withDocs bool
}

// genConfigCmd represents the gen config command.
var genConfigCmd = &cobra.Command{
Expand Down Expand Up @@ -77,7 +80,7 @@ var genConfigCmd = &cobra.Command{
return fmt.Errorf("error validating the cluster endpoint URL: %w", err)
}

switch configVersion {
switch genConfigCmdFlags.configVersion {
case "v1alpha1":
return genV1Alpha1Config(args)
}
Expand Down Expand Up @@ -106,21 +109,21 @@ func fixControlPlaneEndpoint(u *url.URL) *url.URL {
func genV1Alpha1Config(args []string) error {
// If output dir isn't specified, set to the current working dir
var err error
if outputDir == "" {
outputDir, err = os.Getwd()
if genConfigCmdFlags.outputDir == "" {
genConfigCmdFlags.outputDir, err = os.Getwd()
if err != nil {
return fmt.Errorf("failed to get working dir: %w", err)
}
}

// Create dir path, ignoring "already exists" messages
if err = os.MkdirAll(outputDir, os.ModePerm); err != nil && !os.IsExist(err) {
if err = os.MkdirAll(genConfigCmdFlags.outputDir, os.ModePerm); err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create output dir: %w", err)
}

var genOptions []generate.GenOption //nolint:prealloc

for _, registryMirror := range registryMirrors {
for _, registryMirror := range genConfigCmdFlags.registryMirrors {
components := strings.SplitN(registryMirror, "=", 2)
if len(components) != 2 {
return fmt.Errorf("invalid registry mirror spec: %q", registryMirror)
Expand All @@ -129,10 +132,10 @@ func genV1Alpha1Config(args []string) error {
genOptions = append(genOptions, generate.WithRegistryMirror(components[0], components[1]))
}

if talosVersion != "" {
if genConfigCmdFlags.talosVersion != "" {
var versionContract *config.VersionContract

versionContract, err = config.ParseContractFromVersion(talosVersion)
versionContract, err = config.ParseContractFromVersion(genConfigCmdFlags.talosVersion)
if err != nil {
return fmt.Errorf("invalid talos-version: %w", err)
}
Expand All @@ -145,13 +148,13 @@ func genV1Alpha1Config(args []string) error {
&bundle.InputOptions{
ClusterName: args[0],
Endpoint: args[1],
KubeVersion: strings.TrimPrefix(kubernetesVersion, "v"),
KubeVersion: strings.TrimPrefix(genConfigCmdFlags.kubernetesVersion, "v"),
GenOptions: append(genOptions,
generate.WithInstallDisk(installDisk),
generate.WithInstallImage(installImage),
generate.WithAdditionalSubjectAltNames(additionalSANs),
generate.WithDNSDomain(dnsDomain),
generate.WithPersist(persistConfig),
generate.WithInstallDisk(genConfigCmdFlags.installDisk),
generate.WithInstallImage(genConfigCmdFlags.installImage),
generate.WithAdditionalSubjectAltNames(genConfigCmdFlags.additionalSANs),
generate.WithDNSDomain(genConfigCmdFlags.dnsDomain),
generate.WithPersist(genConfigCmdFlags.persistConfig),
),
},
),
Expand All @@ -160,7 +163,16 @@ func genV1Alpha1Config(args []string) error {
return fmt.Errorf("failed to generate config bundle: %w", err)
}

if err = configBundle.Write(outputDir, machine.TypeInit, machine.TypeControlPlane, machine.TypeJoin); err != nil {
commentsFlags := encoder.CommentsDisabled
if genConfigCmdFlags.withDocs {
commentsFlags |= encoder.CommentsDocs
}

if genConfigCmdFlags.withExamples {
commentsFlags |= encoder.CommentsExamples
}

if err = configBundle.Write(genConfigCmdFlags.outputDir, commentsFlags, machine.TypeInit, machine.TypeControlPlane, machine.TypeJoin); err != nil {
return err
}

Expand All @@ -172,7 +184,7 @@ func genV1Alpha1Config(args []string) error {
return fmt.Errorf("failed to marshal config: %+v", err)
}

fullFilePath := filepath.Join(outputDir, "talosconfig")
fullFilePath := filepath.Join(genConfigCmdFlags.outputDir, "talosconfig")

if err = ioutil.WriteFile(fullFilePath, data, 0o644); err != nil {
return fmt.Errorf("%w", err)
Expand All @@ -185,14 +197,16 @@ func genV1Alpha1Config(args []string) error {

func init() {
genCmd.AddCommand(genConfigCmd)
genConfigCmd.Flags().StringVar(&installDisk, "install-disk", "/dev/sda", "the disk to install to")
genConfigCmd.Flags().StringVar(&installImage, "install-image", helpers.DefaultImage(images.DefaultInstallerImageRepository), "the image used to perform an installation")
genConfigCmd.Flags().StringSliceVar(&additionalSANs, "additional-sans", []string{}, "additional Subject-Alt-Names for the APIServer certificate")
genConfigCmd.Flags().StringVar(&dnsDomain, "dns-domain", "cluster.local", "the dns domain to use for cluster")
genConfigCmd.Flags().StringVar(&configVersion, "version", "v1alpha1", "the desired machine config version to generate")
genConfigCmd.Flags().StringVar(&talosVersion, "talos-version", "", "the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)")
genConfigCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", "", "desired kubernetes version to run")
genConfigCmd.Flags().StringVarP(&outputDir, "output-dir", "o", "", "destination to output generated files")
genConfigCmd.Flags().StringSliceVar(&registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
genConfigCmd.Flags().BoolVarP(&persistConfig, "persist", "p", true, "the desired persist value for configs")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.installDisk, "install-disk", "/dev/sda", "the disk to install to")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.installImage, "install-image", helpers.DefaultImage(images.DefaultInstallerImageRepository), "the image used to perform an installation")
genConfigCmd.Flags().StringSliceVar(&genConfigCmdFlags.additionalSANs, "additional-sans", []string{}, "additional Subject-Alt-Names for the APIServer certificate")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.dnsDomain, "dns-domain", "cluster.local", "the dns domain to use for cluster")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.configVersion, "version", "v1alpha1", "the desired machine config version to generate")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.talosVersion, "talos-version", "", "the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.kubernetesVersion, "kubernetes-version", "", "desired kubernetes version to run")
genConfigCmd.Flags().StringVarP(&genConfigCmdFlags.outputDir, "output-dir", "o", "", "destination to output generated files")
genConfigCmd.Flags().StringSliceVar(&genConfigCmdFlags.registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
genConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.persistConfig, "persist", "p", true, "the desired persist value for configs")
genConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withExamples, "with-examples", "", true, "renders all machine configs with the commented examples")
genConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withDocs, "with-docs", "", true, "renders all machine configs adding the documentation for each field")
}
8 changes: 4 additions & 4 deletions pkg/machinery/config/encoder/documentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func addComments(node *yaml.Node, doc *Doc, comments ...int) {
}

//nolint:gocyclo
func renderExample(key string, doc *Doc) string {
func renderExample(key string, doc *Doc, flags CommentsFlags) string {
if doc == nil {
return ""
}
Expand All @@ -218,19 +218,19 @@ func renderExample(key string, doc *Doc) string {

e.Populate(i)

node, err := toYamlNode(defaultValue)
node, err := toYamlNode(defaultValue, flags)
if err != nil {
continue
}

node, err = toYamlNode(map[string]*yaml.Node{
key: node,
})
}, flags)
if err != nil {
continue
}

if i == 0 {
if i == 0 && flags.enabled(CommentsDocs) {
addComments(node, doc, HeadComment, LineComment)
}

Expand Down
47 changes: 29 additions & 18 deletions pkg/machinery/config/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,46 @@ import (

// Encoder implements config encoder.
type Encoder struct {
value interface{}
value interface{}
options *Options
}

// NewEncoder initializes and returns an `Encoder`.
func NewEncoder(value interface{}) *Encoder {
func NewEncoder(value interface{}, opts ...Option) *Encoder {
return &Encoder{
value: value,
value: value,
options: newOptions(opts...),
}
}

// Marshal converts value to YAML-serializable value (suitable for MarshalYAML).
func (e *Encoder) Marshal() (*yaml.Node, error) {
node, err := toYamlNode(e.value)
node, err := toYamlNode(e.value, e.options.Comments)
if err != nil {
return nil, err
}

addComments(node, getDoc(e.value), HeadComment, LineComment)
if e.options.Comments.enabled(CommentsDocs) {
addComments(node, getDoc(e.value), HeadComment, LineComment)
}

return node, nil
}

// Encode converts value to yaml.
//nolint:gocyclo
func (e *Encoder) Encode() ([]byte, error) {
if e.options.Comments == CommentsDisabled {
return yaml.Marshal(e.value)
}

node, err := e.Marshal()
if err != nil {
return nil, err
}

// special handling for case when we get an empty output
if node.Kind == yaml.MappingNode && len(node.Content) == 0 && node.FootComment != "" {
if node.Kind == yaml.MappingNode && len(node.Content) == 0 && node.FootComment != "" && e.options.Comments.enabled(CommentsExamples) {
res := ""

if node.HeadComment != "" {
Expand Down Expand Up @@ -85,7 +94,7 @@ func isSet(value reflect.Value) bool {
}

//nolint:gocyclo,cyclop
func toYamlNode(in interface{}) (*yaml.Node, error) {
func toYamlNode(in interface{}, flags CommentsFlags) (*yaml.Node, error) {
node := &yaml.Node{}

// do not wrap yaml.Node into yaml.Node
Expand Down Expand Up @@ -183,8 +192,8 @@ func toYamlNode(in interface{}) (*yaml.Node, error) {
fieldDoc = getDoc(value)
}

if !defined {
example := renderExample(fieldName, fieldDoc)
if !defined && flags.enabled(CommentsExamples) {
example := renderExample(fieldName, fieldDoc, flags)

if example != "" {
examples = append(examples, example)
Expand All @@ -199,15 +208,15 @@ func toYamlNode(in interface{}) (*yaml.Node, error) {

if !skip {
if inline {
child, err := toYamlNode(value)
child, err := toYamlNode(value, flags)
if err != nil {
return nil, err
}

if child.Kind == yaml.MappingNode || child.Kind == yaml.SequenceNode {
appendNodes(node, child.Content...)
}
} else if err := addToMap(node, fieldDoc, fieldName, value, style); err != nil {
} else if err := addToMap(node, fieldDoc, fieldName, value, style, flags); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -235,7 +244,7 @@ func toYamlNode(in interface{}) (*yaml.Node, error) {
element := v.MapIndex(k)
value := element.Interface()

if err := addToMap(node, nil, k.Interface(), value, 0); err != nil {
if err := addToMap(node, nil, k.Interface(), value, 0, flags); err != nil {
return nil, err
}
}
Expand All @@ -248,7 +257,7 @@ func toYamlNode(in interface{}) (*yaml.Node, error) {

var err error

nodes[i], err = toYamlNode(element.Interface())
nodes[i], err = toYamlNode(element.Interface(), flags)
if err != nil {
return nil, err
}
Expand All @@ -271,21 +280,23 @@ func appendNodes(dest *yaml.Node, nodes ...*yaml.Node) {
dest.Content = append(dest.Content, nodes...)
}

func addToMap(dest *yaml.Node, doc *Doc, fieldName, in interface{}, style yaml.Style) error {
key, err := toYamlNode(fieldName)
func addToMap(dest *yaml.Node, doc *Doc, fieldName, in interface{}, style yaml.Style, flags CommentsFlags) error {
key, err := toYamlNode(fieldName, flags)
if err != nil {
return err
}

value, err := toYamlNode(in)
value, err := toYamlNode(in, flags)
if err != nil {
return err
}

value.Style = style

addComments(key, doc, HeadComment, FootComment)
addComments(value, doc, LineComment)
if flags.enabled(CommentsDocs) {
addComments(key, doc, HeadComment, FootComment)
addComments(value, doc, LineComment)
}

// override head comment with line comment for non-scalar nodes
if value.Kind != yaml.ScalarNode {
Expand Down
Loading

0 comments on commit 4b42ced

Please sign in to comment.