~rogpeppe/juju-core/438-local-instance-Addresses

« back to all changes in this revision

Viewing changes to environs/sshstorage/storage.go

[r=axwalk],[bug=1234125] provider/null: fix intermittent test failure

Also, in environs/sshstorage (related to test failure):
capture command output in case of outer ssh/bash command
failure.

Fixes #1234125

https://codereview.appspot.com/14315044/

Show diffs side-by-side

added added

removed removed

Lines of Context:
102
102
                stdin.Close()
103
103
                return nil, err
104
104
        }
 
105
        // Combine stdout and stderr, so we can easily
 
106
        // get at catastrophic failure messages.
 
107
        cmd.Stderr = cmd.Stdout
105
108
        stor := &SSHStorage{
106
109
                host:       host,
107
110
                remotepath: storagedir,
136
139
        return s.run(flockmode, command, nil, 0)
137
140
}
138
141
 
 
142
// terminate closes the stdin, and appends any output to the input error.
 
143
func (s *SSHStorage) terminate(err error) error {
 
144
        s.stdin.Close()
 
145
        var output string
 
146
        for s.scanner.Scan() {
 
147
                output += s.scanner.Text()
 
148
        }
 
149
        if len(output) > 0 {
 
150
                err = fmt.Errorf("%v (output: %q)", err, output)
 
151
        }
 
152
        return err
 
153
}
 
154
 
139
155
func (s *SSHStorage) run(flockmode flockmode, command string, input io.Reader, inputlen int64) (string, error) {
140
156
        const rcPrefix = "JUJU-RC: "
141
157
        command = fmt.Sprintf(
155
171
        if input != nil {
156
172
                wrapper, err := newLineWrapWriter(stdin, base64LineLength)
157
173
                if err != nil {
158
 
                        return "", fmt.Errorf("failed to create split writer: %v", err)
159
 
                }
160
 
                encoder := base64.NewEncoder(base64.StdEncoding, wrapper)
161
 
                if _, err := io.CopyN(encoder, input, inputlen); err != nil {
162
 
                        return "", fmt.Errorf("failed to write input: %v", err)
163
 
                }
164
 
                if err := encoder.Close(); err != nil {
165
 
                        return "", fmt.Errorf("failed to flush encoder: %v", err)
166
 
                }
167
 
                if _, err := stdin.WriteString("\n@EOF\n"); err != nil {
168
 
                        return "", fmt.Errorf("failed to terminate input: %v", err)
 
174
                        err = fmt.Errorf("failed to create split writer: %v", err)
 
175
                } else {
 
176
                        encoder := base64.NewEncoder(base64.StdEncoding, wrapper)
 
177
                        if _, err = io.CopyN(encoder, input, inputlen); err != nil {
 
178
                                err = fmt.Errorf("failed to write input: %v", err)
 
179
                        } else if err = encoder.Close(); err != nil {
 
180
                                err = fmt.Errorf("failed to flush encoder: %v", err)
 
181
                        } else if _, err = stdin.WriteString("\n@EOF\n"); err != nil {
 
182
                                err = fmt.Errorf("failed to terminate input: %v", err)
 
183
                        }
 
184
                }
 
185
                if err != nil {
 
186
                        return "", s.terminate(err)
169
187
                }
170
188
        }
171
189
        if err := stdin.Flush(); err != nil {
172
 
                return "", fmt.Errorf("failed to flush input: %v", err)
 
190
                err = fmt.Errorf("failed to flush input: %v", err)
 
191
                return "", s.terminate(err)
173
192
        }
174
193
        var output []string
175
194
        for s.scanner.Scan() {
189
208
                        output = append(output, line)
190
209
                }
191
210
        }
192
 
        return "", s.scanner.Err()
 
211
 
 
212
        err := fmt.Errorf("failed to locate %q", rcPrefix)
 
213
        if len(output) > 0 {
 
214
                err = fmt.Errorf("%v (output: %q)", err, strings.Join(output, "\n"))
 
215
        }
 
216
        if scannerErr := s.scanner.Err(); scannerErr != nil {
 
217
                err = fmt.Errorf("%v (scanner error: %v)", err, scannerErr)
 
218
        }
 
219
        return "", err
193
220
}
194
221
 
195
222
// path returns a remote absolute path for a storage object name.