talm

Форк
0
/
apply.go 
200 строк · 6.7 Кб
1
// This Source Code Form is subject to the terms of the Mozilla Public
2
// License, v. 2.0. If a copy of the MPL was not distributed with this
3
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
package commands
6

7
import (
8
	"bufio"
9
	"context"
10
	"errors"
11
	"fmt"
12
	"os"
13
	"time"
14

15
	"github.com/aenix-io/talm/pkg/engine"
16
	"github.com/spf13/cobra"
17
	"google.golang.org/protobuf/types/known/durationpb"
18

19
	"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers"
20
	machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
21
	"github.com/siderolabs/talos/pkg/machinery/client"
22
	"github.com/siderolabs/talos/pkg/machinery/constants"
23
)
24

25
var applyCmdFlags struct {
26
	helpers.Mode
27
	certFingerprints  []string
28
	insecure          bool
29
	configFiles       []string // -f/--files
30
	talosVersion      string
31
	withSecrets       string
32
	kubernetesVersion string
33
	dryRun            bool
34
	preserve          bool
35
	stage             bool
36
	force             bool
37
	configTryTimeout  time.Duration
38
	nodesFromArgs     bool
39
	endpointsFromArgs bool
40
}
41

42
var applyCmd = &cobra.Command{
43
	Use:   "apply",
44
	Short: "Apply config to a Talos node",
45
	Long:  ``,
46
	Args:  cobra.NoArgs,
47
	PreRunE: func(cmd *cobra.Command, args []string) error {
48
		if !cmd.Flags().Changed("talos-version") {
49
			applyCmdFlags.talosVersion = Config.TemplateOptions.TalosVersion
50
		}
51
		if !cmd.Flags().Changed("with-secrets") {
52
			applyCmdFlags.withSecrets = Config.TemplateOptions.WithSecrets
53
		}
54
		if !cmd.Flags().Changed("kubernetes-version") {
55
			applyCmdFlags.kubernetesVersion = Config.TemplateOptions.KubernetesVersion
56
		}
57
		if !cmd.Flags().Changed("preserve") {
58
			applyCmdFlags.preserve = Config.UpgradeOptions.Preserve
59
		}
60
		if !cmd.Flags().Changed("stage") {
61
			applyCmdFlags.stage = Config.UpgradeOptions.Stage
62
		}
63
		if !cmd.Flags().Changed("force") {
64
			applyCmdFlags.force = Config.UpgradeOptions.Force
65
		}
66
		applyCmdFlags.nodesFromArgs = len(GlobalArgs.Nodes) > 0
67
		applyCmdFlags.endpointsFromArgs = len(GlobalArgs.Endpoints) > 0
68
		// Set dummy endpoint to avoid errors on building clinet
69
		if len(GlobalArgs.Endpoints) == 0 {
70
			GlobalArgs.Endpoints = append(GlobalArgs.Endpoints, "127.0.0.1")
71
		}
72

73
		return nil
74
	},
75
	RunE: func(cmd *cobra.Command, args []string) error {
76
		return WithClientNoNodes(apply(args))
77
	},
78
}
79

