Skip to content

Commit c60b196

Browse files
bors[bot]Marko Mikulicic
and
Marko Mikulicic
authored
Merge #245 #247
245: Don't panic on error r=mkmik a=mkmik Currently when `kubeseal` wants to report an error, we just `panic` from main, which is ugly. This change also weaves CLI flags into a `run` function so that we can test that in isolation. 247: Include upstream error in kubeseal --rotate and --validate r=mkmik a=mkmik Co-authored-by: Marko Mikulicic <[email protected]>
3 parents 85ced12 + a692db5 + cadc1c5 commit c60b196

File tree

4 files changed

+101
-51
lines changed

4 files changed

+101
-51
lines changed

cmd/kubeseal/main.go

+33-37
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func prettyEncoder(codecs runtimeserializer.CodecFactory, mediaType string, gv r
128128
func openCertFile(certFile string) (io.ReadCloser, error) {
129129
f, err := os.Open(certFile)
130130
if err != nil {
131-
return nil, fmt.Errorf("Error reading %s: %v", certFile, err)
131+
return nil, err
132132
}
133133
return f, nil
134134
}
@@ -139,14 +139,14 @@ func openCertHTTP(c corev1.CoreV1Interface, namespace, name string) (io.ReadClos
139139
ProxyGet("http", name, "", "/v1/cert.pem", nil).
140140
Stream()
141141
if err != nil {
142-
return nil, fmt.Errorf("Error fetching certificate: %v", err)
142+
return nil, fmt.Errorf("cannot fetch certificate: %v", err)
143143
}
144144
return f, nil
145145
}
146146

147-
func openCert() (io.ReadCloser, error) {
148-
if *certFile != "" {
149-
return openCertFile(*certFile)
147+
func openCert(certFile string) (io.ReadCloser, error) {
148+
if certFile != "" {
149+
return openCertFile(certFile)
150150
}
151151

152152
conf, err := clientConfig.ClientConfig()
@@ -233,9 +233,9 @@ func validateSealedSecret(in io.Reader, namespace, name string) error {
233233
res := req.Do()
234234
if err := res.Error(); err != nil {
235235
if status, ok := err.(*k8serrors.StatusError); ok && status.Status().Code == http.StatusConflict {
236-
return fmt.Errorf("Unable to decrypt sealed secret")
236+
return fmt.Errorf("unable to decrypt sealed secret")
237237
}
238-
return fmt.Errorf("Error occurred while validating sealed secret")
238+
return fmt.Errorf("cannot validate sealed secret: %v", err)
239239
}
240240

241241
return nil
@@ -267,9 +267,9 @@ func rotateSealedSecret(in io.Reader, out io.Writer, codecs runtimeserializer.Co
267267
res := req.Do()
268268
if err := res.Error(); err != nil {
269269
if status, ok := err.(*k8serrors.StatusError); ok && status.Status().Code == http.StatusConflict {
270-
return fmt.Errorf("Unable to rotate secret")
270+
return fmt.Errorf("unable to rotate secret")
271271
}
272-
return fmt.Errorf("Error occurred while rotating secret")
272+
return fmt.Errorf("cannot rotate secret: %v", err)
273273
}
274274
body, err := res.Raw()
275275
if err != nil {
@@ -311,49 +311,45 @@ func sealedSecretOutput(out io.Writer, codecs runtimeserializer.CodecFactory, ss
311311
return nil
312312
}
313313

314-
func main() {
315-
flag.Parse()
316-
goflag.CommandLine.Parse([]string{})
317-
318-
if *printVersion {
319-
fmt.Printf("kubeseal version: %s\n", VERSION)
320-
return
314+
func run(w io.Writer, controllerNs, controllerName, certFile string, printVersion, validateSecret, rotate, dumpCert bool) error {
315+
if printVersion {
316+
fmt.Fprintf(w, "kubeseal version: %s\n", VERSION)
317+
return nil
321318
}
322319

323-
if *validateSecret {
324-
err := validateSealedSecret(os.Stdin, *controllerNs, *controllerName)
325-
if err != nil {
326-
panic(err.Error())
327-
}
328-
return
320+
if validateSecret {
321+
return validateSealedSecret(os.Stdin, controllerNs, controllerName)
329322
}
330323

331-
if *rotate {
332-
if err := rotateSealedSecret(os.Stdin, os.Stdout, scheme.Codecs, *controllerNs, *controllerName); err != nil {
333-
panic(err.Error())
334-
}
335-
return
324+
if rotate {
325+
return rotateSealedSecret(os.Stdin, os.Stdout, scheme.Codecs, controllerNs, controllerName)
336326
}
337327

338-
f, err := openCert()
328+
f, err := openCert(certFile)
339329
if err != nil {
340-
panic(err.Error())
330+
return err
341331
}
342332
defer f.Close()
343333

344-
if *dumpCert {
345-
if _, err := io.Copy(os.Stdout, f); err != nil {
346-
panic(err.Error())
347-
}
348-
return
334+
if dumpCert {
335+
_, err := io.Copy(os.Stdout, f)
336+
return err
349337
}
350338

351339
pubKey, err := parseKey(f)
352340
if err != nil {
353-
panic(err.Error())
341+
return err
354342
}
355343

356-
if err := seal(os.Stdin, os.Stdout, scheme.Codecs, pubKey); err != nil {
357-
panic(err.Error())
344+
return seal(os.Stdin, os.Stdout, scheme.Codecs, pubKey)
345+
}
346+
347+
func main() {
348+
flag.Parse()
349+
goflag.CommandLine.Parse([]string{})
350+
351+
if err := run(os.Stdout, *controllerNs, *controllerName, *certFile, *printVersion, *validateSecret, *rotate, *dumpCert); err != nil {
352+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
353+
os.Exit(1)
358354
}
359355
}

cmd/kubeseal/main_test.go

+24-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"strings"
1212
"testing"
1313

14-
"k8s.io/api/core/v1"
14+
v1 "k8s.io/api/core/v1"
1515
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1616
"k8s.io/apimachinery/pkg/runtime"
1717
"k8s.io/client-go/kubernetes/scheme"
@@ -98,13 +98,9 @@ func TestParseKey(t *testing.T) {
9898
}
9999

100100
func TestOpenCertFile(t *testing.T) {
101-
*certFile = tmpfile(t, []byte(testCert))
102-
defer func() {
103-
os.Remove(*certFile)
104-
*certFile = ""
105-
}()
101+
certFile := tmpfile(t, []byte(testCert))
106102

107-
f, err := openCert()
103+
f, err := openCert(certFile)
108104
if err != nil {
109105
t.Fatalf("Error reading test cert file: %v", err)
110106
}
@@ -178,3 +174,24 @@ func TestSeal(t *testing.T) {
178174
}
179175
// NB: See sealedsecret_test.go for e2e crypto test
180176
}
177+
178+
func TestVersion(t *testing.T) {
179+
var buf strings.Builder
180+
err := run(&buf, "", "", "", true, false, false, false)
181+
if err != nil {
182+
t.Fatal(err)
183+
}
184+
185+
if got, want := buf.String(), "kubeseal version: UNKNOWN\n"; got != want {
186+
t.Errorf("got: %q, want: %q", got, want)
187+
}
188+
}
189+
190+
func TestMainError(t *testing.T) {
191+
const badFileName = "/?this/file/cannot/possibly/exist/can/it?"
192+
err := run(ioutil.Discard, "", "", badFileName, false, false, false, false)
193+
194+
if err == nil || !os.IsNotExist(err) {
195+
t.Fatalf("expecting not exist error, got: %v", err)
196+
}
197+
}

integration/integration_suite_test.go

+24-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"os/exec"
1313
"testing"
1414

15-
"k8s.io/api/core/v1"
15+
v1 "k8s.io/api/core/v1"
1616
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1717
"k8s.io/apimachinery/pkg/runtime"
1818
"k8s.io/client-go/kubernetes/scheme"
@@ -80,14 +80,14 @@ func containsString(haystack []string, needle string) bool {
8080
return false
8181
}
8282

83-
func runKubeseal(flags []string, input io.Reader, output io.Writer) error {
83+
func runKubeseal(flags []string, input io.Reader, output io.Writer, opts ...runAppOpt) error {
8484
args := []string{}
8585
if *kubeconfig != "" && !containsString(flags, "--kubeconfig") {
8686
args = append(args, "--kubeconfig", *kubeconfig)
8787
}
8888
args = append(args, flags...)
8989

90-
return runApp(*kubesealBin, args, input, output)
90+
return runApp(*kubesealBin, args, input, output, opts...)
9191
}
9292

9393
type interruptableReader struct {
@@ -129,17 +129,34 @@ func runController(flags []string, input io.Reader, output io.Writer) error {
129129
return runApp(*controllerBin, flags, input, output)
130130
}
131131

132-
func runApp(app string, flags []string, input io.Reader, output io.Writer) error {
132+
type runAppOpt func(*runAppOpts)
133+
134+
type runAppOpts struct {
135+
stderr io.Writer
136+
}
137+
138+
func runAppWithStderr(w io.Writer) runAppOpt {
139+
return func(o *runAppOpts) { o.stderr = w }
140+
}
141+
142+
func runApp(app string, flags []string, input io.Reader, output io.Writer, opts ...runAppOpt) error {
143+
options := runAppOpts{
144+
stderr: GinkgoWriter,
145+
}
146+
for _, o := range opts {
147+
o(&options)
148+
}
149+
133150
fmt.Fprintf(GinkgoWriter, "Running %q %q\n", app, flags)
134151
cmd := exec.Command(app, flags...)
135152
cmd.Stdin = input
136153
cmd.Stdout = output
137-
cmd.Stderr = GinkgoWriter
154+
cmd.Stderr = options.stderr
138155

139156
return cmd.Run()
140157
}
141158

142-
func runKubesealWith(flags []string, input runtime.Object) (runtime.Object, error) {
159+
func runKubesealWith(flags []string, input runtime.Object, opts ...runAppOpt) (runtime.Object, error) {
143160
enc := scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)
144161
indata, err := runtime.Encode(enc, input)
145162
if err != nil {
@@ -150,7 +167,7 @@ func runKubesealWith(flags []string, input runtime.Object) (runtime.Object, erro
150167

151168
outbuf := bytes.Buffer{}
152169

153-
if err := runKubeseal(flags, bytes.NewReader(indata), &outbuf); err != nil {
170+
if err := runKubeseal(flags, bytes.NewReader(indata), &outbuf, opts...); err != nil {
154171
return nil, err
155172
}
156173

integration/kubeseal_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,23 @@ var _ = Describe("kubeseal --verify", func() {
284284
})
285285

286286
})
287+
288+
var _ = Describe("kubeseal --cert", func() {
289+
var input io.Reader
290+
var output *bytes.Buffer
291+
var args []string
292+
293+
BeforeEach(func() {
294+
args = []string{"--cert", "/?this/file/cannot/possibly/exist/right?"}
295+
output = &bytes.Buffer{}
296+
})
297+
298+
JustBeforeEach(func() {
299+
err := runKubeseal(args, input, ioutil.Discard, runAppWithStderr(output))
300+
Expect(err).To(HaveOccurred())
301+
})
302+
303+
It("should return an error", func() {
304+
Expect(output.String()).Should(MatchRegexp("^error:.*no such file or directory"))
305+
})
306+
})

0 commit comments

Comments
 (0)