Skip to content

Commit 6561df5

Browse files
authored
Merge pull request #9766 from sbueringer/pr-improve-apply-output-1.4
[release-1.4] 🌱 Improve output of exec.KubectlApply
2 parents ae0ae3e + e145cc0 commit 6561df5

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
@@ -17,6 +17,7 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"io"
2223
"os"
@@ -27,7 +28,7 @@ import (
2728
"strings"
2829

2930
"github.com/olekukonko/tablewriter"
30-
"github.com/pkg/errors"
31+
pkgerrors "github.com/pkg/errors"
3132
"github.com/spf13/cobra"
3233
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3334
"k8s.io/utils/exec"
@@ -118,11 +119,11 @@ func runTopologyPlan() error {
118119
for _, f := range tp.files {
119120
raw, err := os.ReadFile(f) //nolint:gosec
120121
if err != nil {
121-
return errors.Wrapf(err, "failed to read input file %q", f)
122+
return pkgerrors.Wrapf(err, "failed to read input file %q", f)
122123
}
123124
objects, err := utilyaml.ToUnstructured(raw)
124125
if err != nil {
125-
return errors.Wrapf(err, "failed to convert file %q to list of objects", f)
126+
return pkgerrors.Wrapf(err, "failed to convert file %q to list of objects", f)
126127
}
127128
objs = append(objs, objects...)
128129
}
@@ -151,7 +152,7 @@ func printTopologyPlanOutput(out *cluster.TopologyPlanOutput, outdir string) err
151152
} else {
152153
printChangeSummary(out)
153154
if err := writeOutputFiles(out, outdir); err != nil {
154-
return errors.Wrap(err, "failed to write output files of target cluster changes")
155+
return pkgerrors.Wrap(err, "failed to write output files of target cluster changes")
155156
}
156157
}
157158
fmt.Printf("\n")
@@ -230,17 +231,17 @@ func writeOutputFiles(out *cluster.TopologyPlanOutput, outDir string) error {
230231
// Write created files
231232
createdDir := path.Join(outDir, "created")
232233
if err := os.MkdirAll(createdDir, 0750); err != nil {
233-
return errors.Wrapf(err, "failed to create %q directory", createdDir)
234+
return pkgerrors.Wrapf(err, "failed to create %q directory", createdDir)
234235
}
235236
for _, c := range out.Created {
236237
yaml, err := utilyaml.FromUnstructured([]unstructured.Unstructured{*c})
237238
if err != nil {
238-
return errors.Wrap(err, "failed to convert object to yaml")
239+
return pkgerrors.Wrap(err, "failed to convert object to yaml")
239240
}
240241
fileName := fmt.Sprintf("%s_%s_%s.yaml", c.GetKind(), c.GetNamespace(), c.GetName())
241242
filePath := path.Join(createdDir, fileName)
242243
if err := os.WriteFile(filePath, yaml, 0600); err != nil {
243-
return errors.Wrapf(err, "failed to write yaml to file %q", filePath)
244+
return pkgerrors.Wrapf(err, "failed to write yaml to file %q", filePath)
244245
}
245246
}
246247
if len(out.Created) != 0 {
@@ -250,44 +251,44 @@ func writeOutputFiles(out *cluster.TopologyPlanOutput, outDir string) error {
250251
// Write modified files
251252
modifiedDir := path.Join(outDir, "modified")
252253
if err := os.MkdirAll(modifiedDir, 0750); err != nil {
253-
return errors.Wrapf(err, "failed to create %q directory", modifiedDir)
254+
return pkgerrors.Wrapf(err, "failed to create %q directory", modifiedDir)
254255
}
255256
for _, m := range out.Modified {
256257
// Write the modified object to file.
257258
fileNameModified := fmt.Sprintf("%s_%s_%s.modified.yaml", m.After.GetKind(), m.After.GetNamespace(), m.After.GetName())
258259
filePathModified := path.Join(modifiedDir, fileNameModified)
259260
if err := writeObjectToFile(filePathModified, m.After); err != nil {
260-
return errors.Wrap(err, "failed to write modified object to file")
261+
return pkgerrors.Wrap(err, "failed to write modified object to file")
261262
}
262263

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

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

282283
// Calculate the diff and write to a file.
283284
diffFileName := fmt.Sprintf("%s_%s_%s.diff", m.After.GetKind(), m.After.GetNamespace(), m.After.GetName())
284285
diffFilePath := path.Join(modifiedDir, diffFileName)
285286
diffFile, err := os.OpenFile(filepath.Clean(diffFilePath), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
286287
if err != nil {
287-
return errors.Wrapf(err, "unable to open file %q", diffFilePath)
288+
return pkgerrors.Wrapf(err, "unable to open file %q", diffFilePath)
288289
}
289290
if err := writeDiffToFile(filePathOriginal, filePathModified, diffFile); err != nil {
290-
return errors.Wrapf(err, "failed to write diff to file %q", diffFilePath)
291+
return pkgerrors.Wrapf(err, "failed to write diff to file %q", diffFilePath)
291292
}
292293
}
293294
if len(out.Modified) != 0 {
@@ -300,10 +301,10 @@ func writeOutputFiles(out *cluster.TopologyPlanOutput, outDir string) error {
300301
func writeObjectToFile(filePath string, obj *unstructured.Unstructured) error {
301302
yaml, err := utilyaml.FromUnstructured([]unstructured.Unstructured{*obj})
302303
if err != nil {
303-
return errors.Wrap(err, "failed to convert object to yaml")
304+
return pkgerrors.Wrap(err, "failed to convert object to yaml")
304305
}
305306
if err := os.WriteFile(filePath, yaml, 0600); err != nil {
306-
return errors.Wrapf(err, "failed to write yaml to file %q", filePath)
307+
return pkgerrors.Wrapf(err, "failed to write yaml to file %q", filePath)
307308
}
308309
return nil
309310
}
@@ -345,7 +346,7 @@ func writeDiffToFile(from, to string, out io.Writer) error {
345346
cmd.SetStdout(out)
346347

347348
if err := cmd.Run(); err != nil && !isDiffError(err) {
348-
return errors.Wrapf(err, "failed to run %q", diff)
349+
return pkgerrors.Wrapf(err, "failed to run %q", diff)
349350
}
350351
return nil
351352
}
@@ -379,7 +380,8 @@ func getDiffCommand(args ...string) (string, exec.Cmd) {
379380
// This makes use of the exit code of diff programs which is 0 for no diff, 1 for
380381
// modified and 2 for other errors.
381382
func isDiffError(err error) bool {
382-
if err, ok := err.(exec.ExitError); ok && err.ExitStatus() <= 1 {
383+
var exitErr exec.ExitError
384+
if errors.As(err, &exitErr) && exitErr.ExitStatus() <= 1 {
383385
return true
384386
}
385387
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
)
@@ -244,7 +246,15 @@ func (p *clusterProxy) Apply(ctx context.Context, resources []byte, args ...stri
244246
Expect(ctx).NotTo(BeNil(), "ctx is required for Apply")
245247
Expect(resources).NotTo(BeNil(), "resources is required for Apply")
246248

247-
return exec.KubectlApply(ctx, p.kubeconfigPath, resources, args...)
249+
if err := testexec.KubectlApply(ctx, p.kubeconfigPath, resources, args...); err != nil {
250+
var exitErr *exec.ExitError
251+
if errors.As(err, &exitErr) {
252+
return pkgerrors.New(fmt.Sprintf("%s: stderr: %s", err.Error(), exitErr.Stderr))
253+
}
254+
return err
255+
}
256+
257+
return nil
248258
}
249259

250260
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"
@@ -97,7 +98,8 @@ func InitWithBinary(_ context.Context, binary string, input InitInput) {
9798
_ = os.WriteFile(filepath.Join(input.LogFolder, "clusterctl-init.log"), out, 0644) //nolint:gosec // this is a log file to be shared via prow artifacts
9899
var stdErr string
99100
if err != nil {
100-
if exitErr, ok := err.(*exec.ExitError); ok {
101+
var exitErr *exec.ExitError
102+
if errors.As(err, &exitErr) {
101103
stdErr = string(exitErr.Stderr)
102104
}
103105
}
@@ -359,7 +361,8 @@ func ConfigClusterWithBinary(_ context.Context, clusterctlBinaryPath string, inp
359361
_ = 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
360362
var stdErr string
361363
if err != nil {
362-
if exitErr, ok := err.(*exec.ExitError); ok {
364+
var exitErr *exec.ExitError
365+
if errors.As(err, &exitErr) {
363366
stdErr = string(exitErr.Stderr)
364367
}
365368
}

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)