Skip to content

Commit

Permalink
Introduce template --in-place updates
Browse files Browse the repository at this point in the history
  • Loading branch information
kvaps committed May 6, 2024
1 parent 0968634 commit 40c022d
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 33 deletions.
11 changes: 10 additions & 1 deletion pkg/commands/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ func apply(args []string) func(ctx context.Context, c *client.Client) error {
}

err = withClient(func(ctx context.Context, c *client.Client) error {
fmt.Printf("Nodes: %s\n", GlobalArgs.Nodes)
fmt.Printf("- talm: file=%s, nodes=%s, endpoints=%s\n", configFile, GlobalArgs.Nodes, GlobalArgs.Endpoints)

resp, err := c.ApplyConfiguration(ctx, &machineapi.ApplyConfigurationRequest{
Data: result,
Mode: applyCmdFlags.Mode.Mode,
Expand All @@ -118,6 +119,14 @@ func apply(args []string) func(ctx context.Context, c *client.Client) error {
if err != nil {
return err
}

// Reset args
if !nodesFromArgs {
GlobalArgs.Nodes = []string{}
}
if !endpointsFromArgs {
GlobalArgs.Endpoints = []string{}
}
}
return nil
}
Expand Down
1 change: 0 additions & 1 deletion pkg/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ func addCommand(cmd *cobra.Command) {
}

func processModelineAndUpdateGlobals(configFile string, nodesFromArgs bool, endpointsFromArgs bool) error {
// Use the new function to handle modeline
modelineConfig, err := modeline.ReadAndParseModeline(configFile)
if err != nil {
fmt.Printf("Warning: modeline parsing failed: %v\n", err)
Expand Down
156 changes: 125 additions & 31 deletions pkg/commands/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"os"

"github.com/aenix-io/talm/pkg/engine"
"github.com/aenix-io/talm/pkg/modeline"
Expand All @@ -20,6 +21,7 @@ import (

var templateCmdFlags struct {
insecure bool
configFiles []string // -f/--files
valueFiles []string // --values
templateFiles []string // -t/--template
stringValues []string // --set-string
Expand All @@ -32,6 +34,7 @@ var templateCmdFlags struct {
full bool
offline bool
kubernetesVersion string
inplace bool
}

var templateCmd = &cobra.Command{
Expand All @@ -40,59 +43,150 @@ var templateCmd = &cobra.Command{
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
templateFunc := template
if templateCmdFlags.inplace {
templateFunc = templateUpdate
if len(templateCmdFlags.configFiles) == 0 {
return fmt.Errorf("cannot use --in-place without --file")
}
} else {
if len(templateCmdFlags.configFiles) != 0 {
return fmt.Errorf("cannot use --file without --in-place")
}
if len(templateCmdFlags.templateFiles) < 1 {
return errors.New("templates are not set for the command: please use `--template` flag to set the templates to render manifest from")
}
}

if templateCmdFlags.offline {
return template(args)(context.Background(), nil)
return templateFunc(args)(context.Background(), nil)
}
if templateCmdFlags.insecure {
return WithClientMaintenance(nil, template(args))
return WithClientMaintenance(nil, templateFunc(args))
}

return WithClient(template(args))
return WithClient(templateFunc(args))
},
}

func template(args []string) func(ctx context.Context, c *client.Client) error {
return func(ctx context.Context, c *client.Client) error {
opts := engine.Options{
Insecure: templateCmdFlags.insecure,
ValueFiles: templateCmdFlags.valueFiles,
StringValues: templateCmdFlags.stringValues,
Values: templateCmdFlags.values,
FileValues: templateCmdFlags.fileValues,
JsonValues: templateCmdFlags.jsonValues,
LiteralValues: templateCmdFlags.literalValues,
TalosVersion: templateCmdFlags.talosVersion,
WithSecrets: templateCmdFlags.withSecrets,
Full: templateCmdFlags.full,
Root: Config.RootDir,
Offline: templateCmdFlags.offline,
KubernetesVersion: templateCmdFlags.kubernetesVersion,
TemplateFiles: templateCmdFlags.templateFiles,
output, err := generateOutput(ctx, c, args)
if err != nil {
return err
}

if len(templateCmdFlags.templateFiles) < 1 {
return errors.New("templates are not set for the command: please use `--template` flag to set the templates to render manifest from")
}
fmt.Println(output)
return nil
}
}

result, err := engine.Render(ctx, c, opts)
if err != nil {
return fmt.Errorf("failed to render templates: %w", err)
func templateUpdate(args []string) func(ctx context.Context, c *client.Client) error {
return func(ctx context.Context, c *client.Client) error {
templatesFromArgs := len(templateCmdFlags.templateFiles) > 0
nodesFromArgs := len(GlobalArgs.Nodes) > 0
endpointsFromArgs := len(GlobalArgs.Endpoints) > 0
for _, configFile := range templateCmdFlags.configFiles {
modelineConfig, err := modeline.ReadAndParseModeline(configFile)
if err != nil {
return fmt.Errorf("modeline parsing failed: %v\n", err)
}
if !templatesFromArgs {
if len(modelineConfig.Templates) == 0 {
return fmt.Errorf("modeline does not contain templates information")
} else {
templateCmdFlags.templateFiles = modelineConfig.Templates
}
}
if !nodesFromArgs {
GlobalArgs.Nodes = modelineConfig.Nodes
}
if !endpointsFromArgs {
GlobalArgs.Endpoints = modelineConfig.Endpoints
}

if len(GlobalArgs.Nodes) < 1 {
return errors.New("nodes are not set for the command: please use `--nodes` flag or configuration file to set the nodes to run the command against")
}

fmt.Printf("- talm: file=%s, nodes=%s, endpoints=%s, templates=%s\n", configFile, GlobalArgs.Nodes, GlobalArgs.Endpoints, templateCmdFlags.templateFiles)

template := func(args []string) func(ctx context.Context, c *client.Client) error {
return func(ctx context.Context, c *client.Client) error {
output, err := generateOutput(ctx, c, args)
if err != nil {
return err
}

err = os.WriteFile(configFile, []byte(output), 0o644)
fmt.Fprintf(os.Stderr, "Updated.\n")

return nil
}
}

if templateCmdFlags.offline {
err = template(args)(context.Background(), nil)
} else if templateCmdFlags.insecure {
err = WithClientMaintenance(nil, template(args))
} else {
err = WithClient(template(args))
}
if err != nil {
return err
}

// Reset args
if !templatesFromArgs {
templateCmdFlags.templateFiles = []string{}
}
if !nodesFromArgs {
GlobalArgs.Nodes = []string{}
}
if !endpointsFromArgs {
GlobalArgs.Endpoints = []string{}
}
}
return nil
}
}

// Use the GenerateModeline from the modeline package
modeline, err := modeline.GenerateModeline(GlobalArgs.Nodes, GlobalArgs.Endpoints, templateCmdFlags.templateFiles)
if err != nil {
return fmt.Errorf("failed to generate modeline: %w", err)
}
func generateOutput(ctx context.Context, c *client.Client, args []string) (string, error) {
opts := engine.Options{
Insecure: templateCmdFlags.insecure,
ValueFiles: templateCmdFlags.valueFiles,
StringValues: templateCmdFlags.stringValues,
Values: templateCmdFlags.values,
FileValues: templateCmdFlags.fileValues,
JsonValues: templateCmdFlags.jsonValues,
LiteralValues: templateCmdFlags.literalValues,
TalosVersion: templateCmdFlags.talosVersion,
WithSecrets: templateCmdFlags.withSecrets,
Full: templateCmdFlags.full,
Root: Config.RootDir,
Offline: templateCmdFlags.offline,
KubernetesVersion: templateCmdFlags.kubernetesVersion,
TemplateFiles: templateCmdFlags.templateFiles,
}

fmt.Printf("%s\n%s", modeline, string(result))
result, err := engine.Render(ctx, c, opts)
if err != nil {
return "", fmt.Errorf("failed to render templates: %w", err)
}

return nil
modeline, err := modeline.GenerateModeline(GlobalArgs.Nodes, GlobalArgs.Endpoints, templateCmdFlags.templateFiles)
if err != nil {
return "", fmt.Errorf("failed to generate modeline: %w", err)
}

output := fmt.Sprintf("%s\n%s", modeline, string(result))
return output, nil
}

func init() {
templateCmd.Flags().BoolVarP(&templateCmdFlags.insecure, "insecure", "i", false, "template using the insecure (encrypted with no auth) maintenance service")
templateCmd.Flags().StringSliceVarP(&templateCmdFlags.configFiles, "file", "f", nil, "specify config files for in-place update (can specify multiple)")
templateCmd.Flags().BoolVarP(&templateCmdFlags.inplace, "in-place", "I", false, "update generated files in place")
templateCmd.Flags().StringSliceVarP(&templateCmdFlags.valueFiles, "values", "", []string{}, "specify values in a YAML file (can specify multiple)")
templateCmd.Flags().StringSliceVarP(&templateCmdFlags.templateFiles, "template", "t", []string{}, "specify templates to render manifest from (can specify multiple)")
templateCmd.Flags().StringArrayVar(&templateCmdFlags.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
Expand Down
2 changes: 2 additions & 0 deletions pkg/commands/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ func upgrade(args []string) func(ctx context.Context, c *client.Client) error {

common.SuppressErrors = true

fmt.Printf("- talm: file=%s, nodes=%s, endpoints=%s, image=%s\n", configFile, GlobalArgs.Nodes, GlobalArgs.Endpoints, image)

err = action.NewTracker(
&GlobalArgs,
action.MachineReadyEventFn,
Expand Down

0 comments on commit 40c022d

Please sign in to comment.