Skip to content

Commit

Permalink
fix: patch multi nodes support
Browse files Browse the repository at this point in the history
It was messing up the config due to wrong context being used in patchFn.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
(cherry picked from commit ed12379)
  • Loading branch information
Unix4ever authored and smira committed Sep 17, 2021
1 parent ccb24bc commit 7b4a6b3
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 158 deletions.
226 changes: 114 additions & 112 deletions cmd/talosctl/cmd/talos/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,119 @@ var editCmdFlags struct {
onReboot bool
}

//nolint:gocyclo
func editFn(c *client.Client) func(context.Context, client.ResourceResponse) error {
var lastError string

edit := editor.NewDefaultEditor([]string{
"TALOS_EDITOR",
"EDITOR",
})

return func(ctx context.Context, msg client.ResourceResponse) error {
if msg.Definition != nil {
if msg.Definition.Metadata().ID() != strings.ToLower(config.MachineConfigType) {
return fmt.Errorf("only the machineconfig resource can be edited")
}
}

if msg.Resource == nil {
return nil
}

for {
var (
buf bytes.Buffer
w io.Writer = &buf
id string
)

metadata := msg.Resource.Metadata()

if metadata != nil {
id = metadata.ID()
}

if runtime.GOOS == "windows" {
w = crlf.NewCRLFWriter(w)
}

_, err := w.Write([]byte(
fmt.Sprintf(
"# Editing %s/%s at node %s\n", msg.Resource.Metadata().Type(), id, msg.Metadata.GetHostname(),
),
))
if err != nil {
return err
}

if lastError != "" {
lines := strings.Split(lastError, "\n")

_, err = w.Write([]byte(
fmt.Sprintf("#\n# %s\n", strings.Join(lines, "\n# ")),
))
if err != nil {
return err
}
}

body, err := yaml.Marshal(msg.Resource.Spec())
if err != nil {
return err
}

_, err = w.Write(body)
if err != nil {
return err
}

edited, _, err := edit.LaunchTempFile(fmt.Sprintf("%s-%s-edit-", msg.Resource.Metadata().Type(), id), ".yaml", &buf)
if err != nil {
return err
}

editedWithoutComments := bytes.TrimSpace(cmdutil.StripComments(edited))

if len(bytes.TrimSpace(editedWithoutComments)) == 0 {
fmt.Println("Apply was skipped: empty file.")

break
}

if bytes.Equal(
editedWithoutComments,
bytes.TrimSpace(cmdutil.StripComments(body)),
) {
fmt.Println("Apply was skipped: no changes detected.")

break
}

resp, err := c.ApplyConfiguration(ctx, &machine.ApplyConfigurationRequest{
Data: edited,
Immediate: editCmdFlags.immediate,
OnReboot: editCmdFlags.onReboot,
})
if err != nil {
lastError = err.Error()

continue
}

for _, m := range resp.GetMessages() {
for _, w := range m.GetWarnings() {
cli.Warning("%s", w)
}
}

break
}

return nil
}
}

