Skip to content

Commit 806b10f

Browse files
authored
Merge pull request kubernetes-sigs#9737 from sbueringer/pr-improve-apply-output
🌱 Improve output of exec.KubectlApply
2 parents b587ff9 + adce020 commit 806b10f

File tree

4 files changed

+43
-28
lines changed

4 files changed

+43
-28
lines changed

cmd/clusterctl/cmd/topology_plan.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cmd
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"io"
2324
"os"
@@ -28,7 +29,7 @@ import (
2829
"strings"
2930

3031
"github.com/olekukonko/tablewriter"
31-
"github.com/pkg/errors"
32+
pkgerrors "github.com/pkg/errors"
3233
"github.com/spf13/cobra"
3334
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3435
"k8s.io/utils/exec"
@@ -121,11 +122,11 @@ func runTopologyPlan() error {
121122
for _, f := range tp.files {
122123
raw, err := os.ReadFile(f) //nolint:gosec
123124
if err != nil {
124-
return errors.Wrapf(err, "failed to read input file %q", f)
125+
return pkgerrors.Wrapf(err, "failed to read input file %q", f)
125126
}
126127
objects, err := utilyaml.ToUnstructured(raw)
127128
if err != nil {
128-
return errors.Wrapf(err, "failed to convert file %q to list of objects", f)
129+
return pkgerrors.Wrapf(err, "failed to convert file %q to list of objects", f)
129130
}
130131
objs = append(objs, objects...)
131132
}
@@ -154,7 +155,7 @@ func printTopologyPlanOutput(out *cluster.TopologyPlanOutput, outdir string) err
154155
} else {
155156
printChangeSummary(out)
156157
if err := writeOutputFiles(out, outdir); err != nil {
157-
return errors.Wrap(err, "failed to write output files of target cluster changes")
158+
return pkgerrors.Wrap(err, "failed to write output files of target cluster changes")
158159
}
159160
}
160161
fmt.Printf("\n")
@@ -233,17 +234,17 @@ func writeOutputFiles(out *cluster.TopologyPlanOutput, outDir string) error {
233234
// Write created files
234235
createdDir := path.Join(outDir, "created")
235236
if err := os.MkdirAll(createdDir, 0750); err != nil {
236-
return errors.Wrapf(err, "failed to create %q directory", createdDir)
237+
return pkgerrors.Wrapf(err, "failed to create %q directory", createdDir)
237238
}
238239
for _, c := range out.Created {
239240
yaml, err := utilyaml.FromUnstructured([]unstructured.Unstructured{*c})
240241
if err != nil {
241-
return errors.Wrap(err, "failed to convert object to yaml")
242+
return pkgerrors.Wrap(err, "failed to convert object to yaml")
242243
}
243244
fileName := fmt.Sprintf("%s_%s_%s.yaml", c.GetKind(), c.GetNamespace(), c.GetName())
244245
filePath := path.Join(createdDir, fileName)
245246
if err := os.WriteFile(filePath, yaml, 0600); err != nil {
246-
return errors.Wrapf(err, "failed to write yaml to file %q", filePath)
247+
return pkgerrors.Wrapf(err, "failed to write yaml to file %q", filePath)
247248
}
248249
}
249250
if len(out.Created) != 0 {
@@ -253,44 +254,44 @@ func writeOutputFiles(out *cluster.TopologyPlanOutput, outDir string) error {
253254
// Write modified files
254255
modifiedDir := path.Join(outDir, "modified")
255256
if err := os.MkdirAll(modifiedDir, 0750); err != nil {
256-
return errors.Wrapf(err, "failed to create %q directory", modifiedDir)
257+
return pkgerrors.Wrapf(err, "failed to create %q directory", modifiedDir)
257258
}
258259
for _, m := range out.Modified {
259260
// Write the modified object to file.
260261
fileNameModified := fmt.Sprintf("%s_%s_%s.modified.yaml", m.After.GetKind(), m.After.GetNamespace(), m.After.GetName())
261262
filePathModified := path.Join(modifiedDir, fileNameModified)
262263
if err := writeObjectToFile(filePathModified, m.After); err != nil {
263-
return errors.Wrap(err, "failed to write modified object to file")
264+
return pkgerrors.Wrap(err, "failed to write modified object to file")
264265
}
265266

266267
// Write the original object to file.
267268
fileNameOriginal := fmt.Sprintf("%s_%s_%s.original.yaml", m.Before.GetKind(), m.Before.GetNamespace(), m.Before.GetName())
268269
filePathOriginal := path.Join(modifiedDir, fileNameOriginal)
269270
if err := writeObjectToFile(filePathOriginal, m.Before); err != nil {
270-
return errors.Wrap(err, "failed to write original object to file")
271+
return pkgerrors.Wrap(err, "failed to write original object to file")
271272
}
272273

273274
// Calculate the jsonpatch and write to a file.
274275
patch := crclient.MergeFrom(m.Before)
275276
jsonPatch, err := patch.Data(m.After)
276277
if err != nil {
277-
return errors.Wrapf(err, "failed to calculate jsonpatch of modified object %s/%s", m.After.GetNamespace(), m.After.GetName())
278+
return pkgerrors.Wrapf(err, "failed to calculate jsonpatch of modified object %s/%s", m.After.GetNamespace(), m.After.GetName())
278279
}
279280
patchFileName := fmt.Sprintf("%s_%s_%s.jsonpatch", m.After.GetKind(), m.After.GetNamespace(), m.After.GetName())
280281
patchFilePath := path.Join(modifiedDir, patchFileName)
281282
if err := os.WriteFile(patchFilePath, jsonPatch, 0600); err != nil {
282-
return errors.Wrapf(err, "failed to write jsonpatch to file %q", patchFilePath)
283+
return pkgerrors.Wrapf(err, "failed to write jsonpatch to file %q", patchFilePath)
283284
}
284285

285286
// Calculate the diff and write to a file.
286287
diffFileName := fmt.Sprintf("%s_%s_%s.diff", m.After.GetKind(), m.After.GetNamespace(), m.After.GetName())
287288
diffFilePath := path.Join(modifiedDir, diffFileName)
288289
diffFile, err := os.OpenFile(filepath.Clean(diffFilePath), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
289290
if err != nil {
290-
return errors.Wrapf(err, "unable to open file %q", diffFilePath)
291+
return pkgerrors.Wrapf(err, "unable to open file %q", diffFilePath)
291292
}
292293
if err := writeDiffToFile(filePathOriginal, filePathModified, diffFile); err != nil {
293-
return errors.Wrapf(err, "failed to write diff to file %q", diffFilePath)
294+
return pkgerrors.Wrapf(err, "failed to write diff to file %q", diffFilePath)
294295
}
295296
}
296297
if len(out.Modified) != 0 {
@@ -303,10 +304,10 @@ func writeOutputFiles(out *cluster.TopologyPlanOutput, outDir string) error {
303304
func writeObjectToFile(filePath string, obj *unstructured.Unstructured) error {
304305
yaml, err := utilyaml.FromUnstructured([]unstructured.Unstructured{*obj})
305306
if err != nil {
306-
return errors.Wrap(err, "failed to convert object to yaml")
307+
return pkgerrors.Wrap(err, "failed to convert object to yaml")
307308
}
308309
if err := os.WriteFile(filePath, yaml, 0600); err != nil {
309-
return errors.Wrapf(err, "failed to write yaml to file %q", filePath)
310+
return pkgerrors.Wrapf(err, "failed to write yaml to file %q", filePath)
310311
}
311312
return nil
312313
}
@@ -348,7 +349,7 @@ func writeDiffToFile(from, to string, out io.Writer) error {
348349
cmd.SetStdout(out)
349350

350351
if err := cmd.Run(); err != nil && !isDiffError(err) {
351-
return errors.Wrapf(err, "failed to run %q", diff)
352+
return pkgerrors.Wrapf(err, "failed to run %q", diff)
352353
}
353354
return nil
354355
}
@@ -382,7 +383,8 @@ func getDiffCommand(args ...string) (string, exec.Cmd) {
382383
// This makes use of the exit code of diff programs which is 0 for no diff, 1 for
383384
// modified and 2 for other errors.
384385
func isDiffError(err error) bool {
385-
if err, ok := err.(exec.ExitError); ok && err.ExitStatus() <= 1 {
386+
var exitErr exec.ExitError
387+
if errors.As(err, &exitErr) && exitErr.ExitStatus() <= 1 {
386388
return true
387389
}
388390
return false

test/framework/cluster_proxy.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ import (
2222
"fmt"
2323
"net/url"
2424
"os"
25+
"os/exec"
2526
"path"
2627
goruntime "runtime"
2728
"sync"
2829
"time"
2930

3031
. "github.com/onsi/ginkgo/v2"
3132
. "github.com/onsi/gomega"
33+
pkgerrors "github.com/pkg/errors"
3234
corev1 "k8s.io/api/core/v1"
3335
"k8s.io/apimachinery/pkg/runtime"
3436
"k8s.io/apimachinery/pkg/util/wait"
@@ -42,7 +44,7 @@ import (
4244

4345
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
4446
expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
45-
"sigs.k8s.io/cluster-api/test/framework/exec"
47+
testexec "sigs.k8s.io/cluster-api/test/framework/exec"
4648
"sigs.k8s.io/cluster-api/test/framework/internal/log"
4749
"sigs.k8s.io/cluster-api/test/infrastructure/container"
4850
)
@@ -250,7 +252,15 @@ func (p *clusterProxy) Apply(ctx context.Context, resources []byte, args ...stri
250252
Expect(ctx).NotTo(BeNil(), "ctx is required for Apply")
251253
Expect(resources).NotTo(BeNil(), "resources is required for Apply")
252254

253-
return exec.KubectlApply(ctx, p.kubeconfigPath, resources, args...)
255+
if err := testexec.KubectlApply(ctx, p.kubeconfigPath, resources, args...); err != nil {
256+
var exitErr *exec.ExitError
257+
if errors.As(err, &exitErr) {
258+
return pkgerrors.New(fmt.Sprintf("%s: stderr: %s", err.Error(), exitErr.Stderr))
259+
}
260+
return err
261+
}
262+
263+
return nil
254264
}
255265

256266
func (p *clusterProxy) GetRESTConfig() *rest.Config {

test/framework/clusterctl/client.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package clusterctl
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"os"
2324
"os/exec"
@@ -99,7 +100,8 @@ func InitWithBinary(_ context.Context, binary string, input InitInput) {
99100
_ = os.WriteFile(filepath.Join(input.LogFolder, "clusterctl-init.log"), out, 0644) //nolint:gosec // this is a log file to be shared via prow artifacts
100101
var stdErr string
101102
if err != nil {
102-
if exitErr, ok := err.(*exec.ExitError); ok {
103+
var exitErr *exec.ExitError
104+
if errors.As(err, &exitErr) {
103105
stdErr = string(exitErr.Stderr)
104106
}
105107
}
@@ -333,7 +335,8 @@ func ConfigClusterWithBinary(_ context.Context, clusterctlBinaryPath string, inp
333335
_ = os.WriteFile(filepath.Join(input.LogFolder, fmt.Sprintf("%s-cluster-template.yaml", input.ClusterName)), out, 0644) //nolint:gosec // this is a log file to be shared via prow artifacts
334336
var stdErr string
335337
if err != nil {
336-
if exitErr, ok := err.(*exec.ExitError); ok {
338+
var exitErr *exec.ExitError
339+
if errors.As(err, &exitErr) {
337340
stdErr = string(exitErr.Stderr)
338341
}
339342
}

test/framework/exec/kubectl.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"context"
2222
"fmt"
2323
"os"
24+
"strings"
2425
)
2526

2627
// KubectlApply shells out to kubectl apply.
@@ -34,13 +35,12 @@ func KubectlApply(ctx context.Context, kubeconfigPath string, resources []byte,
3435
WithArgs(aargs...),
3536
WithStdin(rbytes),
3637
)
38+
39+
fmt.Printf("Running kubectl %s\n", strings.Join(aargs, " "))
3740
stdout, stderr, err := applyCmd.Run(ctx)
38-
if err != nil {
39-
fmt.Println(string(stderr))
40-
return err
41-
}
42-
fmt.Println(string(stdout))
43-
return nil
41+
fmt.Printf("stderr:\n%s\n", string(stderr))
42+
fmt.Printf("stdout:\n%s\n", string(stdout))
43+
return err
4444
}
4545

4646
// KubectlWait shells out to kubectl wait.

0 commit comments

Comments
 (0)