diff --git a/CHANGELOG.md b/CHANGELOG.md index 5529675252..d6b6dbbc23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - The Helm operator now uses the CR name for the release name for newly created CRs. Existing CRs will continue to use their existing UID-based release name. When a release name collision occurs (when CRs of different types share the same name), the second CR will fail to install with an error about a duplicate name. ([#1818](https://github.com/operator-framework/operator-sdk/pull/1818)) - Commands [`olm uninstall`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#uninstall) and [`olm status`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#status) no longer use a `--version` flag to specify OLM version. This information is now retrieved from the running cluster. ([#1634](https://github.com/operator-framework/operator-sdk/pull/1634)) +- CRD manifest `spec.version` is still supported, but users will see a warning message if `spec.versions` is not present and an error if `spec.versions` is populated but the version in `spec.version` is not in `spec.versions`. ### Breaking changes diff --git a/doc/operator-scope.md b/doc/operator-scope.md index bbce4626e4..2c8b64fd1e 100644 --- a/doc/operator-scope.md +++ b/doc/operator-scope.md @@ -26,7 +26,7 @@ For each CRD that needs to be cluster-scoped, update its manifest to be cluster- * `deploy/crds/__crd.yaml` * Set `spec.scope: Cluster` -To ensure that the CRD is always generated with `scope: Cluster`, add the tag `// +genclient:nonNamespaced` above the CRD's Go type defintion in `pkg/apis///_types.go`. +To ensure that the CRD is always generated with `scope: Cluster`, add the tag `// +kubebuilder:resource:path=,scope=Cluster`, or if already present replace `scope={Namespaced -> Cluster}`, above the CRD's Go type defintion in `pkg/apis///_types.go`. The `` element must be the lower-case plural of the CRD's Kind, `spec.names.plural`. ### Example for cluster scoped operator @@ -92,7 +92,7 @@ With the above changes the specified manifests should look as follows: // Memcached is the Schema for the memcacheds API // +k8s:openapi-gen=true - // +genclient:nonNamespaced + // +kubebuilder:resource:path=memcacheds,scope=Cluster type Memcached struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/go.mod b/go.mod index 4e5cfa45b3..a66384a72c 100644 --- a/go.mod +++ b/go.mod @@ -90,7 +90,7 @@ require ( k8s.io/kube-state-metrics v1.6.0 k8s.io/kubernetes v1.14.2 sigs.k8s.io/controller-runtime v0.2.0-beta.3 - sigs.k8s.io/controller-tools v0.0.0-20190411181648-9d55346c2bde + sigs.k8s.io/controller-tools v0.2.0 sigs.k8s.io/kustomize v2.0.3+incompatible // indirect vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787 // indirect ) @@ -115,5 +115,4 @@ replace ( k8s.io/helm => k8s.io/helm v2.14.1+incompatible k8s.io/kube-state-metrics => k8s.io/kube-state-metrics v1.6.0 sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.2.0-beta.3 - sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde ) diff --git a/go.sum b/go.sum index 266d625812..c443729b42 100644 --- a/go.sum +++ b/go.sum @@ -106,6 +106,7 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwC github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -155,9 +156,10 @@ github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.5 h1:xpKq9ap8MbYfhuPCF0dBH854Gp9CxZjr/IocxELFflo= +github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= @@ -193,6 +195,8 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -273,7 +277,6 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -293,6 +296,8 @@ github.com/martinlindhe/base36 v0.0.0-20180729042928-5cda0030da17 h1:p63hV5GaWH3 github.com/martinlindhe/base36 v0.0.0-20180729042928-5cda0030da17/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8= github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a h1:+J2gw7Bw77w/fbK7wnNJJDKmw1IbWft2Ul5BzrG1Qm8= github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -378,7 +383,6 @@ github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6y github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rubenv/sql-migrate v0.0.0-20190618074426-f4d34eae5a5c h1:LCELEbde3/GT141OpHRs+jJZrI1tI3ayVd4VqW7Ui2U= @@ -479,12 +483,12 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20170412232759-a6bd8cefa181/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -512,17 +516,20 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190318195719-6c81ef8f67ca/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438 h1:khxRGsvPk4n2y8I/mLLjp7e5dMTJmH75wvqS6nMwUtY= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -535,11 +542,11 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181207222222-4c874b978acb/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190213015956-f7e1b50d2251/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190320215829-36c10c0a621f/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190501045030-23463209683d/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= gomodules.xyz/jsonpatch/v2 v2.0.0 h1:lHNQverf0+Gm1TbSbVIDWVXOhZ2FpZopxRqpr2uIjs4= @@ -636,8 +643,8 @@ k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5 h1:VBM/0P5TWxwk+Nw6Z+lAw3DKgO76g k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/controller-runtime v0.2.0-beta.3 h1:K3dddu6/pOVORH2dBOnEbXif6R80oSDa4y/t1jhoh8s= sigs.k8s.io/controller-runtime v0.2.0-beta.3/go.mod h1:HweyYKQ8fBuzdu2bdaeBJvsFgAi/OqBBnrVGXcqKhME= -sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde h1:ZkaHf5rNYzIB6CB82keKMQNv7xxkqT0ylOBdfJPfi+k= -sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde/go.mod h1:ATWLRP3WGxuAN9HcT2LaKHReXIH+EZGzRuMHuxjXfhQ= +sigs.k8s.io/controller-tools v0.2.0 h1:AmQ/0JKBJAjyAiPAkrAf9QW06jkx2lc5hpxMjamsFpw= +sigs.k8s.io/controller-tools v0.2.0/go.mod h1:8t/X+FVWvk6TaBcsa+UKUBbn7GMtvyBKX30SGl4em6Y= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff v0.0.0-20190426204423-ea680f03cc65/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= diff --git a/internal/pkg/scaffold/ansible/go_mod.go b/internal/pkg/scaffold/ansible/go_mod.go index 145f9a1adf..fec2bc304d 100644 --- a/internal/pkg/scaffold/ansible/go_mod.go +++ b/internal/pkg/scaffold/ansible/go_mod.go @@ -39,16 +39,17 @@ func (s *GoMod) GetInput() (input.Input, error) { const goModTmpl = `module {{ .Repo }} require ( - github.com/NYTimes/gziphandler v1.0.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect - github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect + github.com/google/go-cmp v0.3.0 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect github.com/operator-framework/operator-sdk master github.com/spf13/pflag v1.0.3 - k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 + golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 // indirect + golang.org/x/text v0.3.2 // indirect k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 // indirect sigs.k8s.io/controller-runtime v0.2.0-beta.3 - sigs.k8s.io/controller-tools v0.1.10 ) // Pinned to kubernetes-1.14.1 diff --git a/internal/pkg/scaffold/crd.go b/internal/pkg/scaffold/crd.go index 8a30c265d8..8231f9e0ac 100644 --- a/internal/pkg/scaffold/crd.go +++ b/internal/pkg/scaffold/crd.go @@ -16,19 +16,23 @@ package scaffold import ( "fmt" + "io" "os" "path/filepath" - "strings" "sync" "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/input" "github.com/operator-framework/operator-sdk/internal/util/k8sutil" "github.com/ghodss/yaml" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" "github.com/spf13/afero" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - crdgenerator "sigs.k8s.io/controller-tools/pkg/crd/generator" + crdgen "sigs.k8s.io/controller-tools/pkg/crd" + "sigs.k8s.io/controller-tools/pkg/genall" + "sigs.k8s.io/controller-tools/pkg/loader" ) // CRD is the input needed to generate a deploy/crds/__crd.yaml file @@ -68,6 +72,20 @@ func crdPathForResource(dir string, r *Resource) string { return filepath.Join(dir, file) } +type crdOutputRule struct { + fs afero.Fs +} + +var _ genall.OutputRule = crdOutputRule{} + +// Open is meant to be used to generate a CRD manifest in memory at path. +func (o crdOutputRule) Open(_ *loader.Package, path string) (io.WriteCloser, error) { + if o.fs == nil { + return nil, errors.Errorf("error opening %s: crdOutputRule fs must be set", path) + } + return o.fs.Create(path) +} + var _ CustomRenderer = &CRD{} func (s *CRD) SetFS(fs afero.Fs) { s.initFS(fs) } @@ -75,41 +93,20 @@ func (s *CRD) SetFS(fs afero.Fs) { s.initFS(fs) } func (s *CRD) CustomRender() ([]byte, error) { crd := &apiextv1beta1.CustomResourceDefinition{} if s.IsOperatorGo { - // This sets domain as empty string when we can't extract it from FullGroup. - // In turn this defaults to extracting the domain from project root file - // in controller-tools. - fg := strings.SplitN(s.Resource.FullGroup, ".", 2) - domain := s.Resource.FullGroup - if len(fg) > 1 { - domain = fg[1] - } fs := afero.NewMemMapFs() - g := &crdgenerator.Generator{ - RootPath: s.AbsProjectPath, - Domain: domain, - Repo: s.Repo, - OutputDir: ".", - SkipMapValidation: false, - OutFs: fs, - } - if err := g.ValidateAndInitFields(); err != nil { - return nil, err - } - if err := g.Do(); err != nil { + // controller-tool's generator reads and scaffolds a CRD for all APIs in + // pkg/apis. + err := runCRDGenerator(crdOutputRule{fs: fs}, s.AbsProjectPath) + if err != nil { return nil, err } - - // controller-tools generates crd file names with no _crd.yaml suffix: - // __.yaml. - genPath := fmt.Sprintf("%s_%s_%s.yaml", - s.Resource.GoImportGroup, - s.Resource.Version, - s.Resource.LowerKind, - ) - b, err := afero.ReadFile(fs, genPath) + // controller-tools generates CRD file names in the format below, which + // we need to read from fs. + genFile := fmt.Sprintf("%s_%s.yaml", s.Resource.FullGroup, s.Resource.Resource) + b, err := afero.ReadFile(fs, genFile) if err != nil { if os.IsNotExist(err) { - return nil, fmt.Errorf("no API exists for Group %s Version %s Kind %s", + return nil, fmt.Errorf("error generating CRD for Group %s Version %s Kind %s", s.Resource.GoImportGroup, s.Resource.Version, s.Resource.Kind) } return nil, err @@ -119,12 +116,10 @@ func (s *CRD) CustomRender() ([]byte, error) { } // controller-tools does not set ListKind or Singular names. setCRDNamesForResource(crd, s.Resource) - // Remove controller-tools default label. - delete(crd.Labels, "controller-tools.k8s.io") } else { // There are currently no commands to update CRD manifests for non-Go - // operators, so if a CRD manifests already exists for this gvk, this - // scaffold is a no-op. + // operators, so if a CRD manifest already exists for this gvk, this + // scaffold is a no-op (for now). path := crdPathForResource(filepath.Join(s.AbsProjectPath, CRDsDir), s.Resource) if _, err := s.getFS().Stat(path); err == nil { b, err := afero.ReadFile(s.getFS(), path) @@ -141,10 +136,41 @@ func (s *CRD) CustomRender() ([]byte, error) { } } - setCRDVersions(crd) + setCRDStorageVersion(crd) + if err := checkCRDVersions(crd); err != nil { + return nil, err + } return k8sutil.GetObjectBytes(crd, yaml.Marshal) } +func runCRDGenerator(rule genall.OutputRule, root string) (err error) { + absAPIsDir := filepath.Join(root, ApisDir) + gvs, err := k8sutil.ParseGroupVersions(absAPIsDir) + if err != nil { + return errors.Wrapf(err, "error parsing API group versions from directory %+q", absAPIsDir) + } + apiDirs := []string{} + for g, vs := range gvs { + for _, v := range vs { + apiDirs = append(apiDirs, filepath.Join(absAPIsDir, g, v)) + } + } + + cg := crdgen.Generator{} + gens := genall.Generators{cg} + r, err := gens.ForRoots(apiDirs...) + if err != nil { + return errors.Wrapf(err, "error loading API roots %+q", apiDirs) + } + r.OutputRules.ByGenerator = map[genall.Generator]genall.OutputRule{cg: rule} + ctx := r.GenerationContext + ctx.OutputRule = r.OutputRules.ForGenerator(gens[0]) + if err := gens[0].Generate(&ctx); err != nil { + return errors.Wrapf(err, "error generating CRDs") + } + return nil +} + func newCRDForResource(r *Resource) *apiextv1beta1.CustomResourceDefinition { crd := &apiextv1beta1.CustomResourceDefinition{ TypeMeta: metav1.TypeMeta{ @@ -155,9 +181,11 @@ func newCRDForResource(r *Resource) *apiextv1beta1.CustomResourceDefinition { Name: fmt.Sprintf("%s.%s", r.Resource, r.FullGroup), }, Spec: apiextv1beta1.CustomResourceDefinitionSpec{ - Group: r.FullGroup, - Scope: apiextv1beta1.NamespaceScoped, - Version: r.Version, + Group: r.FullGroup, + Scope: apiextv1beta1.NamespaceScoped, + Versions: []apiextv1beta1.CustomResourceDefinitionVersion{ + {Name: r.Version, Served: true, Storage: true}, + }, Subresources: &apiextv1beta1.CustomResourceSubresources{ Status: &apiextv1beta1.CustomResourceSubresourceStatus{}, }, @@ -182,35 +210,48 @@ func setCRDNamesForResource(crd *apiextv1beta1.CustomResourceDefinition, r *Reso } } -func setCRDVersions(crd *apiextv1beta1.CustomResourceDefinition) { - // crd.Version is deprecated, use crd.Versions instead. - var crdVersions []apiextv1beta1.CustomResourceDefinitionVersion - if crd.Spec.Version != "" { - var verExists, hasStorageVer bool - for _, ver := range crd.Spec.Versions { - if crd.Spec.Version == ver.Name { - verExists = true - } - // There must be exactly one version flagged as a storage version. - if ver.Storage { - hasStorageVer = true - } - } - if !verExists { - crdVersions = []apiextv1beta1.CustomResourceDefinitionVersion{ - {Name: crd.Spec.Version, Served: true, Storage: !hasStorageVer}, - } +func setCRDStorageVersion(crd *apiextv1beta1.CustomResourceDefinition) { + if len(crd.Spec.Versions) == 0 { + return + } + for _, ver := range crd.Spec.Versions { + if ver.Storage { + return } - } else { - crdVersions = []apiextv1beta1.CustomResourceDefinitionVersion{ - {Name: "v1alpha1", Served: true, Storage: true}, + } + // Set the first element in spec.versions to be the storage version. + log.Infof("Setting CRD %q storage version to %s", crd.GetName(), crd.Spec.Versions[0].Name) + crd.Spec.Versions[0].Storage = true +} + +// checkCRDVersions ensures version(s) generated for a CRD are in valid format. +// From the Kubernetes CRD docs: +// +// The version field is deprecated and optional, but if it is not empty, +// it must match the first item in the versions field. +func checkCRDVersions(crd *apiextv1beta1.CustomResourceDefinition) error { + singleVer := crd.Spec.Version != "" + multiVers := len(crd.Spec.Versions) > 0 + if singleVer { + if !multiVers { + log.Warnf("CRD %s: spec.version is deprecated and should be migrated to spec.versions", crd.Spec.Names.Kind) + } else if crd.Spec.Version != crd.Spec.Versions[0].Name { + return errors.Errorf("spec.version %s must be the first element in spec.versions for CRD %s", crd.Spec.Version, crd.Spec.Names.Kind) } } - if len(crd.Spec.Versions) > 0 { - // crd.Version should always be the first element in crd.Versions. - crd.Spec.Versions = append(crdVersions, crd.Spec.Versions...) - } else { - crd.Spec.Versions = crdVersions + var hasStorageVer bool + for _, ver := range crd.Spec.Versions { + // There must be exactly one version flagged as a storage version. + if ver.Storage { + if hasStorageVer { + return errors.Errorf("spec.versions cannot have more than one storage version for CRD %s", crd.Spec.Names.Kind) + } + hasStorageVer = true + } + } + if multiVers && !hasStorageVer { + return errors.Errorf("spec.versions must have exactly one storage version for CRD %s", crd.Spec.Names.Kind) } + return nil } diff --git a/internal/pkg/scaffold/crd_test.go b/internal/pkg/scaffold/crd_test.go index 7422d9c95a..f1ae2d3e53 100644 --- a/internal/pkg/scaffold/crd_test.go +++ b/internal/pkg/scaffold/crd_test.go @@ -65,47 +65,49 @@ spec: plural: memcacheds singular: memcached scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - size: - description: Size is the size of the memcached deployment - format: int32 - type: integer - required: - - size - type: object - status: - properties: - nodes: - description: Nodes are the names of the memcached pods - items: - type: string - type: array - required: - - nodes - type: object version: v1alpha1 versions: - name: v1alpha1 + schema: + openAPIV3Schema: + description: Memcached is the Schema for the memcacheds API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + size: + description: Size is the size of the memcached deployment + format: int32 + type: integer + required: + - size + type: object + status: + properties: + nodes: + description: Nodes are the names of the memcached pods + items: + type: string + type: array + required: + - nodes + type: object + type: object served: true storage: true + subresources: + status: {} ` func TestCRDNonGoProject(t *testing.T) { @@ -158,31 +160,31 @@ spec: plural: appservices singular: appservice scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - properties: - size: - format: int32 - type: integer - required: - - size - type: object - status: - properties: - nodes: - items: - type: string - type: array - required: - - nodes - type: object version: v1alpha1 versions: - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + spec: + properties: + size: + format: int32 + type: integer + required: + - size + type: object + status: + properties: + nodes: + items: + type: string + type: array + required: + - nodes + type: object served: true storage: true + subresources: + status: {} ` diff --git a/internal/pkg/scaffold/go_mod.go b/internal/pkg/scaffold/go_mod.go index 1ed9b014ac..8fb192115f 100644 --- a/internal/pkg/scaffold/go_mod.go +++ b/internal/pkg/scaffold/go_mod.go @@ -46,7 +46,6 @@ require ( k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 // indirect sigs.k8s.io/controller-runtime v0.2.0-beta.3 - sigs.k8s.io/controller-tools v0.1.10 ) // Pinned to kubernetes-1.14.1 @@ -61,7 +60,6 @@ replace ( replace ( github.com/coreos/prometheus-operator => github.com/coreos/prometheus-operator v0.31.1 sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.2.0-beta.3 - sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde // Pinned to v2.10.0 (kubernetes-1.14.1) so https://proxy.golang.org can // resolve it correctly. github.com/prometheus/prometheus => github.com/prometheus/prometheus d20e84d0fb64aff2f62a977adc8cfb656da4e286 diff --git a/internal/pkg/scaffold/gopkgtoml.go b/internal/pkg/scaffold/gopkgtoml.go index 465b1d29fd..af689353b2 100644 --- a/internal/pkg/scaffold/gopkgtoml.go +++ b/internal/pkg/scaffold/gopkgtoml.go @@ -34,19 +34,10 @@ func (s *GopkgToml) GetInput() (input.Input, error) { return s.Input, nil } -const gopkgTomlTmpl = `# Force dep to vendor the code generators, which aren't imported just used at dev time. -required = [ - "sigs.k8s.io/controller-tools/pkg/crd/generator", -] - -[[override]] +const gopkgTomlTmpl = `[[override]] name = "github.com/go-openapi/spec" branch = "master" -[[override]] - name = "sigs.k8s.io/controller-tools" - revision = "9d55346c2bde73fb3326ac22eac2e5210a730207" - [[override]] name = "k8s.io/api" # revision for tag "kubernetes-1.14.1" diff --git a/internal/pkg/scaffold/helm/go_mod.go b/internal/pkg/scaffold/helm/go_mod.go index facfc1a120..32ae680a73 100644 --- a/internal/pkg/scaffold/helm/go_mod.go +++ b/internal/pkg/scaffold/helm/go_mod.go @@ -46,6 +46,7 @@ require ( github.com/emicklei/go-restful v2.9.3+incompatible // indirect github.com/go-openapi/spec v0.19.0 // indirect github.com/google/btree v1.0.0 // indirect + github.com/google/go-cmp v0.3.0 // indirect github.com/gorilla/websocket v1.4.0 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect @@ -53,9 +54,12 @@ require ( github.com/imdario/mergo v0.3.7 // indirect github.com/jonboulle/clockwork v0.1.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect github.com/operator-framework/operator-sdk master github.com/spf13/pflag v1.0.3 github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 // indirect + golang.org/x/text v0.3.2 // indirect golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect google.golang.org/appengine v1.5.0 // indirect gotest.tools v2.2.0+incompatible // indirect @@ -64,7 +68,6 @@ require ( k8s.io/helm v2.14.1+incompatible // indirect k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 // indirect sigs.k8s.io/controller-runtime v0.2.0-beta.3 - sigs.k8s.io/controller-tools v0.1.10 ) // Pinned to kubernetes-1.14.1 diff --git a/internal/pkg/scaffold/tools.go b/internal/pkg/scaffold/tools.go index a04b494085..a869e6dafa 100644 --- a/internal/pkg/scaffold/tools.go +++ b/internal/pkg/scaffold/tools.go @@ -34,9 +34,7 @@ func (s *Tools) GetInput() (input.Input, error) { const toolsTmpl = `// +build tools +// Place any runtime dependencies as imports in this file. +// Go modules will be forced to download and install them. package tools - -import ( - _ "sigs.k8s.io/controller-tools/pkg/crd/generator" -) ` diff --git a/internal/pkg/scaffold/types.go b/internal/pkg/scaffold/types.go index 33d29870ad..948bebefd7 100644 --- a/internal/pkg/scaffold/types.go +++ b/internal/pkg/scaffold/types.go @@ -72,6 +72,7 @@ type {{.Resource.Kind}}Status struct { // {{.Resource.Kind}} is the Schema for the {{ .Resource.Resource }} API // +k8s:openapi-gen=true // +kubebuilder:subresource:status +// +kubebuilder:resource:path={{.Resource.Resource}},scope=Namespaced type {{.Resource.Kind}} struct { metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` metav1.ObjectMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` diff --git a/internal/pkg/scaffold/types_test.go b/internal/pkg/scaffold/types_test.go index 55663ea5a9..b1b30aa26f 100644 --- a/internal/pkg/scaffold/types_test.go +++ b/internal/pkg/scaffold/types_test.go @@ -67,6 +67,7 @@ type AppServiceStatus struct { // AppService is the Schema for the appservices API // +k8s:openapi-gen=true // +kubebuilder:subresource:status +// +kubebuilder:resource:path=appservices,scope=Namespaced type AppService struct { metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + ` metav1.ObjectMeta ` + "`" + `json:"metadata,omitempty"` + "`" + ` diff --git a/test/test-framework/deploy/namespace-init.yaml b/test/test-framework/deploy/namespace-init.yaml index fc9b93f90d..749ed548a3 100644 --- a/test/test-framework/deploy/namespace-init.yaml +++ b/test/test-framework/deploy/namespace-init.yaml @@ -65,7 +65,6 @@ roleRef: apiVersion: apps/v1 kind: Deployment metadata: - creationTimestamp: null name: memcached-operator spec: replicas: 1 @@ -75,7 +74,6 @@ spec: strategy: {} template: metadata: - creationTimestamp: null labels: name: memcached-operator spec: diff --git a/test/test-framework/pkg/apis/cache/v1alpha1/memcached_types.go b/test/test-framework/pkg/apis/cache/v1alpha1/memcached_types.go index 989a1683d4..67933261bf 100644 --- a/test/test-framework/pkg/apis/cache/v1alpha1/memcached_types.go +++ b/test/test-framework/pkg/apis/cache/v1alpha1/memcached_types.go @@ -35,6 +35,7 @@ type MemcachedStatus struct { // Memcached is the Schema for the memcacheds API // +k8s:openapi-gen=true // +kubebuilder:subresource:status +// +kubebuilder:resource:path=memcacheds,scope=Namespaced type Memcached struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"`