Skip to content

Commit 523f1ce

Browse files
authored
Merge pull request #298 from hashicorp/winrm_error_handling
fix(winrm): catch cmd err from winrm
2 parents d2010b9 + f6edf98 commit 523f1ce

File tree

2 files changed

+42
-69
lines changed

2 files changed

+42
-69
lines changed

packer/communicator.go

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,6 @@ func (r *RemoteCmd) RunWithUi(ctx context.Context, c Communicator, ui Ui) error
123123
r.Stderr = io.MultiWriter(r.Stderr, stderr_w)
124124
}
125125

126-
// Start the command
127-
if err := c.Start(ctx, r); err != nil {
128-
return err
129-
}
130-
131126
// Create the channels we'll use for data
132127
stdoutCh := iochan.DelimReader(stdout_r, '\n')
133128
stderrCh := iochan.DelimReader(stderr_r, '\n')
@@ -140,32 +135,49 @@ func (r *RemoteCmd) RunWithUi(ctx context.Context, c Communicator, ui Ui) error
140135
}()
141136

142137
// Loop and get all our output
143-
OutputLoop:
144-
for {
145-
select {
146-
case output := <-stderrCh:
147-
if output != "" {
148-
ui.Error(r.cleanOutputLine(output))
149-
}
150-
case output := <-stdoutCh:
151-
if output != "" {
152-
ui.Message(r.cleanOutputLine(output))
138+
var wg sync.WaitGroup
139+
var ctxErr error
140+
wg.Add(1)
141+
142+
go func() {
143+
defer wg.Done()
144+
exiting := false
145+
146+
for !exiting {
147+
select {
148+
case output, ok := <-stderrCh:
149+
if ok && output != "" {
150+
ui.Error(r.cleanOutputLine(output))
151+
}
152+
case output, ok := <-stdoutCh:
153+
if ok && output != "" {
154+
ui.Say(r.cleanOutputLine(output))
155+
}
156+
case <-r.exitCh:
157+
exiting = true
158+
case <-ctx.Done():
159+
ctxErr = ctx.Err()
160+
return
153161
}
154-
case <-r.exitCh:
155-
break OutputLoop
156-
case <-ctx.Done():
157-
return ctx.Err()
158162
}
159-
}
160163

161-
// Make sure we finish off stdout/stderr because we may have gotten
162-
// a message from the exit channel before finishing these first.
163-
for output := range stdoutCh {
164-
ui.Message(r.cleanOutputLine(output))
164+
// Drain remaining messages from stdout and stderr if channels are still open.
165+
for output := range stdoutCh {
166+
ui.Say(r.cleanOutputLine(output))
167+
}
168+
for output := range stderrCh {
169+
ui.Error(r.cleanOutputLine(output))
170+
}
171+
}()
172+
173+
// Start the command
174+
if err := c.Start(ctx, r); err != nil {
175+
return err
165176
}
166177

167-
for output := range stderrCh {
168-
ui.Error(r.cleanOutputLine(output))
178+
wg.Wait()
179+
if ctxErr != nil {
180+
return ctxErr
169181
}
170182

171183
return nil

sdk-internals/communicator/winrm/communicator.go

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"os"
1717
"path/filepath"
1818
"strings"
19-
"sync"
2019

2120
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
2221
"github.com/masterzen/winrm"
@@ -82,50 +81,12 @@ func New(config *Config) (*Communicator, error) {
8281

8382
// Start implementation of communicator.Communicator interface
8483
func (c *Communicator) Start(ctx context.Context, rc *packersdk.RemoteCmd) error {
85-
shell, err := c.client.CreateShell()
86-
if err != nil {
87-
return err
88-
}
89-
9084
log.Printf("[INFO] starting remote command: %s", rc.Command)
91-
cmd, err := shell.Execute(rc.Command)
92-
if err != nil {
93-
return err
94-
}
95-
96-
go runCommand(shell, cmd, rc)
97-
return nil
98-
}
85+
exitCode, err := c.client.Run(rc.Command, rc.Stdout, rc.Stderr)
9986

100-
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *packersdk.RemoteCmd) {
101-
defer shell.Close()
102-
var wg sync.WaitGroup
103-
104-
copyFunc := func(w io.Writer, r io.Reader) {
105-
defer wg.Done()
106-
io.Copy(w, r)
107-
}
108-
109-
if rc.Stdout != nil && cmd.Stdout != nil {
110-
wg.Add(1)
111-
go copyFunc(rc.Stdout, cmd.Stdout)
112-
} else {
113-
log.Printf("[WARN] Failed to read stdout for command '%s'", rc.Command)
114-
}
115-
116-
if rc.Stderr != nil && cmd.Stderr != nil {
117-
wg.Add(1)
118-
go copyFunc(rc.Stderr, cmd.Stderr)
119-
} else {
120-
log.Printf("[WARN] Failed to read stderr for command '%s'", rc.Command)
121-
}
122-
123-
cmd.Wait()
124-
wg.Wait()
125-
126-
code := cmd.ExitCode()
127-
log.Printf("[INFO] command '%s' exited with code: %d", rc.Command, code)
128-
rc.SetExited(code)
87+
rc.SetExited(exitCode)
88+
log.Printf("[INFO] command '%s' exited with code: %d", rc.Command, exitCode)
89+
return err
12990
}
13091

13192
// Upload implementation of communicator.Communicator interface

0 commit comments

Comments
 (0)