generated from kubernetes/kubernetes-template-project
-
Notifications
You must be signed in to change notification settings - Fork 103
/
app.go
141 lines (123 loc) · 4.14 KB
/
app.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
"fmt"
"os"
"path/filepath"
"github.com/pkg/errors"
"k8s.io/klog"
"sigs.k8s.io/kubetest2/pkg/exec"
"sigs.k8s.io/kubetest2/pkg/metadata"
"sigs.k8s.io/kubetest2/pkg/types"
)
// Main implements the kubetest2 deployer binary entrypoint
// Each deployer binary should invoke this, in addition to loading deployers
func Main(deployerName string, newDeployer types.NewDeployer) {
// see cmd.go for the rest of the CLI boilerplate
if err := Run(deployerName, newDeployer); err != nil {
// only print the error if it's not an IncorrectUsage (which we've)
// already output along with usage
if _, isUsage := err.(types.IncorrectUsage); !isUsage {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
}
os.Exit(1)
}
}
// RealMain contains nearly all of the application logic / control flow
// beyond the command line boilerplate
func RealMain(opts types.Options, d types.Deployer, tester types.Tester) (result error) {
/*
Now for the core kubetest2 logic:
- build
- cluster up
- test
- cluster down
Throughout this, collecting metadata and writing it out on exit
*/
// TODO(bentheelder): signal handling & timeout
// ensure the artifacts dir
if err := os.MkdirAll(opts.ArtifactsDir(), os.ModePerm); err != nil {
return err
}
// setup the metadata writer
junitRunner, err := os.Create(
filepath.Join(opts.ArtifactsDir(), "junit_runner.xml"),
)
if err != nil {
return errors.Wrap(err, "could not create runner output")
}
writer := metadata.NewWriter(junitRunner)
// defer writing out the metadata on exit
// NOTE: defer is LIFO, so this should actually be the finish time
defer func() {
// TODO(bentheelder): instead of keeping the first error, consider
// a multi-error type
if err := writer.Finish(); err != nil && result == nil {
result = err
}
if err := junitRunner.Sync(); err != nil && result == nil {
result = err
}
if err := junitRunner.Close(); err != nil && result == nil {
result = err
}
}()
klog.Infof("ID for this run: %q", opts.RunID())
// build if specified
if opts.ShouldBuild() {
if err := writer.WrapStep("Build", d.Build); err != nil {
// we do not continue to up / test etc. if build fails
return err
}
}
// ensure tearing down the cluster happens last, even if up or test fails.
defer func() {
if opts.ShouldDown() {
// TODO(bentheelder): instead of keeping the first error, consider
// a multi-error type
if err := writer.WrapStep("Down", d.Down); err != nil && result == nil {
result = err
}
}
}()
// up a cluster
if opts.ShouldUp() {
// TODO(bentheelder): this should write out to JUnit
if err := writer.WrapStep("Up", d.Up); err != nil {
// we do not continue to test if build fails
return err
}
}
// and finally test, if a test was specified
if opts.ShouldTest() {
test := exec.Command(tester.TesterPath, tester.TesterArgs...)
exec.InheritOutput(test)
envsForTester := os.Environ()
envsForTester = append(envsForTester, fmt.Sprintf("%s=%s", "ARTIFACTS", opts.ArtifactsDir()))
envsForTester = append(envsForTester, fmt.Sprintf("%s=%s", "KUBETEST2_RUN_ID", opts.RunID()))
// If the deployer provides a kubeconfig pass it to the tester
// else assumes that it is handled offline by default methods like
// ~/.kube/config
if dWithKubeconfig, ok := d.(types.DeployerWithKubeconfig); ok {
if kconfig, err := dWithKubeconfig.Kubeconfig(); err == nil {
envsForTester = append(envsForTester, fmt.Sprintf("%s=%s", "KUBECONFIG", kconfig))
}
}
test.SetEnv(envsForTester...)
if err := writer.WrapStep("Test", test.Run); err != nil {
return err
}
}
return nil
}