80
func apply(args []string) func(ctx context.Context, c *client.Client) error {
81
	return func(ctx context.Context, c *client.Client) error {
82
		for _, configFile := range applyCmdFlags.configFiles {
83
			if err := processModelineAndUpdateGlobals(configFile, applyCmdFlags.nodesFromArgs, applyCmdFlags.endpointsFromArgs, true); err != nil {
84
				return err
85
			}
86

87
			opts := engine.Options{
88
				TalosVersion:      applyCmdFlags.talosVersion,
89
				WithSecrets:       applyCmdFlags.withSecrets,
90
				KubernetesVersion: applyCmdFlags.kubernetesVersion,
91
			}
92

93
			patches := []string{"@" + configFile}
94
			configBundle, err := engine.FullConfigProcess(ctx, opts, patches)
95
			if err != nil {
96
				return fmt.Errorf("full config processing error: %s", err)
97
			}
98

99
			machineType := configBundle.ControlPlaneCfg.Machine().Type()
100
			result, err := engine.SerializeConfiguration(configBundle, machineType)
101
			if err != nil {
102
				return fmt.Errorf("error serializing configuration: %s", err)
103
			}
104

105
			withClient := func(f func(ctx context.Context, c *client.Client) error) error {
106
				if applyCmdFlags.insecure {
107
					return WithClientMaintenance(applyCmdFlags.certFingerprints, f)
108
				}
109

110
				return WithClientNoNodes(func(ctx context.Context, cli *client.Client) error {
111
					if len(GlobalArgs.Nodes) < 1 {
112
						configContext := cli.GetConfigContext()
113
						if configContext == nil {
114
							return errors.New("failed to resolve config context")
115
						}
116

117
						GlobalArgs.Nodes = configContext.Nodes
118
					}
119

120
					ctx = client.WithNodes(ctx, GlobalArgs.Nodes...)
121

122
					return f(ctx, cli)
123
				})
124
			}
125

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

129
				resp, err := c.ApplyConfiguration(ctx, &machineapi.ApplyConfigurationRequest{
130
					Data:           result,
131
					Mode:           applyCmdFlags.Mode.Mode,
132
					DryRun:         applyCmdFlags.dryRun,
133
					TryModeTimeout: durationpb.New(applyCmdFlags.configTryTimeout),
134
				})
135
				if err != nil {
136
					return fmt.Errorf("error applying new configuration: %s", err)
137
				}
138

139
				helpers.PrintApplyResults(resp)
140

141
				return nil
142
			})
143
			if err != nil {
144
				return err
145
			}
146

147
			// Reset args
148
			if !applyCmdFlags.nodesFromArgs {
149
				GlobalArgs.Nodes = []string{}
150
			}
151
			if !applyCmdFlags.endpointsFromArgs {
152
				GlobalArgs.Endpoints = []string{}
153
			}
154
		}
155
		return nil
156
	}
157
}
158

159
// readFirstLine reads and returns the first line of the file specified by the filename.
160
// It returns an error if opening or reading the file fails.
161
func readFirstLine(filename string) (string, error) {
162
	// Open the file
163
	file, err := os.Open(filename)
164
	if err != nil {
165
		return "", fmt.Errorf("error opening file: %v", err)
166
	}
167
	defer file.Close() // Ensure the file is closed after reading
168

169
	// Create a scanner to read the file
170
	scanner := bufio.NewScanner(file)
171

172
	// Read the first line
173
	if scanner.Scan() {
174
		return scanner.Text(), nil
175
	}
176

177
	// Check for errors during scanning
178
	if err := scanner.Err(); err != nil {
179
		return "", fmt.Errorf("error reading file: %v", err)
180
	}
181

182
	// If no lines in the file, return an empty string
183
	return "", nil
184
}
185

186
func init() {
187
	applyCmd.Flags().BoolVarP(&applyCmdFlags.insecure, "insecure", "i", false, "apply using the insecure (encrypted with no auth) maintenance service")
188
	applyCmd.Flags().StringSliceVarP(&applyCmdFlags.configFiles, "file", "f", nil, "specify config files or patches in a YAML file (can specify multiple)")
189
	applyCmd.Flags().StringVar(&applyCmdFlags.talosVersion, "talos-version", "", "the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)")
190
	applyCmd.Flags().StringVar(&applyCmdFlags.withSecrets, "with-secrets", "", "use a secrets file generated using 'gen secrets'")
191

192
	applyCmd.Flags().StringVar(&applyCmdFlags.kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run")
193
	applyCmd.Flags().BoolVar(&applyCmdFlags.dryRun, "dry-run", false, "check how the config change will be applied in dry-run mode")
194
	applyCmd.Flags().DurationVar(&applyCmdFlags.configTryTimeout, "timeout", constants.ConfigTryTimeout, "the config will be rolled back after specified timeout (if try mode is selected)")
195
	applyCmd.Flags().StringSliceVar(&applyCmdFlags.certFingerprints, "cert-fingerprint", nil, "list of server certificate fingeprints to accept (defaults to no check)")
196
	applyCmd.Flags().BoolVar(&applyCmdFlags.force, "force", false, "will overwrite existing files")
197
	helpers.AddModeFlags(&applyCmdFlags.Mode, applyCmd)
198

199
	addCommand(applyCmd)
200
}
201

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.