// editCmd represents the edit command.
var editCmd = &cobra.Command{
Use: "edit <type> [<id>]",
Expand All @@ -44,120 +157,9 @@ or EDITOR environment variables, or fall back to 'vi' for Linux
or 'notepad' for Windows.`,
RunE: func(cmd *cobra.Command, args []string) error {
return WithClient(func(ctx context.Context, c *client.Client) error {
edit := editor.NewDefaultEditor([]string{
"TALOS_EDITOR",
"EDITOR",
})

resourceType := args[0]

var lastError string

editFn := func(parentCtx context.Context, msg client.ResourceResponse) error {
if msg.Definition != nil {
if msg.Definition.Metadata().ID() != strings.ToLower(config.MachineConfigType) {
return fmt.Errorf("only the machineconfig resource can be edited")
}
}

if msg.Resource == nil {
return nil
}

for {
var (
buf bytes.Buffer
w io.Writer = &buf
id string
)

metadata := msg.Resource.Metadata()

if metadata != nil {
id = metadata.ID()
}

if runtime.GOOS == "windows" {
w = crlf.NewCRLFWriter(w)
}

_, err := w.Write([]byte(
fmt.Sprintf(
"# Editing %s/%s at node %s\n", msg.Resource.Metadata().Type(), id, msg.Metadata.GetHostname(),
),
))
if err != nil {
return err
}

if lastError != "" {
lines := strings.Split(lastError, "\n")

_, err = w.Write([]byte(
fmt.Sprintf("#\n# %s\n", strings.Join(lines, "\n# ")),
))
if err != nil {
return err
}
}

body, err := yaml.Marshal(msg.Resource.Spec())
if err != nil {
return err
}

_, err = w.Write(body)
if err != nil {
return err
}

edited, _, err := edit.LaunchTempFile(fmt.Sprintf("%s-%s-edit-", resourceType, id), ".yaml", &buf)
if err != nil {
return err
}

editedWithoutComments := bytes.TrimSpace(cmdutil.StripComments(edited))

if len(bytes.TrimSpace(editedWithoutComments)) == 0 {
fmt.Println("Apply was skipped: empty file.")

break
}

if bytes.Equal(
editedWithoutComments,
bytes.TrimSpace(cmdutil.StripComments(body)),
) {
fmt.Println("Apply was skipped: no changes detected.")

break
}

resp, err := c.ApplyConfiguration(parentCtx, &machine.ApplyConfigurationRequest{
Data: edited,
Immediate: editCmdFlags.immediate,
OnReboot: editCmdFlags.onReboot,
})
if err != nil {
lastError = err.Error()

continue
}
for _, m := range resp.GetMessages() {
for _, w := range m.GetWarnings() {
cli.Warning("%s", w)
}
}

break
}

return nil
}

for _, node := range Nodes {
nodeCtx := client.WithNodes(ctx, node)
if err := helpers.ForEachResource(nodeCtx, c, editFn, editCmdFlags.namespace, args...); err != nil {
if err := helpers.ForEachResource(nodeCtx, c, editFn(c), editCmdFlags.namespace, args...); err != nil {
return err
}
}
Expand Down
98 changes: 52 additions & 46 deletions cmd/talosctl/cmd/talos/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,57 @@ var patchCmdFlags struct {
onReboot bool
}

func patchFn(c *client.Client, patch jsonpatch.Patch) func(context.Context, client.ResourceResponse) error {
return func(ctx context.Context, msg client.ResourceResponse) error {
if msg.Resource == nil {
if msg.Definition.Metadata().ID() != strings.ToLower(config.MachineConfigType) {
return fmt.Errorf("only the machineconfig resource can be edited")
}

return nil
}

body, err := yaml.Marshal(msg.Resource.Spec())
if err != nil {
return err
}

patched, err := configpatcher.JSON6902(body, patch)
if err != nil {
return err
}

resp, err := c.ApplyConfiguration(ctx, &machine.ApplyConfigurationRequest{
Data: patched,
Immediate: patchCmdFlags.immediate,
OnReboot: patchCmdFlags.onReboot,
})

if bytes.Equal(
bytes.TrimSpace(cmdutil.StripComments(patched)),
bytes.TrimSpace(cmdutil.StripComments(body)),
) {
fmt.Println("Apply was skipped: no changes detected.")

return nil
}

fmt.Printf("patched %s/%s at the node %s\n",
msg.Resource.Metadata().Type(),
msg.Resource.Metadata().ID(),
msg.Metadata.GetHostname(),
)

for _, m := range resp.GetMessages() {
for _, w := range m.GetWarnings() {
cli.Warning("%s", w)
}
}

return err
}
}

// patchCmd represents the edit command.
var patchCmd = &cobra.Command{
Use: "patch <type> [<id>]",
Expand Down Expand Up @@ -67,54 +118,9 @@ var patchCmd = &cobra.Command{
return err
}

patchFn := func(parentCtx context.Context, msg client.ResourceResponse) error {
if msg.Resource == nil {
if msg.Definition.Metadata().ID() != strings.ToLower(config.MachineConfigType) {
return fmt.Errorf("only the machineconfig resource can be edited")
}

return nil
}

body, err := yaml.Marshal(msg.Resource.Spec())
if err != nil {
return err
}

patched, err := configpatcher.JSON6902(body, patch)
if err != nil {
return err
}

resp, err := c.ApplyConfiguration(ctx, &machine.ApplyConfigurationRequest{
Data: patched,
Immediate: patchCmdFlags.immediate,
OnReboot: patchCmdFlags.onReboot,
})

if bytes.Equal(
bytes.TrimSpace(cmdutil.StripComments(patched)),
bytes.TrimSpace(cmdutil.StripComments(body)),
) {
fmt.Println("Apply was skipped: no changes detected.")

return nil
}

fmt.Printf("patched %s at the node %s\n", args[0], msg.Metadata.GetHostname())

for _, m := range resp.GetMessages() {
for _, w := range m.GetWarnings() {
cli.Warning("%s", w)
}
}

return err
}

for _, node := range Nodes {
nodeCtx := client.WithNodes(ctx, node)
if err := helpers.ForEachResource(nodeCtx, c, patchFn, patchCmdFlags.namespace, args...); err != nil {
if err := helpers.ForEachResource(nodeCtx, c, patchFn(c, patch), patchCmdFlags.namespace, args...); err != nil {
return err
}
}
Expand Down

0 comments on commit 7b4a6b3

Please sign in to comment.