-
Notifications
You must be signed in to change notification settings - Fork 1.8k
pkg/test: add in-cluster/in-image testing support #469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pkg/test: add in-cluster/in-image testing support #469
Conversation
749d6e0
to
0cbc804
Compare
@@ -42,12 +56,79 @@ For example: | |||
`, | |||
Run: buildFunc, | |||
} | |||
buildCmd.Flags().BoolVarP(&enableTests, "enable-tests", "e", false, "Enable in-cluster testing by adding test binary to the image") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are keeping the default false for now and plan on changing it? I think eventually this should be a default of true? Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, we will keep it as default false. The SDK does not create any default tests for operators and the build would fail in that case. This is why we need a user to confirm that they have tests that they want to include. The test binary is also 34 MB, which may be undesirable to include by default.
commands/operator-sdk/cmd/build.go
Outdated
dbcmd.Env = append(os.Environ(), fmt.Sprintf("IMAGE=%v", image)) | ||
intermediateImageName := image | ||
if enableTests { | ||
if namespacedManBuild == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if pulling this code block into its own function may make this more readable?
0cbc804
to
7cfeb77
Compare
6a1309b
to
aa34ac0
Compare
The cluster test has defers that need to run on error, which would not run if cmdError is used due to its use of os.Exit(). Instead, we can just return an error, which allows the defer functions to run.
This adds tests for the new incluster image testing mode as well as fixes some bugs that this test exposed
We don't need to do any extra operations anymore if a user does not supply a namespaced manifest path, so we can just use a default string
389d16a
to
4f303c7
Compare
c152125
to
50eb65c
Compare
pkg/generator/templates.go
Outdated
command: ["/go-test.sh"] | ||
resources: | ||
requests: | ||
cpu: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should specify resource requests by default. This could prevent the pod from being scheduled onto a node if there isn't enough cpu.
By not setting a default, the pod will either take on the default request and limit enforced by the namespace, or use as much as is available.
commands/operator-sdk/cmd/build.go
Outdated
func renderTestManifest(image string) error { | ||
namespacedBytes, err := ioutil.ReadFile(namespacedManBuild) | ||
if err != nil { | ||
log.Fatalf("could not read rbac manifest: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not rbac manifest(at least not in the test cluster
case).
log.Fatalf("could not read namespaced manifest: %v", err)
commands/operator-sdk/cmd/build.go
Outdated
log.Fatalf("could not read rbac manifest: %v", err) | ||
} | ||
if err = generator.RenderTestYaml(cmdutil.GetConfig(), image); err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to generate deploy/test-pod.yaml: (%v)", err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use log.Fatalf()
instead of cmdError.ExitWithError()
. It's the exact same thing except it returns a specific error code.
We're going to remove cmdError.ExitWithError since returning error codes isn't as useful as we thought initially, and we never specified more than two codes.
commands/operator-sdk/cmd/build.go
Outdated
if err = generator.RenderTestYaml(cmdutil.GetConfig(), image); err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to generate deploy/test-pod.yaml: (%v)", err)) | ||
} | ||
return verifyDeploymentImage(namespacedBytes, image) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only error renderTestManifest()
returns is actually just treated as a warning that's just printed out.
genWarning := renderTestManifest(image)
if genWarning != nil {
fmt.Printf("%s\n", genWarning)
}
For the other two errors it just fails fast with log.Fatal
.
So change renderTestManifest()
to not return an error.
And print the warning message from verifyDeploymentImage()
either here or outside this function by just checking the error returned directly from it.
pkg/generator/templates.go
Outdated
@@ -562,7 +588,12 @@ fi | |||
: ${IMAGE:?"Need to set IMAGE, e.g. gcr.io/<repo>/<your>-operator"} | |||
|
|||
echo "building container ${IMAGE}..." | |||
docker build -t "${IMAGE}" -f tmp/build/Dockerfile . | |||
docker build -t "${IMAGE}" -f tmp/build/Dockerfile . --build-arg NAMESPACEDMAN=$NAMESPACEDMAN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're no longer using this docker-build.sh
script anymore right? We're just calling docker build
directly in operator-sdk build
.
So we should probably not generate this anymore.
pkg/generator/generator.go
Outdated
return err | ||
} | ||
return renderWriteFile(filepath.Join(buildDir, dockerfile), "tmp/build/Dockerfile", dockerFileTmpl, dTd) | ||
return writeFileAndPrint(filepath.Join(buildDir, goTest), buf.Bytes(), os.FileMode(int(0755))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the constant defaultExecFileMode
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaultExecMode is currently set to 0744, which doesn't work for this setup. Should I change defaultExecMode to 0755?
pkg/test/framework.go
Outdated
inCluster := false | ||
if *kubeconfigPath == "incluster" { | ||
// Work around https://github.com/kubernetes/kubernetes/issues/40973 | ||
// See https://github.com/coreos/etcd-operator/issues/731#issuecomment-283804819 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: We can remove the etcd-operator issue link since we're linking to the upstream issue in the line above.
ImagePullPolicy: pullPolicy, | ||
Command: []string{"/go-test.sh"}, | ||
Env: []v1.EnvVar{{ | ||
Name: "TEST_NAMESPACE", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Define this as a constant somewhere. In pkg/test probably.
pkg/test/framework.go
Outdated
@@ -114,7 +138,11 @@ func AddToFrameworkScheme(addToScheme addToSchemeFunc, obj runtime.Object) error | |||
Global.RestMapper.Reset() | |||
Global.DynamicClient, err = dynclient.New(Global.KubeConfig, dynclient.Options{Scheme: Global.Scheme, Mapper: Global.RestMapper}) | |||
err = wait.PollImmediate(time.Second, time.Second*10, func() (done bool, err error) { | |||
err = Global.DynamicClient.List(goctx.TODO(), &dynclient.ListOptions{Namespace: "default"}, obj) | |||
if Global.InCluster { | |||
err = Global.DynamicClient.List(goctx.TODO(), &dynclient.ListOptions{Namespace: os.Getenv("TEST_NAMESPACE")}, obj) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should verify that TEST_NAMESPACE
is not empty in the incluster
case above, before using it here and in ctx.GetNamespace()
.
} | ||
testCmd.Flags().StringVarP(&testNamespace, "namespace", "n", "default", "Namespace to run tests in") | ||
testCmd.Flags().StringVarP(&kubeconfigCluster, "kubeconfig", "k", defaultKubeConfig, "Kubeconfig path") | ||
testCmd.Flags().StringVarP(&imagePullPolicy, "imagePullPolicy", "i", "Always", "Set test pod image pull policy. Allowed values: Always, Never") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more nit here: Is there a reason to ask people to capitalize the words "always" and "never"? It's somewhat unusual for a CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason was that they are capitalized in the config file. I could change it, or maybe use strings.ToLower(...)
and support both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've decided to support both upper and lowercase
commands/operator-sdk/cmd/build.go
Outdated
log.Fatalf("failed to generate deploy/test-pod.yaml: (%v)", err) | ||
} | ||
// the error from verifyDeploymentImage is just a warning, not fatal error | ||
fmt.Printf("%v", verifyDeploymentImage(namespacedBytes, image)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this print <nil>
every time if there's no error returned by verifyDeploymentImage()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it does; I somehow missed that. I'll put a nil check there
@@ -238,20 +266,10 @@ func MemcachedCluster(t *testing.T) { | |||
f := framework.Global | |||
ctx := f.NewTestCtx(t) | |||
defer ctx.Cleanup(t) | |||
operatorYAML, err := ioutil.ReadFile("deploy/operator.yaml") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the returned error.
LGTM after nit. Great work. |
Issue #435