operator-framework / operator-sdk

SDK for building Kubernetes applications. Provides high level APIs, useful abstractions, and project scaffolding.
https://sdk.operatorframework.io
Apache License 2.0
7.27k stars 1.75k forks source link

operator up local works but operator test local --up-local does not. #1105

Closed aaronmcohen closed 5 years ago

aaronmcohen commented 5 years ago

Bug Report

What did you do?

Create a simple operator:

import ( "testing"

"github.com/operator-framework/operator-sdk/pkg/test"

)

func TestMain(m *testing.M) { test.MainEntry(m) }

- create `test/e2e/sample_test.go`
```go 
package e2e

import (
    "sample-operator/pkg/apis"
    "sample-operator/pkg/apis/example/v1"
    "testing"
    "time"

    "github.com/operator-framework/operator-sdk/pkg/test"
    "github.com/operator-framework/operator-sdk/pkg/test/e2eutil"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
    retryInterval        = time.Second * 5
    timeout              = time.Second * 120
    cleanupRetryInterval = time.Second * 1
    cleanupTimeout       = time.Second * 5
)

func TestSimple(t *testing.T) {

    sampleList := &v1.SampleList{
        TypeMeta: metav1.TypeMeta{
            Kind:       "Sample",
            APIVersion: "example.com/v1",
        },
    }
    crdError := test.AddToFrameworkScheme(apis.AddToScheme, sampleList)
    if crdError != nil {
        t.Fatalf("failed to add custom resource scheme to framework: %v", crdError)
    }
    ctx := test.NewTestCtx(t)
    defer ctx.Cleanup()
    crError := ctx.InitializeClusterResources(&test.CleanupOptions{TestContext: ctx, Timeout: cleanupTimeout, RetryInterval: cleanupRetryInterval})
    if crError != nil {
        t.Fatalf("failed to initialize cluster resources: %v", crError)
    }
    t.Log("Initialized cluster resources")
    namespace, err := ctx.GetNamespace()
    if err != nil {
        t.Fatal(err)
    }
    // get global framework variables
    f := test.Global
    // wait for memcached-operator to be ready
    err = e2eutil.WaitForDeployment(t, f.KubeClient, namespace, "sample-operator", 1, retryInterval, timeout)
    if err != nil {
        t.Fatal(err)
    }
}

A clear and concise description of the steps you took (or insert a code snippet).

What did you expect to see?

I expected the operator to start similar to operator up local and the test to run.

Out put of operator up local —-namespace default

INFO[0000] Running the operator locally.                
INFO[0000] Using namespace default.                     
{"level":"info","ts":1550435555.129973,"logger":"cmd","msg":"Go Version: go1.11.5"}
{"level":"info","ts":1550435555.130034,"logger":"cmd","msg":"Go OS/Arch: darwin/amd64"}
{"level":"info","ts":1550435555.130042,"logger":"cmd","msg":"Version of operator-sdk: v0.5.0+git"}
{"level":"info","ts":1550435555.131935,"logger":"leader","msg":"Trying to become the leader."}
{"level":"info","ts":1550435555.1319711,"logger":"leader","msg":"Skipping leader election; not running in a cluster."}
{"level":"info","ts":1550435555.179819,"logger":"cmd","msg":"Registering Components."}
{"level":"info","ts":1550435555.17999,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"sample-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1550435555.1802392,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"sample-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1550435555.180445,"logger":"metrics","msg":"Skipping metrics Service creation; not running in a cluster."}
{"level":"info","ts":1550435555.180456,"logger":"cmd","msg":"Starting the Cmd."}
{"level":"info","ts":1550435555.2845519,"logger":"kubebuilder.controller","msg":"Starting Controller","controller":"sample-controller"}
{"level":"info","ts":1550435555.388376,"logger":"kubebuilder.controller","msg":"Starting workers","controller":"sample-controller","worker count":1}
{"level":"info","ts":1550435555.3886878,"logger":"controller_sample","msg":"Reconciling Sample","Request.Namespace":"default","Request.Name":"example-sample"}
{"level":"info","ts":1550435555.388872,"logger":"controller_sample","msg":"Creating a new Pod","Request.Namespace":"default","Request.Name":"example-sample","Pod.Namespace":"default","Pod.Name":"example-sample-pod"}
{"level":"info","ts":1550435555.411828,"logger":"controller_sample","msg":"Reconciling Sample","Request.Namespace":"default","Request.Name":"example-sample"}
{"level":"info","ts":1550435555.411999,"logger":"controller_sample","msg":"Skip reconcile: Pod already exists","Request.Namespace":"default","Request.Name":"example-sample","Pod.Namespace":"default","Pod.Name":"example-sample-pod"}
{"level":"info","ts":1550435555.428324,"logger":"controller_sample","msg":"Reconciling Sample","Request.Namespace":"default","Request.Name":"example-sample"}
{"level":"info","ts":1550435555.4283772,"logger":"controller_sample","msg":"Skip reconcile: Pod already exists","Request.Namespace":"default","Request.Name":"example-sample","Pod.Namespace":"default","Pod.Name":"example-sample-pod"}
{"level":"info","ts":1550435555.441859,"logger":"controller_sample","msg":"Reconciling Sample","Request.Namespace":"default","Request.Name":"example-sample"}
{"level":"info","ts":1550435555.4419231,"logger":"controller_sample","msg":"Skip reconcile: Pod already exists","Request.Namespace":"default","Request.Name":"example-sample","Pod.Namespace":"default","Pod.Name":"example-sample-pod"}
{"level":"info","ts":1550435557.533906,"logger":"controller_sample","msg":"Reconciling Sample","Request.Namespace":"default","Request.Name":"example-sample"}
{"level":"info","ts":1550435557.5339751,"logger":"controller_sample","msg":"Skip reconcile: Pod already exists","Request.Namespace":"default","Request.Name":"example-sample","Pod.Namespace":"default","Pod.Name":"example-sample-pod"}

kubectl get pods

NAME                 READY   STATUS    RESTARTS   AGE
example-sample-pod   1/1     Running   0          7m50s

What did you see instead? Under which circumstances?

Output of operator-sdk test local --up-local --debug --namespace default .

INFO[0000] Testing operator locally.                    
?       sample-operator/cmd/manager [no test files]
?       sample-operator/pkg/apis    [no test files]
?       sample-operator/pkg/apis/example/v1 [no test files]
?       sample-operator/pkg/controller  [no test files]
?       sample-operator/pkg/controller/sample   [no test files]
time="2019-02-17T15:23:43-05:00" level=info msg="Started local operator"
--- FAIL: TestSimple (121.24s)
    client.go:57: resource type ServiceAccount with namespace/name (default/sample-operator) created
    client.go:57: resource type Role with namespace/name (default/sample-operator) created
    client.go:57: resource type RoleBinding with namespace/name (default/sample-operator) created
    client.go:57: resource type Deployment with namespace/name (default/sample-operator) created
    simple_test.go:40: Initialized cluster resources
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    wait_util.go:61: Waiting for full availability of sample-operator deployment (0/1)
    simple_test.go:50: timed out waiting for the condition
    client.go:75: resource type Deployment with namespace/name (default/sample-operator) successfully deleted
    client.go:75: resource type RoleBinding with namespace/name (default/sample-operator) successfully deleted
    client.go:75: resource type Role with namespace/name (default/sample-operator) successfully deleted
    client.go:75: resource type ServiceAccount with namespace/name (default/sample-operator) successfully deleted
FAIL
time="2019-02-17T15:25:44-05:00" level=info msg="Local operator stdout: unknown shorthand flag: 'o' in -o\n"
time="2019-02-17T15:25:44-05:00" level=info msg="Local operator stderr: unknown shorthand flag: 'o' in -o\nUsage of build/_output/bin/sample-operator-local:\n      --kubeconfig string     Paths to a kubeconfig. Only required if out-of-cluster.\n      --master string         The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.\n      --zap-devel             Enable zap development mode (changes defaults to console encoder, debug log level, and disables sampling)\n      --zap-encoder encoder   Zap log encoding ('json' or 'console')\n      --zap-level level       Zap log level (one of 'debug', 'info', 'error') (default info)\n      --zap-sample sample     Enable zap log sampling\n"
FAIL    sample-operator/test/e2d    122.170s
?       sample-operator/version [no test files]
Error: failed to exec []string{"go", "test", "./...", "-namespacedMan", "/var/folders/l2/ntz6vdlj2fqfjn4mt9brg7c80000gn/T/namespaced-manifest.yaml506854290", "-globalMan", "/var/folders/l2/ntz6vdlj2fqfjn4mt9brg7c80000gn/T/global-manifest.yaml635078601", "-root", "/Users/aaroncohen/go/src/sample-operator", "-singleNamespace", "-parallel=1", "-localOperator"}: exit status 1
Usage:
  operator-sdk test local <path to tests directory> [flags]

Flags:
      --debug                        Enable debug-level logging
      --global-manifest string       Path to manifest for Global resources (e.g. CRD manifests)
      --go-test-flags string         Additional flags to pass to go test
  -h, --help                         help for local
      --image string                 Use a different operator image from the one specified in the namespaced manifest
      --kubeconfig string            Kubeconfig path
      --molecule-test-flags string   Additional flags to pass to molecule test
      --namespace string             If non-empty, single namespace to run tests in
      --namespaced-manifest string   Path to manifest for per-test, namespaced resources (e.g. RBAC and Operator manifest)
      --no-setup                     Disable test resource creation
      --up-local                     Enable running operator locally with go run instead of as an image in the cluster

kubectl get pods

NAME                              READY   STATUS         RESTARTS   AGE
sample-operator-c4b59bc6d-zhbff   0/1     ErrImagePull   0          4s

kubectl describe pod sample-operator-c4b59bc6d-zhbff

Name:               sample-operator-c4b59bc6d-zhbff
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               minikube/10.0.2.15
Start Time:         Sun, 17 Feb 2019 15:23:44 -0500
Labels:             name=sample-operator
                    pod-template-hash=c4b59bc6d
Annotations:        <none>
Status:             Pending
IP:                 172.17.0.6
Controlled By:      ReplicaSet/sample-operator-c4b59bc6d
Containers:
  sample-operator:
    Container ID:  
    Image:         sample-operator:0.0.1
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Command:
      sample-operator
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    Restart Count:  0
    Environment:
      WATCH_NAMESPACE:  default (v1:metadata.namespace)
      POD_NAME:         sample-operator-c4b59bc6d-zhbff (v1:metadata.name)
      OPERATOR_NAME:    sample-operator
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from sample-operator-token-4kpdq (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  sample-operator-token-4kpdq:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  sample-operator-token-4kpdq
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  24s               default-scheduler  Successfully assigned default/sample-operator-c4b59bc6d-zhbff to minikube
  Normal   BackOff    22s               kubelet, minikube  Back-off pulling image "sample-operator:0.0.1"
  Warning  Failed     22s               kubelet, minikube  Error: ImagePullBackOff
  Normal   Pulling    8s (x2 over 23s)  kubelet, minikube  pulling image "sample-operator:0.0.1"
  Warning  Failed     8s (x2 over 23s)  kubelet, minikube  Failed to pull image "sample-operator:0.0.1": rpc error: code = Unknown desc = Error response from daemon: pull access denied for sample-operator, repository does not exist or may require 'docker login'
  Warning  Failed     8s (x2 over 23s)  kubelet, minikube  Error: ErrImagePull

Environment

This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.

[[projects]] digest = "1:2173c429b0c4654deb4f3e8d1f503c374f93a6b5549d74f9cba797c1e787f8e4" name = "cloud.google.com/go" packages = ["compute/metadata"] pruneopts = "NT" revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4" version = "v0.36.0"

[[projects]] digest = "1:75d2b55b13298745ec068057251d05d65bbae0a668201fe45ad6986551a55601" name = "github.com/BurntSushi/toml" packages = ["."] pruneopts = "NT" revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" version = "v0.3.1"

[[projects]] digest = "1:a26f8da48b22e6176c1c6a2459904bb30bd0c49ada04b2963c2c3a203e81a620" name = "github.com/Masterminds/semver" packages = ["."] pruneopts = "NT" revision = "c7af12943936e8c39859482e61f0574c2fd7fc75" version = "v1.4.2"

[[projects]] digest = "1:0a111edd8693fd977f42a0c4f199a0efb13c20aec9da99ad8830c7bb6a87e8d6" name = "github.com/PuerkitoBio/purell" packages = ["."] pruneopts = "NT" revision = "44968752391892e1b0d0b821ee79e9a85fa13049" version = "v1.1.1"

[[projects]] branch = "master" digest = "1:8098cd40cd09879efbf12e33bcd51ead4a66006ac802cd563a66c4f3373b9727" name = "github.com/PuerkitoBio/urlesc" packages = ["."] pruneopts = "NT" revision = "de5bf2ad457846296e2031421a34e2568e304e35"

[[projects]] digest = "1:680b63a131506e668818d630d3ca36123ff290afa0afc9f4be21940adca3f27d" name = "github.com/appscode/jsonpatch" packages = ["."] pruneopts = "NT" revision = "7c0e3b262f30165a8ec3d0b4c6059fd92703bfb2" version = "1.0.0"

[[projects]] branch = "master" digest = "1:c819830f4f5ef85874a90ac3cbcc96cd322c715f5c96fbe4722eacd3dafbaa07" name = "github.com/beorn7/perks" packages = ["quantile"] pruneopts = "NT" revision = "3a771d992973f24aa725d07868b467d1ddfceafb"

[[projects]] digest = "1:c61f4f97321a37adcb5b4fd4fd61209cd553e46c99ee606c465553541b12a229" name = "github.com/coreos/prometheus-operator" packages = [ "pkg/apis/monitoring", "pkg/apis/monitoring/v1", "pkg/client/versioned/scheme", "pkg/client/versioned/typed/monitoring/v1", ] pruneopts = "NT" revision = "72ec4b9b16ef11700724dc71fec77112536eed40" version = "v0.26.0"

[[projects]] digest = "1:4b8b5811da6970495e04d1f4e98bb89518cc3cfc3b3f456bdb876ed7b6c74049" name = "github.com/davecgh/go-spew" packages = ["spew"] pruneopts = "NT" revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1"

[[projects]] digest = "1:2453249730493850718f891fb40b8f1bc932a0265384fc85b269dc04a01d4673" name = "github.com/emicklei/go-restful" packages = [ ".", "log", ] pruneopts = "NT" revision = "85d198d05a92d31823b852b4a5928114912e8949" version = "v2.9.0"

[[projects]] digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756" name = "github.com/ghodss/yaml" packages = ["."] pruneopts = "NT" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0"

[[projects]] branch = "master" digest = "1:d421af4c4fe51d399667d573982d663fe1fa67020a88d3ae43466ebfe8e2b5c9" name = "github.com/go-logr/logr" packages = ["."] pruneopts = "NT" revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"

[[projects]] digest = "1:340497a512995aa69c0add901d79a2096b3449d35a44a6f1f1115091a9f8c687" name = "github.com/go-logr/zapr" packages = ["."] pruneopts = "NT" revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" version = "v0.1.0"

[[projects]] digest = "1:260f7ebefc63024c8dfe2c9f1a2935a89fa4213637a1f522f592f80c001cc441" name = "github.com/go-openapi/jsonpointer" packages = ["."] pruneopts = "NT" revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" version = "v0.18.0"

[[projects]] digest = "1:98abd61947ff5c7c6fcfec5473d02a4821ed3a2dd99a4fbfdb7925b0dd745546" name = "github.com/go-openapi/jsonreference" packages = ["."] pruneopts = "NT" revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3" version = "v0.18.0"

[[projects]] branch = "master" digest = "1:8f80caf2fa31f78a035f33981c9685013033073b53f344f579e60fa69f0c6670" name = "github.com/go-openapi/spec" packages = ["."] pruneopts = "NT" revision = "53d776530bf78a11b03a7b52dd8a083086b045e5"

[[projects]] digest = "1:dc0f590770e5a6c70ea086232324f7b7dc4857c60eca63ab8ff78e0a5cfcdbf3" name = "github.com/go-openapi/swag" packages = ["."] pruneopts = "NT" revision = "1d29f06aebd59ccdf11ae04aa0334ded96e2d909" version = "v0.18.0"

[[projects]] digest = "1:9059915429f7f3a5f18cfa6b7cab9a28721d7ac6db4079a62044aa229eb7f2a8" name = "github.com/gobuffalo/envy" packages = ["."] pruneopts = "NT" revision = "fa0dfdc10b5366ce365b7d9d1755a03e4e797bc5" version = "v1.6.15"

[[projects]] digest = "1:fb7b2a3e97946b9886007313497664ab2842c7b6473c33460e97157a38935f5d" name = "github.com/gobwas/glob" packages = [ ".", "compiler", "match", "syntax", "syntax/ast", "syntax/lexer", "util/runes", "util/strings", ] pruneopts = "NT" revision = "5ccd90ef52e1e632236f7326478d4faa74f99438" version = "v0.2.3"

[[projects]] digest = "1:932970e69f16e127aa0653b8263ae588cd127fa53273e19ba44332902c9826f2" name = "github.com/gogo/protobuf" packages = [ "proto", "sortkeys", ] pruneopts = "NT" revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7" version = "v1.2.0"

[[projects]] branch = "master" digest = "1:e2b86e41f3d669fc36b50d31d32d22c8ac656c75aa5ea89717ce7177e134ff2a" name = "github.com/golang/glog" packages = ["."] pruneopts = "NT" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"

[[projects]] branch = "master" digest = "1:20b774dcfdf0fff3148432beb828c52404f3eb3d70b7ce71ae0356ed6cbc2bae" name = "github.com/golang/groupcache" packages = ["lru"] pruneopts = "NT" revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b"

[[projects]] digest = "1:d7cb4458ea8782e6efacd8f4940796ec559c90833509c436f40c4085b98156dd" name = "github.com/golang/protobuf" packages = [ "proto", "ptypes", "ptypes/any", "ptypes/duration", "ptypes/timestamp", ] pruneopts = "NT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0"

[[projects]] branch = "master" digest = "1:05f95ffdfcf651bdb0f05b40b69e7f5663047f8da75c72d58728acb59b5cc107" name = "github.com/google/btree" packages = ["."] pruneopts = "NT" revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"

[[projects]] branch = "master" digest = "1:52c5834e2bebac9030c97cc0798ac11c3aa8a39f098aeb419f142533da6cd3cc" name = "github.com/google/gofuzz" packages = ["."] pruneopts = "NT" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"

[[projects]] digest = "1:56a1f3949ebb7fa22fa6b4e4ac0fe0f77cc4faee5b57413e6fa9199a8458faf1" name = "github.com/google/uuid" packages = ["."] pruneopts = "NT" revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" version = "v1.1.0"

[[projects]] digest = "1:289332c13b80edfefc88397cce5266c16845dcf204fa2f6ac7e464ee4c7f6e96" name = "github.com/googleapis/gnostic" packages = [ "OpenAPIv2", "compiler", "extensions", ] pruneopts = "NT" revision = "7c663266750e7d82587642f65e60bc4083f1f84e" version = "v0.2.0"

[[projects]] branch = "master" digest = "1:bb7bd892abcb75ef819ce2efab9d54d22b7e38dc05ffac55428bb0578b52912b" name = "github.com/gregjones/httpcache" packages = [ ".", "diskcache", ] pruneopts = "NT" revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"

[[projects]] digest = "1:b42cde0e1f3c816dd57f57f7bbcf05ca40263ad96f168714c130c611fc0856a6" name = "github.com/hashicorp/golang-lru" packages = [ ".", "simplelru", ] pruneopts = "NT" revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" version = "v0.5.0"

[[projects]] digest = "1:aaa38889f11896ee3644d77e17dc7764cc47f5f3d3b488268df2af2b52541c5f" name = "github.com/imdario/mergo" packages = ["."] pruneopts = "NT" revision = "7c29201646fa3de8506f701213473dd407f19646" version = "v0.3.7"

[[projects]] digest = "1:406338ad39ab2e37b7f4452906442a3dbf0eb3379dd1f06aafb5c07e769a5fbb" name = "github.com/inconshreveable/mousetrap" packages = ["."] pruneopts = "NT" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" version = "v1.0"

[[projects]] digest = "1:f5b9328966ccea0970b1d15075698eff0ddb3e75889560aad2e9f76b289b536a" name = "github.com/joho/godotenv" packages = ["."] pruneopts = "NT" revision = "23d116af351c84513e1946b527c88823e476be13" version = "v1.3.0"

[[projects]] digest = "1:1d39c063244ad17c4b18e8da1551163b6ffb52bd1640a49a8ec5c3b7bf4dbd5d" name = "github.com/json-iterator/go" packages = ["."] pruneopts = "NT" revision = "1624edc4454b8682399def8740d46db5e4362ba4" version = "v1.1.5"

[[projects]] digest = "1:4059c14e87a2de3a434430340521b5feece186c1469eff0834c29a63870de3ed" name = "github.com/konsorten/go-windows-terminal-sequences" packages = ["."] pruneopts = "NT" revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" version = "v1.0.1"

[[projects]] branch = "master" digest = "1:7d9fcac7f1228470c4ea0ee31cdfb662a758c44df691e39b3e76c11d3e12ba8f" name = "github.com/mailru/easyjson" packages = [ "buffer", "jlexer", "jwriter", ] pruneopts = "NT" revision = "60711f1a8329503b04e1c88535f419d0bb440bff"

[[projects]] digest = "1:56dbf15e091bf7926cb33a57cb6bdfc658fc6d3498d2f76f10a97ce7856f1fde" name = "github.com/markbates/inflect" packages = ["."] pruneopts = "NT" revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6" version = "v1.0.4"

[[projects]] digest = "1:ea1db000388d88b31db7531c83016bef0d6db0d908a07794bfc36aca16fbf935" name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] pruneopts = "NT" revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" version = "v1.0.1"

[[projects]] digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f" name = "github.com/modern-go/concurrent" packages = ["."] pruneopts = "NT" revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" version = "1.0.3"

[[projects]] digest = "1:c6aca19413b13dc59c220ad7430329e2ec454cc310bc6d8de2c7e2b93c18a0f6" name = "github.com/modern-go/reflect2" packages = ["."] pruneopts = "NT" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" version = "1.0.1"

[[projects]] branch = "master" digest = "1:cdcff8c4cec20c30c6cd57a2c34726bf2ca97c459f88ec7b4877d11b721d0b02" name = "github.com/operator-framework/operator-sdk" packages = [ "internal/util/fileutil", "internal/util/k8sutil", "internal/util/projutil", "internal/util/yamlutil", "pkg/k8sutil", "pkg/leader", "pkg/log/zap", "pkg/metrics", "pkg/scaffold", "pkg/scaffold/ansible", "pkg/scaffold/helm", "pkg/scaffold/input", "pkg/test", "pkg/test/e2eutil", "version", ] pruneopts = "NT" revision = "e9b48df1d85c0468145a52864962c8f72197985c"

[[projects]] digest = "1:93b1d84c5fa6d1ea52f4114c37714cddd84d5b78f151b62bb101128dd51399bf" name = "github.com/pborman/uuid" packages = ["."] pruneopts = "NT" revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" version = "v1.2"

[[projects]] branch = "master" digest = "1:bf2ac97824a7221eb16b096aecc1c390d4c8a4e49524386aaa2e2dd215cbfb31" name = "github.com/petar/GoLLRB" packages = ["llrb"] pruneopts = "NT" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"

[[projects]] digest = "1:e4e9e026b8e4c5630205cd0208efb491b40ad40552e57f7a646bb8a46896077b" name = "github.com/peterbourgon/diskv" packages = ["."] pruneopts = "NT" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1"

[[projects]] digest = "1:14715f705ff5dfe0ffd6571d7d201dd8e921030f8070321a79380d8ca4ec1a24" name = "github.com/pkg/errors" packages = ["."] pruneopts = "NT" revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" version = "v0.8.1"

[[projects]] digest = "1:ec2a29e3bd141038ae5c3d3a4f57db0c341fcc1d98055a607aedd683aed124ee" name = "github.com/prometheus/client_golang" packages = [ "prometheus", "prometheus/internal", "prometheus/promhttp", ] pruneopts = "NT" revision = "505eaef017263e299324067d40ca2c48f6a2cf50" version = "v0.9.2"

[[projects]] branch = "master" digest = "1:c2cc5049e927e2749c0d5163c9f8d924880d83e84befa732b9aad0b6be227bed" name = "github.com/prometheus/client_model" packages = ["go"] pruneopts = "NT" revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"

[[projects]] digest = "1:30261b5e263b5c4fb40571b53a41a99c96016c6b1b2c45c1cefd226fc3f6304b" name = "github.com/prometheus/common" packages = [ "expfmt", "internal/bitbucket.org/ww/goautoneg", "model", ] pruneopts = "NT" revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250" version = "v0.2.0"

[[projects]] branch = "master" digest = "1:0069c5bbd941d86f6b2e3fde6c9c701a74a7a14b5f570674235cd53ed7fa685f" name = "github.com/prometheus/procfs" packages = [ ".", "internal/util", "nfs", "xfs", ] pruneopts = "NT" revision = "f8d8b3f739bd91a7c0462cb55235ef63c79c9abc"

[[projects]] digest = "1:fcef1ce61da6f8f6f115154fb0e0e5b159fe11656839ba1e6061372711c013ee" name = "github.com/rogpeppe/go-internal" packages = [ "modfile", "module", "semver", ] pruneopts = "NT" revision = "1cf9852c553c5b7da2d5a4a091129a7822fed0c9" version = "v1.2.2"

[[projects]] digest = "1:1f84287a4ca2c8f729d8155ba4c45915f5854ebbd214e406070779753da68422" name = "github.com/sirupsen/logrus" packages = ["."] pruneopts = "NT" revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" version = "v1.3.0"

[[projects]] digest = "1:1bc08ec221c4fb25e6f2c019b23fe989fb44573c696983d8e403a3b76cc378e1" name = "github.com/spf13/afero" packages = [ ".", "mem", ] pruneopts = "NT" revision = "f4711e4db9e9a1d3887343acb72b2bbfc2f686f5" version = "v1.2.1"

[[projects]] digest = "1:234b95cdbb31612ff4f97e0ac69abdede0c60f5f84e5d3f40123859f77d8bc2c" name = "github.com/spf13/cobra" packages = ["."] pruneopts = "NT" revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" version = "v0.0.3"

[[projects]] digest = "1:9d8420bbf131d1618bde6530af37c3799340d3762cc47210c1d9532a4c3a2779" name = "github.com/spf13/pflag" packages = ["."] pruneopts = "NT" revision = "298182f68c66c05229eb03ac171abe6e309ee79a" version = "v1.0.3"

[[projects]] digest = "1:22f696cee54865fb8e9ff91df7b633f6b8f22037a8015253c6b6a71ca82219c7" name = "go.uber.org/atomic" packages = ["."] pruneopts = "NT" revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" version = "v1.3.2"

[[projects]] digest = "1:58ca93bdf81bac106ded02226b5395a0595d5346cdc4caa8d9c1f3a5f8f9976e" name = "go.uber.org/multierr" packages = ["."] pruneopts = "NT" revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" version = "v1.1.0"

[[projects]] digest = "1:572fa4496563920f3e3107a2294cf2621d6cc4ffd03403fb6397b1bab9fa082a" name = "go.uber.org/zap" packages = [ ".", "buffer", "internal/bufferpool", "internal/color", "internal/exit", "zapcore", ] pruneopts = "NT" revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" version = "v1.9.1"

[[projects]] branch = "master" digest = "1:ac2aca57313c6183eee8ae3bb09bafb99e8249652aaa233aad5739b830636646" name = "golang.org/x/crypto" packages = ["ssh/terminal"] pruneopts = "NT" revision = "74369b46fc6756741c016591724fd1cb8e26845f"

[[projects]] branch = "master" digest = "1:922c0bb9dc59af35400f6725ed08582f99f710ffc1a1075e8914c73515bb269e" name = "golang.org/x/net" packages = [ "context", "context/ctxhttp", "http/httpguts", "http2", "http2/hpack", "idna", ] pruneopts = "NT" revision = "3a22650c66bd7f4fb6d1e8072ffd7b75c8a27898"

[[projects]] branch = "master" digest = "1:495ec760c8fb3ce35f5126abf6e9f33a2069f9c7ad67006d84e7352cbb51537c" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", "jwt", ] pruneopts = "NT" revision = "3e8b2be1363542a95c52ea0796d4a40dacfb5b95"

[[projects]] branch = "master" digest = "1:cb28bbe2e8a756f9f8da0784e2b47df60904be7895212412081730a5a9a3407b" name = "golang.org/x/sys" packages = [ "unix", "windows", ] pruneopts = "NT" revision = "d0b11bdaac8adb652bff00e49bcacf992835621a"

[[projects]] digest = "1:8c74f97396ed63cc2ef04ebb5fc37bb032871b8fd890a25991ed40974b00cd2a" name = "golang.org/x/text" packages = [ "collate", "collate/build", "internal/colltab", "internal/gen", "internal/tag", "internal/triegen", "internal/ucd", "language", "secure/bidirule", "transform", "unicode/bidi", "unicode/cldr", "unicode/norm", "unicode/rangetable", "width", ] pruneopts = "NT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0"

[[projects]] branch = "master" digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90" name = "golang.org/x/time" packages = ["rate"] pruneopts = "NT" revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd"

[[projects]] branch = "master" digest = "1:d10793fdb379e3e2330bec1c0fc2442f345db036e321e4d0b4952622a7374a0f" name = "golang.org/x/tools" packages = [ "go/ast/astutil", "go/gcexportdata", "go/internal/cgo", "go/internal/gcimporter", "go/internal/packagesdriver", "go/packages", "go/types/typeutil", "imports", "internal/fastwalk", "internal/gopathwalk", "internal/module", "internal/semver", ] pruneopts = "NT" revision = "8dcb7bc8c7fe0a895995c76c721cef79419ac98a"

[[projects]] digest = "1:902ffa11f1d8c19c12b05cabffe69e1a16608ad03a8899ebcb9c6bde295660ae" name = "google.golang.org/appengine" packages = [ ".", "internal", "internal/app_identity", "internal/base", "internal/datastore", "internal/log", "internal/modules", "internal/remote_api", "internal/urlfetch", "urlfetch", ] pruneopts = "NT" revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" version = "v1.4.0"

[[projects]] digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" name = "gopkg.in/inf.v0" packages = ["."] pruneopts = "NT" revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" version = "v0.9.1"

[[projects]] digest = "1:18108594151654e9e696b27b181b953f9a90b16bf14d253dd1b397b025a1487f" name = "gopkg.in/yaml.v2" packages = ["."] pruneopts = "NT" revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" version = "v2.2.2"

[[projects]] digest = "1:6fa82ea248029bbbdddade20c06ab177ff6e485e5e45e48b045707415b7efd34" name = "k8s.io/api" packages = [ "admission/v1beta1", "admissionregistration/v1alpha1", "admissionregistration/v1beta1", "apps/v1", "apps/v1beta1", "apps/v1beta2", "auditregistration/v1alpha1", "authentication/v1", "authentication/v1beta1", "authorization/v1", "authorization/v1beta1", "autoscaling/v1", "autoscaling/v2beta1", "autoscaling/v2beta2", "batch/v1", "batch/v1beta1", "batch/v2alpha1", "certificates/v1beta1", "coordination/v1beta1", "core/v1", "events/v1beta1", "extensions/v1beta1", "networking/v1", "policy/v1beta1", "rbac/v1", "rbac/v1alpha1", "rbac/v1beta1", "scheduling/v1alpha1", "scheduling/v1beta1", "settings/v1alpha1", "storage/v1", "storage/v1alpha1", "storage/v1beta1", ] pruneopts = "NT" revision = "05914d821849570fba9eacfb29466f2d8d3cd229"

[[projects]] digest = "1:c6f23048e162e65d586c809fd02e263e180ad157f110df17437c22517bb59a4b" name = "k8s.io/apiextensions-apiserver" packages = [ "pkg/apis/apiextensions", "pkg/apis/apiextensions/v1beta1", "pkg/client/clientset/clientset/scheme", ] pruneopts = "NT" revision = "0fe22c71c47604641d9aa352c785b7912c200562"

[[projects]] digest = "1:15b5c41ff6faa4d0400557d4112d6337e1abc961c65513d44fce7922e32c9ca7" name = "k8s.io/apimachinery" packages = [ "pkg/api/errors", "pkg/api/meta", "pkg/api/resource", "pkg/apis/meta/internalversion", "pkg/apis/meta/v1", "pkg/apis/meta/v1/unstructured", "pkg/apis/meta/v1beta1", "pkg/conversion", "pkg/conversion/queryparams", "pkg/fields", "pkg/labels", "pkg/runtime", "pkg/runtime/schema", "pkg/runtime/serializer", "pkg/runtime/serializer/json", "pkg/runtime/serializer/protobuf", "pkg/runtime/serializer/recognizer", "pkg/runtime/serializer/streaming", "pkg/runtime/serializer/versioning", "pkg/selection", "pkg/types", "pkg/util/cache", "pkg/util/clock", "pkg/util/diff", "pkg/util/errors", "pkg/util/framer", "pkg/util/intstr", "pkg/util/json", "pkg/util/mergepatch", "pkg/util/naming", "pkg/util/net", "pkg/util/runtime", "pkg/util/sets", "pkg/util/strategicpatch", "pkg/util/uuid", "pkg/util/validation", "pkg/util/validation/field", "pkg/util/wait", "pkg/util/yaml", "pkg/version", "pkg/watch", "third_party/forked/golang/json", "third_party/forked/golang/reflect", ] pruneopts = "NT" revision = "2b1284ed4c93a43499e781493253e2ac5959c4fd"

[[projects]] digest = "1:c904a3d70131b33df36e4e51b574226b82308fc1ea66964aa21095a95d453fc9" name = "k8s.io/client-go" packages = [ "discovery", "discovery/cached", "dynamic", "kubernetes", "kubernetes/scheme", "kubernetes/typed/admissionregistration/v1alpha1", "kubernetes/typed/admissionregistration/v1beta1", "kubernetes/typed/apps/v1", "kubernetes/typed/apps/v1beta1", "kubernetes/typed/apps/v1beta2", "kubernetes/typed/auditregistration/v1alpha1", "kubernetes/typed/authentication/v1", "kubernetes/typed/authentication/v1beta1", "kubernetes/typed/authorization/v1", "kubernetes/typed/authorization/v1beta1", "kubernetes/typed/autoscaling/v1", "kubernetes/typed/autoscaling/v2beta1", "kubernetes/typed/autoscaling/v2beta2", "kubernetes/typed/batch/v1", "kubernetes/typed/batch/v1beta1", "kubernetes/typed/batch/v2alpha1", "kubernetes/typed/certificates/v1beta1", "kubernetes/typed/coordination/v1beta1", "kubernetes/typed/core/v1", "kubernetes/typed/events/v1beta1", "kubernetes/typed/extensions/v1beta1", "kubernetes/typed/networking/v1", "kubernetes/typed/policy/v1beta1", "kubernetes/typed/rbac/v1", "kubernetes/typed/rbac/v1alpha1", "kubernetes/typed/rbac/v1beta1", "kubernetes/typed/scheduling/v1alpha1", "kubernetes/typed/scheduling/v1beta1", "kubernetes/typed/settings/v1alpha1", "kubernetes/typed/storage/v1", "kubernetes/typed/storage/v1alpha1", "kubernetes/typed/storage/v1beta1", "pkg/apis/clientauthentication", "pkg/apis/clientauthentication/v1alpha1", "pkg/apis/clientauthentication/v1beta1", "pkg/version", "plugin/pkg/client/auth/exec", "plugin/pkg/client/auth/gcp", "rest", "rest/watch", "restmapper", "third_party/forked/golang/template", "tools/auth", "tools/cache", "tools/clientcmd", "tools/clientcmd/api", "tools/clientcmd/api/latest", "tools/clientcmd/api/v1", "tools/leaderelection", "tools/leaderelection/resourcelock", "tools/metrics", "tools/pager", "tools/record", "tools/reference", "transport", "util/buffer", "util/cert", "util/connrotation", "util/flowcontrol", "util/homedir", "util/integer", "util/jsonpath", "util/retry", "util/workqueue", ] pruneopts = "NT" revision = "8d9ed539ba3134352c586810e749e58df4e94e4f"

[[projects]] digest = "1:dc1ae99dcab96913d81ae970b1f7a7411a54199b14bfb17a7e86f9a56979c720" name = "k8s.io/code-generator" packages = [ "cmd/client-gen", "cmd/client-gen/args", "cmd/client-gen/generators", "cmd/client-gen/generators/fake", "cmd/client-gen/generators/scheme", "cmd/client-gen/generators/util", "cmd/client-gen/path", "cmd/client-gen/types", "cmd/conversion-gen", "cmd/conversion-gen/args", "cmd/conversion-gen/generators", "cmd/deepcopy-gen", "cmd/deepcopy-gen/args", "cmd/defaulter-gen", "cmd/defaulter-gen/args", "cmd/informer-gen", "cmd/informer-gen/args", "cmd/informer-gen/generators", "cmd/lister-gen", "cmd/lister-gen/args", "cmd/lister-gen/generators", "pkg/util", ] pruneopts = "T" revision = "c2090bec4d9b1fb25de3812f868accc2bc9ecbae"

[[projects]] branch = "master" digest = "1:2b9071c93303f1196cfe959c7f7f69ed1e4a5180f240a259536c5886f79f86d4" name = "k8s.io/gengo" packages = [ "args", "examples/deepcopy-gen/generators", "examples/defaulter-gen/generators", "examples/set-gen/sets", "generator", "namer", "parser", "types", ] pruneopts = "T" revision = "0689ccc1d7d65d9dd1bedcc3b0b1ed7df91ba266"

[[projects]] digest = "1:0c99d649552f4a6da222ce2fe47d345f903f8f8bd4f52efc15afe63a3303f489" name = "k8s.io/helm" packages = [ "pkg/chartutil", "pkg/ignore", "pkg/proto/hapi/chart", "pkg/proto/hapi/version", "pkg/sympath", "pkg/version", ] pruneopts = "NT" revision = "d325d2a9c179b33af1a024cdb5a4472b6288016a" version = "v2.12.0"

[[projects]] digest = "1:29f93bb84d907a2c035e729e19d66fe52165d8c905cb3ef1920140d76ae6afaf" name = "k8s.io/klog" packages = ["."] pruneopts = "NT" revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0" version = "v0.2.0"

[[projects]] digest = "1:c48a795cd7048bb1888273bc604b6e69b22f9b8089c3df65f77cc527757b515c" name = "k8s.io/kube-openapi" packages = [ "cmd/openapi-gen", "cmd/openapi-gen/args", "pkg/common", "pkg/generators", "pkg/generators/rules", "pkg/util/proto", "pkg/util/sets", ] pruneopts = "NT" revision = "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803"

[[projects]] digest = "1:06035489efbd51ccface65fc878ceeb849aba05b2f9443c8993f363fc96e80ac" name = "sigs.k8s.io/controller-runtime" packages = [ "pkg/cache", "pkg/cache/internal", "pkg/client", "pkg/client/apiutil", "pkg/client/config", "pkg/controller", "pkg/controller/controllerutil", "pkg/event", "pkg/handler", "pkg/internal/controller", "pkg/internal/controller/metrics", "pkg/internal/recorder", "pkg/leaderelection", "pkg/manager", "pkg/metrics", "pkg/patch", "pkg/predicate", "pkg/reconcile", "pkg/recorder", "pkg/runtime/inject", "pkg/runtime/log", "pkg/runtime/scheme", "pkg/runtime/signals", "pkg/source", "pkg/source/internal", "pkg/webhook/admission", "pkg/webhook/admission/types", "pkg/webhook/internal/metrics", "pkg/webhook/types", ] pruneopts = "NT" revision = "12d98582e72927b6cd0123e2b4e819f9341ce62c" version = "v0.1.10"

[[projects]] digest = "1:0a14ea9a2647d064bb9d48b2de78306e74b196681efd7b654eb0b518d90c2e8d" name = "sigs.k8s.io/controller-tools" packages = [ "pkg/crd/generator", "pkg/crd/util", "pkg/internal/codegen", "pkg/internal/codegen/parse", "pkg/internal/general", "pkg/util", ] pruneopts = "NT" revision = "950a0e88e4effb864253b3c7504b326cc83b9d11" version = "v0.1.8"

[[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" name = "sigs.k8s.io/yaml" packages = ["."] pruneopts = "NT" revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480" version = "v1.1.0"

[solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = [ "github.com/go-openapi/spec", "github.com/operator-framework/operator-sdk/pkg/k8sutil", "github.com/operator-framework/operator-sdk/pkg/leader", "github.com/operator-framework/operator-sdk/pkg/log/zap", "github.com/operator-framework/operator-sdk/pkg/metrics", "github.com/operator-framework/operator-sdk/pkg/test", "github.com/operator-framework/operator-sdk/pkg/test/e2eutil", "github.com/operator-framework/operator-sdk/version", "github.com/spf13/pflag", "k8s.io/api/core/v1", "k8s.io/apimachinery/pkg/api/errors", "k8s.io/apimachinery/pkg/apis/meta/v1", "k8s.io/apimachinery/pkg/runtime", "k8s.io/apimachinery/pkg/runtime/schema", "k8s.io/apimachinery/pkg/types", "k8s.io/client-go/plugin/pkg/client/auth/gcp", "k8s.io/code-generator/cmd/client-gen", "k8s.io/code-generator/cmd/conversion-gen", "k8s.io/code-generator/cmd/deepcopy-gen", "k8s.io/code-generator/cmd/defaulter-gen", "k8s.io/code-generator/cmd/informer-gen", "k8s.io/code-generator/cmd/lister-gen", "k8s.io/gengo/args", "k8s.io/kube-openapi/cmd/openapi-gen", "k8s.io/kube-openapi/pkg/common", "sigs.k8s.io/controller-runtime/pkg/client", "sigs.k8s.io/controller-runtime/pkg/client/config", "sigs.k8s.io/controller-runtime/pkg/controller", "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil", "sigs.k8s.io/controller-runtime/pkg/handler", "sigs.k8s.io/controller-runtime/pkg/manager", "sigs.k8s.io/controller-runtime/pkg/reconcile", "sigs.k8s.io/controller-runtime/pkg/runtime/log", "sigs.k8s.io/controller-runtime/pkg/runtime/scheme", "sigs.k8s.io/controller-runtime/pkg/runtime/signals", "sigs.k8s.io/controller-runtime/pkg/source", "sigs.k8s.io/controller-tools/pkg/crd/generator", ] solver-name = "gps-cdcl" solver-version = 1

kubectl version

Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.3", GitCommit:"721bfa751924da8d1680787490c54b9179b1fed0", GitTreeState:"clean", BuildDate:"2019-02-04T04:48:03Z", GoVersion:"go1.11.5", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.3", GitCommit:"721bfa751924da8d1680787490c54b9179b1fed0", GitTreeState:"clean", BuildDate:"2019-02-01T20:00:57Z", GoVersion:"go1.11.5", Compiler:"gc", Platform:"linux/amd64"}
AlexNPavel commented 5 years ago

Hello. Since the operator is running locally instead of in the cluster, WaitForDeployment will not be able to successfully complete. We have another function to solve this problem: WaitForOperatorDeployment. This function will act the same as WaitForDeployment unless the tests are being run with --up-local, in which case it will finish immediately (as the operator should be running locally).

This function is mentioned in the documentation: https://github.com/operator-framework/operator-sdk/blob/master/doc/test-framework/writing-e2e-tests.md#3-setup-the-test-context-and-resources

aaronmcohen commented 5 years ago

@AlexNPavel Thank you!

aaronmcohen commented 5 years ago

@AlexNPavel I might have spoken too soon. After adding WaitForOperatorDeployment I thought the test was successful but it turns out it was finishing immediately as you mentioned.

The problem is the operator is running locally but it is trying to pull the operator docker image instead. Thus it is failing.

Updated test/e2e/sample_test.go

package e2e

import (
    "context"
    "sample-operator/pkg/apis"
    "sample-operator/pkg/apis/example/v1"
    "testing"
    "time"

    "github.com/operator-framework/operator-sdk/pkg/test"
    "github.com/operator-framework/operator-sdk/pkg/test/e2eutil"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
    retryInterval        = time.Second * 5
    timeout              = time.Second * 120
    cleanupRetryInterval = time.Second * 1
    cleanupTimeout       = time.Second * 5
)

func TestSimple(t *testing.T) {

    sampleList := &v1.SampleList{
        TypeMeta: metav1.TypeMeta{
            Kind:       "Sample",
            APIVersion: "example.com/v1",
        },
    }
    crdError := test.AddToFrameworkScheme(apis.AddToScheme, sampleList)
    if crdError != nil {
        t.Fatalf("failed to add custom resource scheme to framework: %v", crdError)
    }
    ctx := test.NewTestCtx(t)
    defer ctx.Cleanup()
    crError := ctx.InitializeClusterResources(&test.CleanupOptions{TestContext: ctx, Timeout: cleanupTimeout, RetryInterval: cleanupRetryInterval})
    if crError != nil {
        t.Fatalf("failed to initialize cluster resources: %v", crError)
    }
    t.Log("Initialized cluster resources")
    namespace, err := ctx.GetNamespace()
    if err != nil {
        t.Fatal(err)
    }
    // get global framework variables
    f := test.Global
    // wait for operator to be ready
    err = e2eutil.WaitForOperatorDeployment(t, f.KubeClient, namespace, "sample-operator", 1, retryInterval, timeout)
    if err != nil {
        t.Fatal(err)
    }
    time.Sleep(30000)
    sample := &v1.Sample{
        TypeMeta: metav1.TypeMeta{
            Kind:       "Sample",
            APIVersion: "example.com/v1",
        },
        ObjectMeta: metav1.ObjectMeta{
            Name:      "simple-test",
            Namespace: namespace,
        },
        Spec: v1.SampleSpec{},
    }
    err = f.Client.Create(context.TODO(), sample, &test.CleanupOptions{TestContext: ctx, Timeout: timeout, RetryInterval: retryInterval})

    if err != nil {
        t.Fatal(err)
    }
    err = e2eutil.WaitForDeployment(t, f.KubeClient, namespace, "simple-test", 1, time.Second*5, time.Second*30)
    if err != nil {
        t.Fatal(err)
    }
}

kubectl describe pod sample-operator-c4b59bc6d-gjppn

Name:               sample-operator-c4b59bc6d-gjppn
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               minikube/10.0.2.15
Start Time:         Mon, 18 Feb 2019 16:46:05 -0500
Labels:             name=sample-operator
                    pod-template-hash=c4b59bc6d
Annotations:        <none>
Status:             Pending
IP:                 172.17.0.6
Controlled By:      ReplicaSet/sample-operator-c4b59bc6d
Containers:
  sample-operator:
    Container ID:  
    Image:         sample-operator:0.0.1
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Command:
      sample-operator
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    Restart Count:  0
    Environment:
      WATCH_NAMESPACE:  default (v1:metadata.namespace)
      POD_NAME:         sample-operator-c4b59bc6d-gjppn (v1:metadata.name)
      OPERATOR_NAME:    sample-operator
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from sample-operator-token-pwhcg (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  sample-operator-token-pwhcg:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  sample-operator-token-pwhcg
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  20s               default-scheduler  Successfully assigned default/sample-operator-c4b59bc6d-gjppn to minikube
  Normal   BackOff    18s               kubelet, minikube  Back-off pulling image "sample-operator:0.0.1"
  Warning  Failed     18s               kubelet, minikube  Error: ImagePullBackOff
  Normal   Pulling    5s (x2 over 19s)  kubelet, minikube  pulling image "sample-operator:0.0.1"
  Warning  Failed     5s (x2 over 19s)  kubelet, minikube  Failed to pull image "sample-operator:0.0.1": rpc error: code = Unknown desc = Error response from daemon: pull access denied for sample-operator, repository does not exist or may require 'docker login'
  Warning  Failed     5s (x2 over 19s)  kubelet, minikube  Error: ErrImagePull
AlexNPavel commented 5 years ago

Oh, that shouldn't matter. That seems to be a bug I accidentally introduced with this commit: https://github.com/operator-framework/operator-sdk/commit/a491ff9fc42df57cff6a33f037e6fc137c8f9536#diff-b6a250dfb7ca3e246979976a0467cf97

I'll make a PR to fix that (namespaced resources should not be created in the cluster if running in up local mode). However, the test should be ignoring the fact that the operator is failing to start, and the local operator should be handling the CRs correctly.

AlexNPavel commented 5 years ago

Actually, I found another bug that was created more recently. I'll make a PR soon and update this once that's open.

AlexNPavel commented 5 years ago

@aaronmcohen This issue should be resolved with PR #1109. Thanks for finding this bug

aaronmcohen commented 5 years ago

@AlexNPavel That seemed to have solved the issue. It is no longer trying to deploy the operator into the cluster. However there seems to still an issue showing up in the log operator stdout: unknown shorthand flag: 'o' in -o\n"

Here is the full output:

INFO[0000] Testing operator locally.                    
?       sample-operator/cmd/manager [no test files]
?       sample-operator/pkg/apis    [no test files]
?       sample-operator/pkg/apis/example/v1 [no test files]
?       sample-operator/pkg/controller  [no test files]
?       sample-operator/pkg/controller/sample   [no test files]
time="2019-02-19T10:17:18-05:00" level=info msg="Started local operator"
--- FAIL: TestSimple (30.10s)
    simple_test.go:41: Initialized cluster resources
    wait_util.go:45: Operator is running locally; skip waitForDeployment
    client.go:57: resource type Sample with namespace/name (default/simple-test) created
    wait_util.go:52: Waiting for availability of simple-test deployment
    wait_util.go:52: Waiting for availability of simple-test deployment
    wait_util.go:52: Waiting for availability of simple-test deployment
    wait_util.go:52: Waiting for availability of simple-test deployment
    wait_util.go:52: Waiting for availability of simple-test deployment
    wait_util.go:52: Waiting for availability of simple-test deployment
    wait_util.go:52: Waiting for availability of simple-test deployment
    simple_test.go:71: timed out waiting for the condition
    client.go:75: resource type Sample with namespace/name (default/simple-test) successfully deleted
FAIL
time="2019-02-19T10:17:48-05:00" level=info msg="Local operator stdout: unknown shorthand flag: 'o' in -o\n"
time="2019-02-19T10:17:48-05:00" level=info msg="Local operator stderr: unknown shorthand flag: 'o' in -o\nUsage of build/_output/bin/sample-operator-local:\n      --kubeconfig string     Paths to a kubeconfig. Only required if out-of-cluster.\n      --master string         The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.\n      --zap-devel             Enable zap development mode (changes defaults to console encoder, debug log level, and disables sampling)\n      --zap-encoder encoder   Zap log encoding ('json' or 'console')\n      --zap-level level       Zap log level (one of 'debug', 'info', 'error') (default info)\n      --zap-sample sample     Enable zap log sampling\n"
FAIL    sample-operator/test/e2d    31.283s
?       sample-operator/version [no test files]
Error: failed to exec []string{"go", "test", "./...", "-namespacedMan", "/var/folders/l2/ntz6vdlj2fqfjn4mt9brg7c80000gn/T/empty.yaml630456813", "-globalMan", "/var/folders/l2/ntz6vdlj2fqfjn4mt9brg7c80000gn/T/global-manifest.yaml514829416", "-root", "/Users/aaroncohen/go/src/sample-operator", "-singleNamespace", "-parallel=1", "-localOperator"}: exit status 1
Usage:
  operator-sdk test local <path to tests directory> [flags]

Flags:
      --debug                        Enable debug-level logging
      --global-manifest string       Path to manifest for Global resources (e.g. CRD manifests)
      --go-test-flags string         Additional flags to pass to go test
  -h, --help                         help for local
      --image string                 Use a different operator image from the one specified in the namespaced manifest
      --kubeconfig string            Kubeconfig path
      --molecule-test-flags string   Additional flags to pass to molecule test
      --namespace string             If non-empty, single namespace to run tests in
      --namespaced-manifest string   Path to manifest for per-test, namespaced resources (e.g. RBAC and Operator manifest)
      --no-setup                     Disable test resource creation
      --up-local                     Enable running operator locally with go run instead of as an image in the cluster

shell returned 1

The code that is running:

package e2e

import (
    "context"
    "sample-operator/pkg/apis"
    "sample-operator/pkg/apis/example/v1"
    "testing"
    "time"

    "github.com/operator-framework/operator-sdk/pkg/test"
    "github.com/operator-framework/operator-sdk/pkg/test/e2eutil"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
    retryInterval        = time.Second * 5
    timeout              = time.Second * 120
    cleanupRetryInterval = time.Second * 1
    cleanupTimeout       = time.Second * 5
)

func TestSimple(t *testing.T) {

    sampleList := &v1.SampleList{
        TypeMeta: metav1.TypeMeta{
            Kind:       "Sample",
            APIVersion: "example.com/v1",
        },
    }
    crdError := test.AddToFrameworkScheme(apis.AddToScheme, sampleList)
    if crdError != nil {
        t.Fatalf("failed to add custom resource scheme to framework: %v", crdError)
    }
    ctx := test.NewTestCtx(t)
    defer ctx.Cleanup()
    crError := ctx.InitializeClusterResources(&test.CleanupOptions{TestContext: ctx, Timeout: cleanupTimeout, RetryInterval: cleanupRetryInterval})
    if crError != nil {
        t.Fatalf("failed to initialize cluster resources: %v", crError)
    }
    t.Log("Initialized cluster resources")
    namespace, err := ctx.GetNamespace()
    if err != nil {
        t.Fatal(err)
    }
    // get global framework variables
    f := test.Global
    // wait for operator to be ready
    err = e2eutil.WaitForOperatorDeployment(t, f.KubeClient, namespace, "sample-operator", 1, retryInterval, timeout)
    if err != nil {
        t.Fatal(err)
    }
    sample := &v1.Sample{
        TypeMeta: metav1.TypeMeta{
            Kind:       "Sample",
            APIVersion: "example.com/v1",
        },
        ObjectMeta: metav1.ObjectMeta{
            Name:      "simple-test",
            Namespace: namespace,
        },
        Spec: v1.SampleSpec{},
    }
    err = f.Client.Create(context.TODO(), sample, &test.CleanupOptions{TestContext: ctx, Timeout: timeout, RetryInterval: retryInterval})

    if err != nil {
        t.Fatal(err)
    }
    err = e2eutil.WaitForDeployment(t, f.KubeClient, namespace, "simple-test", 1, time.Second*5, time.Second*30)
    if err != nil {
        t.Fatal(err)
    }
}
aaronmcohen commented 5 years ago

Nevermind the previous post. Needed to run dev ensure --update