diff --git a/go.mod b/go.mod index 18630b76bcb..be58b550c08 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 github.com/kr/text v0.1.0 github.com/markbates/inflect v1.0.4 - github.com/onsi/ginkgo v1.14.1 - github.com/onsi/gomega v1.10.2 + github.com/onsi/ginkgo v1.15.0 + github.com/onsi/gomega v1.10.5 github.com/operator-framework/api v0.5.3 github.com/operator-framework/operator-lib v0.4.0 github.com/operator-framework/operator-registry v1.15.3 @@ -22,7 +22,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 github.com/stretchr/testify v1.6.1 - golang.org/x/tools v0.0.0-20201014231627-1610a49f37af + golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e gomodules.xyz/jsonpatch/v3 v3.0.1 helm.sh/helm/v3 v3.4.1 k8s.io/api v0.20.1 @@ -46,6 +46,9 @@ replace ( github.com/containerd/containerd => github.com/containerd/containerd v1.4.3 github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.10.0 golang.org/x/text => golang.org/x/text v0.3.3 // Required to fix CVE-2020-14040 + + // Validating changes from KB + sigs.k8s.io/kubebuilder/v3 => github.com/Adirio/kubebuilder/v3 v3.0.0-alpha.0.0.20210301113100-ccb4e08add05 ) exclude github.com/spf13/viper v1.3.2 // Required to fix CVE-2018-1098 diff --git a/go.sum b/go.sum index 590e734724d..8861bb545e3 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Adirio/kubebuilder/v3 v3.0.0-alpha.0.0.20210301113100-ccb4e08add05 h1:4GQmDxlTgapFnz7rapcoLtqfSoyCHj0ShmOUbzanucY= +github.com/Adirio/kubebuilder/v3 v3.0.0-alpha.0.0.20210301113100-ccb4e08add05/go.mod h1:O+YpPPkBBBQ+H7b2W1SqL8ygxDHFrVanJICzV8ToZtE= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -721,6 +723,8 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -731,6 +735,8 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1083,10 +1089,11 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1102,8 +1109,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1165,6 +1172,8 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1222,12 +1231,11 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201014231627-1610a49f37af h1:VIUWFyOgzG3c0t9KYop5Ybp4m56LupfOnFYX7Ipnz+I= -golang.org/x/tools v0.0.0-20201014231627-1610a49f37af/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1460,8 +1468,6 @@ sigs.k8s.io/controller-runtime v0.8.0/go.mod h1:v9Lbj5oX443uR7GXYY46E0EE2o7k2YxQ sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= sigs.k8s.io/controller-tools v0.4.1 h1:VkuV0MxlRPmRu5iTgBZU4UxUX2LiR99n3sdQGRxZF4w= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= -sigs.k8s.io/kubebuilder/v3 v3.0.0-alpha.0.0.20210211121616-05abe25e7215 h1:pwEHSu3/ODNEr33DNrKt2DovGV84LhRBLt4QyrT6FJA= -sigs.k8s.io/kubebuilder/v3 v3.0.0-alpha.0.0.20210211121616-05abe25e7215/go.mod h1:b1WkCy5t/3VSRBCffSfPV1WbH+f45ls69d4ic37sW6w= 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/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= diff --git a/hack/generate/samples/internal/go/v2/memcached_with_webhooks.go b/hack/generate/samples/internal/go/v2/memcached_with_webhooks.go index 2c5415b09f7..84a63c7a33b 100644 --- a/hack/generate/samples/internal/go/v2/memcached_with_webhooks.go +++ b/hack/generate/samples/internal/go/v2/memcached_with_webhooks.go @@ -59,11 +59,10 @@ func (mh *MemcachedGoWithWebhooks) Prepare() { func (mh *MemcachedGoWithWebhooks) Run() { log.Infof("creating the project") err := mh.ctx.Init( - "--project-version", "3", "--plugins", "go/v2", + "--project-version", "3", "--repo", "github.com/example/memcached-operator", - "--domain", - mh.ctx.Domain) + "--domain", mh.ctx.Domain) pkg.CheckError("creating the project", err) err = mh.ctx.CreateAPI( diff --git a/hack/generate/samples/internal/go/v3/memcached_with_webhooks.go b/hack/generate/samples/internal/go/v3/memcached_with_webhooks.go index cf74fbf501b..64d7743d43b 100644 --- a/hack/generate/samples/internal/go/v3/memcached_with_webhooks.go +++ b/hack/generate/samples/internal/go/v3/memcached_with_webhooks.go @@ -59,11 +59,10 @@ func (mh *MemcachedGoWithWebhooks) Prepare() { func (mh *MemcachedGoWithWebhooks) Run() { log.Infof("creating the project") err := mh.ctx.Init( - "--project-version", "3", "--plugins", "go/v3", + "--project-version", "3", "--repo", "github.com/example/memcached-operator", - "--domain", - mh.ctx.Domain) + "--domain", mh.ctx.Domain) pkg.CheckError("creating the project", err) err = mh.ctx.CreateAPI( diff --git a/internal/cmd/operator-sdk/cli/cli.go b/internal/cmd/operator-sdk/cli/cli.go index cab6264f33b..082680d5b0c 100644 --- a/internal/cmd/operator-sdk/cli/cli.go +++ b/internal/cmd/operator-sdk/cli/cli.go @@ -19,28 +19,30 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "sigs.k8s.io/kubebuilder/v3/pkg/cli" - cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2" cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" + golangv2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2" + golangv3 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3" "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/bundle" "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/cleanup" - "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/completion" "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/generate" "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/olm" "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/run" "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/scorecard" "github.com/operator-framework/operator-sdk/internal/flags" + "github.com/operator-framework/operator-sdk/internal/plugins" ansiblev1 "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1" - golangv2 "github.com/operator-framework/operator-sdk/internal/plugins/golang/v2" - golangv3 "github.com/operator-framework/operator-sdk/internal/plugins/golang/v3" + envtestv1 "github.com/operator-framework/operator-sdk/internal/plugins/envtest/v1" helmv1 "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1" + manifestsv1 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v1" + scorecardv1 "github.com/operator-framework/operator-sdk/internal/plugins/scorecard/v1" "github.com/operator-framework/operator-sdk/internal/util/projutil" ) var commands = []*cobra.Command{ bundle.NewCmd(), cleanup.NewCmd(), - completion.NewCmd(), generate.NewCmd(), olm.NewCmd(), run.NewCmd(), @@ -48,27 +50,48 @@ var commands = []*cobra.Command{ } func Run() error { - cli, _ := GetPluginsCLIAndRoot() - return cli.Run() + c, _ := GetPluginsCLIAndRoot() + return c.Run() } // GetPluginsCLIAndRoot returns the plugins based CLI configured to use operator-sdk as the root command // This CLI can run kubebuilder commands and certain SDK specific commands that are aligned for // the kubebuilder project layout func GetPluginsCLIAndRoot() (cli.CLI, *cobra.Command) { + ansibleBundle, _ := plugin.NewBundle("ansible" + plugins.DefaultNameQualifier, plugin.Version{Number: 1}, + &ansiblev1.Plugin{}, + &manifestsv1.Plugin{}, + &scorecardv1.Plugin{}, + ) + gov2Bundle, _ := plugin.NewBundle("go" + plugins.DefaultNameQualifier, plugin.Version{Number: 2}, + &golangv2.Plugin{}, + &envtestv1.Plugin{}, + &manifestsv1.Plugin{}, + &scorecardv1.Plugin{}, + ) + gov3Bundle, _ := plugin.NewBundle("go" + plugins.DefaultNameQualifier, plugin.Version{Number: 3}, + &golangv2.Plugin{}, + &manifestsv1.Plugin{}, + &scorecardv1.Plugin{}, + ) + helmBundle, _ := plugin.NewBundle("helm" + plugins.DefaultNameQualifier, plugin.Version{Number: 1}, + &helmv1.Plugin{}, + &manifestsv1.Plugin{}, + &scorecardv1.Plugin{}, + ) c, err := cli.New( cli.WithCommandName("operator-sdk"), cli.WithVersion(makeVersionString()), - cli.WithDefaultProjectVersion(cfgv3.Version), cli.WithPlugins( - &golangv2.Plugin{}, - &golangv3.Plugin{}, - &helmv1.Plugin{}, - &ansiblev1.Plugin{}, + ansibleBundle, + gov2Bundle, + gov3Bundle, + helmBundle, ), - cli.WithDefaultPlugins(cfgv2.Version, &golangv2.Plugin{}), - cli.WithDefaultPlugins(cfgv3.Version, &golangv3.Plugin{}), + cli.WithDefaultPlugins(&golangv3.Plugin{}, &manifestsv1.Plugin{}, &scorecardv1.Plugin{}), + cli.WithDefaultProjectVersion(cfgv3.Version), cli.WithExtraCommands(commands...), + cli.WithCompletion(), ) if err != nil { log.Fatal(err) diff --git a/internal/cmd/operator-sdk/completion/bash.go b/internal/cmd/operator-sdk/completion/bash.go deleted file mode 100644 index 9362e6ba931..00000000000 --- a/internal/cmd/operator-sdk/completion/bash.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © 2018 The Operator-SDK Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion - -import ( - "os" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -func newBashCmd() *cobra.Command { - return &cobra.Command{ - Use: "bash", - Short: "Generate bash completions", - RunE: func(cmd *cobra.Command, cmdArgs []string) error { - if err := cmd.Root().GenBashCompletion(os.Stdout); err != nil { - log.Fatal(err) - } - return nil - }, - } -} diff --git a/internal/cmd/operator-sdk/completion/bash_test.go b/internal/cmd/operator-sdk/completion/bash_test.go deleted file mode 100644 index dce45c6f837..00000000000 --- a/internal/cmd/operator-sdk/completion/bash_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Running a completion bash command", func() { - Describe("newBashCmd", func() { - It("creates a cobra command", func() { - cmd := newBashCmd() - Expect(cmd).NotTo(BeNil()) - Expect(cmd.Use).NotTo(Equal("")) - Expect(cmd.Short).NotTo(Equal("")) - }) - }) -}) diff --git a/internal/cmd/operator-sdk/completion/cmd.go b/internal/cmd/operator-sdk/completion/cmd.go deleted file mode 100644 index 259a16560a9..00000000000 --- a/internal/cmd/operator-sdk/completion/cmd.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2018 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion - -import ( - "github.com/spf13/cobra" -) - -func NewCmd() *cobra.Command { - completionCmd := &cobra.Command{ - Use: "completion", - Short: "Generators for shell completions", - } - completionCmd.AddCommand(newZshCmd()) - completionCmd.AddCommand(newBashCmd()) - return completionCmd -} diff --git a/internal/cmd/operator-sdk/completion/cmd_test.go b/internal/cmd/operator-sdk/completion/cmd_test.go deleted file mode 100644 index 883a317cd9f..00000000000 --- a/internal/cmd/operator-sdk/completion/cmd_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Running a completion command", func() { - Describe("NewCmd", func() { - It("creates a cobra command with the correct subcommands", func() { - cmd := NewCmd() - Expect(cmd).NotTo(BeNil()) - - subcommands := cmd.Commands() - Expect(len(subcommands)).To(Equal(2)) - Expect(subcommands[0].Use).To(Equal("bash")) - Expect(subcommands[1].Use).To(Equal("zsh")) - }) - }) -}) diff --git a/internal/cmd/operator-sdk/completion/completion_suite_test.go b/internal/cmd/operator-sdk/completion/completion_suite_test.go deleted file mode 100644 index 7626254fae0..00000000000 --- a/internal/cmd/operator-sdk/completion/completion_suite_test.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion_test - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestCompletion(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Completion Suite") -} diff --git a/internal/cmd/operator-sdk/completion/zsh.go b/internal/cmd/operator-sdk/completion/zsh.go deleted file mode 100644 index c46fa4218a3..00000000000 --- a/internal/cmd/operator-sdk/completion/zsh.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © 2018 The Operator-SDK Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion - -import ( - "os" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -func newZshCmd() *cobra.Command { - return &cobra.Command{ - Use: "zsh", - Short: "Generate zsh completions", - RunE: func(cmd *cobra.Command, cmdArgs []string) error { - if err := cmd.Root().GenZshCompletion(os.Stdout); err != nil { - log.Fatal(err) - } - return nil - }, - } -} diff --git a/internal/cmd/operator-sdk/completion/zsh_test.go b/internal/cmd/operator-sdk/completion/zsh_test.go deleted file mode 100644 index c7a846bffae..00000000000 --- a/internal/cmd/operator-sdk/completion/zsh_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package completion - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("Running a completion zsh command", func() { - Describe("newZshCmd", func() { - It("creates a cobra command", func() { - cmd := newZshCmd() - Expect(cmd).NotTo(BeNil()) - Expect(cmd.Use).NotTo(Equal("")) - Expect(cmd.Short).NotTo(Equal("")) - }) - }) -}) diff --git a/internal/cmd/operator-sdk/generate/packagemanifests/packagemanifests_test.go b/internal/cmd/operator-sdk/generate/packagemanifests/packagemanifests_test.go index afbc99f9eea..4dedfc64238 100644 --- a/internal/cmd/operator-sdk/generate/packagemanifests/packagemanifests_test.go +++ b/internal/cmd/operator-sdk/generate/packagemanifests/packagemanifests_test.go @@ -196,7 +196,7 @@ var _ = Describe("Running a generate packagemanifests command", func() { err := c.setDefaults() Expect(err).NotTo(HaveOccurred()) Expect(c.packageName).To(Equal("memcached-operator")) - Expect(c.layout).To(Equal("go.kubebuilder.io/v3")) + Expect(c.layout).To(Equal("go.kubebuilder.io/v3,manifests.sdk.operatorframework.io/v1,scorecard.sdk.operatorframework.io/v1")) }) It("doesn't overwrite the package name if it's already set", func() { c.packageName = "cherry" @@ -204,7 +204,7 @@ var _ = Describe("Running a generate packagemanifests command", func() { err := c.setDefaults() Expect(err).NotTo(HaveOccurred()) Expect(c.packageName).To(Equal("cherry")) - Expect(c.layout).To(Equal("go.kubebuilder.io/v3")) + Expect(c.layout).To(Equal("go.kubebuilder.io/v3,manifests.sdk.operatorframework.io/v1,scorecard.sdk.operatorframework.io/v1")) }) }) Context("an invalid project file is present", func() { diff --git a/internal/kubebuilder/cmdutil/cmdutil.go b/internal/kubebuilder/cmdutil/cmdutil.go deleted file mode 100644 index aa3e7f4a9e9..00000000000 --- a/internal/kubebuilder/cmdutil/cmdutil.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cmdutil - -// Scaffolder interface creates files to set up a controller manager -type Scaffolder interface { - // Scaffold performs the scaffolding - Scaffold() error -} - -// RunOptions represent the types used to implement the different commands -type RunOptions interface { - // - Step 1: verify that the command can be run (e.g., go version, project version, arguments, ...) - Validate() error - // - Step 2: create the Scaffolder instance - GetScaffolder() (Scaffolder, error) - // - Step 3: call the Scaffold method of the Scaffolder instance. Doesn't need any method - // - Step 4: finish the command execution - PostScaffold() error -} - -// Run executes a command -func Run(options RunOptions) error { - // Step 1: validate - if err := options.Validate(); err != nil { - return err - } - - // Step 2: get scaffolder - scaffolder, err := options.GetScaffolder() - if err != nil { - return err - } - // Step 3: scaffold - if scaffolder != nil { - if err := scaffolder.Scaffold(); err != nil { - return err - } - } - // Step 4: finish - if err := options.PostScaffold(); err != nil { - return err - } - - return nil -} diff --git a/internal/kubebuilder/filesystem/errors.go b/internal/kubebuilder/filesystem/errors.go deleted file mode 100644 index 7f605d3241a..00000000000 --- a/internal/kubebuilder/filesystem/errors.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "errors" - "fmt" -) - -// This file contains the errors returned by the file system wrapper -// They are not exported as they should not be created outside of this package -// Exported functions are provided to check which kind of error was returned - -// fileExistsError is returned if it could not be checked if the file exists -type fileExistsError struct { - path string - err error -} - -// Error implements error interface -func (e fileExistsError) Error() string { - return fmt.Sprintf("failed to check if %s exists: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e fileExistsError) Unwrap() error { - return e.err -} - -// IsFileExistsError checks if the returned error is because the file could not be checked for existence -func IsFileExistsError(err error) bool { - return errors.As(err, &fileExistsError{}) -} - -// openFileError is returned if the file could not be opened -type openFileError struct { - path string - err error -} - -// Error implements error interface -func (e openFileError) Error() string { - return fmt.Sprintf("failed to open %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e openFileError) Unwrap() error { - return e.err -} - -// IsOpenFileError checks if the returned error is because the file could not be opened -func IsOpenFileError(err error) bool { - return errors.As(err, &openFileError{}) -} - -// createDirectoryError is returned if the directory could not be created -type createDirectoryError struct { - path string - err error -} - -// Error implements error interface -func (e createDirectoryError) Error() string { - return fmt.Sprintf("failed to create directory for %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e createDirectoryError) Unwrap() error { - return e.err -} - -// IsCreateDirectoryError checks if the returned error is because the directory could not be created -func IsCreateDirectoryError(err error) bool { - return errors.As(err, &createDirectoryError{}) -} - -// createFileError is returned if the file could not be created -type createFileError struct { - path string - err error -} - -// Error implements error interface -func (e createFileError) Error() string { - return fmt.Sprintf("failed to create %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e createFileError) Unwrap() error { - return e.err -} - -// IsCreateFileError checks if the returned error is because the file could not be created -func IsCreateFileError(err error) bool { - return errors.As(err, &createFileError{}) -} - -// readFileError is returned if the file could not be read -type readFileError struct { - path string - err error -} - -// Error implements error interface -func (e readFileError) Error() string { - return fmt.Sprintf("failed to read from %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e readFileError) Unwrap() error { - return e.err -} - -// IsReadFileError checks if the returned error is because the file could not be read -func IsReadFileError(err error) bool { - return errors.As(err, &readFileError{}) -} - -// writeFileError is returned if the file could not be written -type writeFileError struct { - path string - err error -} - -// Error implements error interface -func (e writeFileError) Error() string { - return fmt.Sprintf("failed to write to %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e writeFileError) Unwrap() error { - return e.err -} - -// IsWriteFileError checks if the returned error is because the file could not be written to -func IsWriteFileError(err error) bool { - return errors.As(err, &writeFileError{}) -} - -// closeFileError is returned if the file could not be created -type closeFileError struct { - path string - err error -} - -// Error implements error interface -func (e closeFileError) Error() string { - return fmt.Sprintf("failed to close %s: %v", e.path, e.err) -} - -// Unwrap implements Wrapper interface -func (e closeFileError) Unwrap() error { - return e.err -} - -// IsCloseFileError checks if the returned error is because the file could not be closed -func IsCloseFileError(err error) bool { - return errors.As(err, &closeFileError{}) -} diff --git a/internal/kubebuilder/filesystem/errors_test.go b/internal/kubebuilder/filesystem/errors_test.go deleted file mode 100644 index 090101fa4e4..00000000000 --- a/internal/kubebuilder/filesystem/errors_test.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "errors" - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/ginkgo/extensions/table" - . "github.com/onsi/gomega" -) - -var _ = Describe("Errors", func() { - var ( - path = filepath.Join("path", "to", "file") - err = errors.New("test error") - fileExistsErr = fileExistsError{path, err} - openFileErr = openFileError{path, err} - createDirectoryErr = createDirectoryError{path, err} - createFileErr = createFileError{path, err} - readFileErr = readFileError{path, err} - writeFileErr = writeFileError{path, err} - closeFileErr = closeFileError{path, err} - ) - - DescribeTable("IsXxxxError should return true for themselves and false for the rest", - func(f func(error) bool, itself error, rest ...error) { - Expect(f(itself)).To(BeTrue()) - for _, err := range rest { - Expect(f(err)).To(BeFalse()) - } - }, - Entry("file exists", IsFileExistsError, fileExistsErr, - openFileErr, createDirectoryErr, createFileErr, readFileErr, writeFileErr, closeFileErr), - Entry("open file", IsOpenFileError, openFileErr, - fileExistsErr, createDirectoryErr, createFileErr, readFileErr, writeFileErr, closeFileErr), - Entry("create directory", IsCreateDirectoryError, createDirectoryErr, - fileExistsErr, openFileErr, createFileErr, readFileErr, writeFileErr, closeFileErr), - Entry("create file", IsCreateFileError, createFileErr, - fileExistsErr, openFileErr, createDirectoryErr, readFileErr, writeFileErr, closeFileErr), - Entry("read file", IsReadFileError, readFileErr, - fileExistsErr, openFileErr, createDirectoryErr, createFileErr, writeFileErr, closeFileErr), - Entry("write file", IsWriteFileError, writeFileErr, - fileExistsErr, openFileErr, createDirectoryErr, createFileErr, readFileErr, closeFileErr), - Entry("close file", IsCloseFileError, closeFileErr, - fileExistsErr, openFileErr, createDirectoryErr, createFileErr, readFileErr, writeFileErr), - ) - - DescribeTable("should contain the wrapped error and error message", - func(err error) { - Expect(err).To(MatchError(err)) - Expect(err.Error()).To(ContainSubstring(err.Error())) - }, - Entry("file exists", fileExistsErr), - Entry("open file", openFileErr), - Entry("create directory", createDirectoryErr), - Entry("create file", createFileErr), - Entry("read file", readFileErr), - Entry("write file", writeFileErr), - Entry("close file", closeFileErr), - ) -}) diff --git a/internal/kubebuilder/filesystem/filesystem.go b/internal/kubebuilder/filesystem/filesystem.go deleted file mode 100644 index 1c124a1ce18..00000000000 --- a/internal/kubebuilder/filesystem/filesystem.go +++ /dev/null @@ -1,181 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "io" - "os" - "path/filepath" - - "github.com/spf13/afero" -) - -const ( - createOrUpdate = os.O_WRONLY | os.O_CREATE | os.O_TRUNC - - defaultDirectoryPermission os.FileMode = 0755 - defaultFilePermission os.FileMode = 0644 -) - -// FileSystem is an IO wrapper to create files -type FileSystem interface { - // Exists checks if the file exists - Exists(path string) (bool, error) - - // Open opens the file and returns a self-closing io.Reader. - Open(path string) (io.ReadCloser, error) - - // Create creates the directory and file and returns a self-closing - // io.Writer pointing to that file. If the file exists, it truncates it. - Create(path string) (io.Writer, error) -} - -// fileSystem implements FileSystem -type fileSystem struct { - fs afero.Fs - dirPerm os.FileMode - filePerm os.FileMode - fileMode int -} - -// New returns a new FileSystem -func New(options ...Options) FileSystem { - // Default values - fs := fileSystem{ - fs: afero.NewOsFs(), - dirPerm: defaultDirectoryPermission, - filePerm: defaultFilePermission, - fileMode: createOrUpdate, - } - - // Apply options - for _, option := range options { - option(&fs) - } - - return fs -} - -// Options configure FileSystem -type Options func(system *fileSystem) - -// DirectoryPermissions makes FileSystem.Create use the provided directory -// permissions -func DirectoryPermissions(dirPerm os.FileMode) Options { - return func(fs *fileSystem) { - fs.dirPerm = dirPerm - } -} - -// FilePermissions makes FileSystem.Create use the provided file permissions -func FilePermissions(filePerm os.FileMode) Options { - return func(fs *fileSystem) { - fs.filePerm = filePerm - } -} - -// Exists implements FileSystem.Exists -func (fs fileSystem) Exists(path string) (bool, error) { - exists, err := afero.Exists(fs.fs, path) - if err != nil { - return exists, fileExistsError{path, err} - } - - return exists, nil -} - -// Open implements FileSystem.Open -func (fs fileSystem) Open(path string) (io.ReadCloser, error) { - rc, err := fs.fs.Open(path) - if err != nil { - return nil, openFileError{path, err} - } - - return &readFile{path, rc}, nil -} - -// Create implements FileSystem.Create -func (fs fileSystem) Create(path string) (io.Writer, error) { - // Create the directory if needed - if err := fs.fs.MkdirAll(filepath.Dir(path), fs.dirPerm); err != nil { - return nil, createDirectoryError{path, err} - } - - // Create or truncate the file - wc, err := fs.fs.OpenFile(path, fs.fileMode, fs.filePerm) - if err != nil { - return nil, createFileError{path, err} - } - - return &writeFile{path, wc}, nil -} - -var _ io.ReadCloser = &readFile{} - -// readFile implements io.Reader -type readFile struct { - path string - io.ReadCloser -} - -// Read implements io.Reader.ReadCloser -func (f *readFile) Read(content []byte) (n int, err error) { - // Read the content - n, err = f.ReadCloser.Read(content) - // EOF is a special case error that we can't wrap - if err == io.EOF { - return - } - if err != nil { - return n, readFileError{f.path, err} - } - - return n, nil -} - -// Close implements io.Reader.ReadCloser -func (f *readFile) Close() error { - if err := f.ReadCloser.Close(); err != nil { - return closeFileError{f.path, err} - } - - return nil -} - -// writeFile implements io.Writer -type writeFile struct { - path string - io.WriteCloser -} - -// Write implements io.Writer.Write -func (f *writeFile) Write(content []byte) (n int, err error) { - // Close the file when we end writing - defer func() { - if closeErr := f.Close(); err == nil && closeErr != nil { - err = closeFileError{f.path, err} - } - }() - - // Write the content - n, err = f.WriteCloser.Write(content) - if err != nil { - return n, writeFileError{f.path, err} - } - - return n, nil -} diff --git a/internal/kubebuilder/filesystem/filesystem_suite_test.go b/internal/kubebuilder/filesystem/filesystem_suite_test.go deleted file mode 100644 index c3be2d93bde..00000000000 --- a/internal/kubebuilder/filesystem/filesystem_suite_test.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestScaffold(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Filesystem Suite") -} diff --git a/internal/kubebuilder/filesystem/filesystem_test.go b/internal/kubebuilder/filesystem/filesystem_test.go deleted file mode 100644 index 6a3d216f112..00000000000 --- a/internal/kubebuilder/filesystem/filesystem_test.go +++ /dev/null @@ -1,150 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "os" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("FileSystem", func() { - Describe("New", func() { - const ( - dirPerm os.FileMode = 0777 - filePerm os.FileMode = 0666 - ) - - var ( - fsi FileSystem - fs fileSystem - ok bool - ) - - Context("when using no options", func() { - BeforeEach(func() { - fsi = New() - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use default directory permission", func() { - Expect(fs.dirPerm).To(Equal(defaultDirectoryPermission)) - }) - - It("should use default file permission", func() { - Expect(fs.filePerm).To(Equal(defaultFilePermission)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - - Context("when using directory permission option", func() { - BeforeEach(func() { - fsi = New(DirectoryPermissions(dirPerm)) - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use provided directory permission", func() { - Expect(fs.dirPerm).To(Equal(dirPerm)) - }) - - It("should use default file permission", func() { - Expect(fs.filePerm).To(Equal(defaultFilePermission)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - - Context("when using file permission option", func() { - BeforeEach(func() { - fsi = New(FilePermissions(filePerm)) - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use default directory permission", func() { - Expect(fs.dirPerm).To(Equal(defaultDirectoryPermission)) - }) - - It("should use provided file permission", func() { - Expect(fs.filePerm).To(Equal(filePerm)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - - Context("when using both directory and file permission options", func() { - BeforeEach(func() { - fsi = New(DirectoryPermissions(dirPerm), FilePermissions(filePerm)) - fs, ok = fsi.(fileSystem) - }) - - It("should be a fileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should not have a nil fs", func() { - Expect(fs.fs).NotTo(BeNil()) - }) - - It("should use provided directory permission", func() { - Expect(fs.dirPerm).To(Equal(dirPerm)) - }) - - It("should use provided file permission", func() { - Expect(fs.filePerm).To(Equal(filePerm)) - }) - - It("should use default file mode", func() { - Expect(fs.fileMode).To(Equal(createOrUpdate)) - }) - }) - }) - - // NOTE: FileSystem.Exists, FileSystem.Open, FileSystem.Open().Read, FileSystem.Create and FileSystem.Create().Write - // are hard to test in unitary tests as they deal with actual files -}) diff --git a/internal/kubebuilder/filesystem/mock.go b/internal/kubebuilder/filesystem/mock.go deleted file mode 100644 index b7d213c1fc3..00000000000 --- a/internal/kubebuilder/filesystem/mock.go +++ /dev/null @@ -1,217 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "bytes" - "io" -) - -// mockFileSystem implements FileSystem -type mockFileSystem struct { - path string - exists func(path string) bool - existsError error - openFileError error - createDirError error - createFileError error - input *bytes.Buffer - readFileError error - output *bytes.Buffer - writeFileError error - closeFileError error -} - -// NewMock returns a new FileSystem -func NewMock(options ...MockOptions) FileSystem { - // Default values - fs := mockFileSystem{ - exists: func(_ string) bool { return false }, - output: new(bytes.Buffer), - } - - // Apply options - for _, option := range options { - option(&fs) - } - - return fs -} - -// MockOptions configure FileSystem -type MockOptions func(system *mockFileSystem) - -// MockPath ensures that the file created with this scaffold is at path -func MockPath(path string) MockOptions { - return func(fs *mockFileSystem) { - fs.path = path - } -} - -// MockExists makes FileSystem.Exists use the provided function to check if the file exists -func MockExists(exists func(path string) bool) MockOptions { - return func(fs *mockFileSystem) { - fs.exists = exists - } -} - -// MockExistsError makes FileSystem.Exists return err -func MockExistsError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.existsError = err - } -} - -// MockOpenFileError makes FileSystem.Open return err -func MockOpenFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.openFileError = err - } -} - -// MockCreateDirError makes FileSystem.Create return err -func MockCreateDirError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.createDirError = err - } -} - -// MockCreateFileError makes FileSystem.Create return err -func MockCreateFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.createFileError = err - } -} - -// MockInput provides a buffer where the content will be read from -func MockInput(input *bytes.Buffer) MockOptions { - return func(fs *mockFileSystem) { - fs.input = input - } -} - -// MockReadFileError makes the Read method (of the io.Reader returned by FileSystem.Open) return err -func MockReadFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.readFileError = err - } -} - -// MockOutput provides a buffer where the content will be written -func MockOutput(output *bytes.Buffer) MockOptions { - return func(fs *mockFileSystem) { - fs.output = output - } -} - -// MockWriteFileError makes the Write method (of the io.Writer returned by FileSystem.Create) return err -func MockWriteFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.writeFileError = err - } -} - -// MockCloseFileError makes the Write method (of the io.Writer returned by FileSystem.Create) return err -func MockCloseFileError(err error) MockOptions { - return func(fs *mockFileSystem) { - fs.closeFileError = err - } -} - -// Exists implements FileSystem.Exists -func (fs mockFileSystem) Exists(path string) (bool, error) { - if fs.existsError != nil { - return false, fileExistsError{path, fs.existsError} - } - - return fs.exists(path), nil -} - -// Open implements FileSystem.Open -func (fs mockFileSystem) Open(path string) (io.ReadCloser, error) { - if fs.openFileError != nil { - return nil, openFileError{path, fs.openFileError} - } - - if fs.input == nil { - fs.input = bytes.NewBufferString("Hello world!") - } - - return &mockReadFile{path, fs.input, fs.readFileError, fs.closeFileError}, nil -} - -// Create implements FileSystem.Create -func (fs mockFileSystem) Create(path string) (io.Writer, error) { - if fs.createDirError != nil { - return nil, createDirectoryError{path, fs.createDirError} - } - - if fs.createFileError != nil { - return nil, createFileError{path, fs.createFileError} - } - - return &mockWriteFile{path, fs.output, fs.writeFileError, fs.closeFileError}, nil -} - -// mockReadFile implements io.Reader mocking a readFile for tests -type mockReadFile struct { - path string - input *bytes.Buffer - readFileError error - closeFileError error -} - -// Read implements io.Reader.ReadCloser -func (f *mockReadFile) Read(content []byte) (n int, err error) { - if f.readFileError != nil { - return 0, readFileError{path: f.path, err: f.readFileError} - } - - return f.input.Read(content) -} - -// Read implements io.Reader.ReadCloser -func (f *mockReadFile) Close() error { - if f.closeFileError != nil { - return closeFileError{path: f.path, err: f.closeFileError} - } - - return nil -} - -// mockWriteFile implements io.Writer mocking a writeFile for tests -type mockWriteFile struct { - path string - content *bytes.Buffer - writeFileError error - closeFileError error -} - -// Write implements io.Writer.Write -func (f *mockWriteFile) Write(content []byte) (n int, err error) { - defer func() { - if err == nil && f.closeFileError != nil { - err = closeFileError{f.path, f.closeFileError} - } - }() - - if f.writeFileError != nil { - return 0, writeFileError{f.path, f.writeFileError} - } - - return f.content.Write(content) -} diff --git a/internal/kubebuilder/filesystem/mock_test.go b/internal/kubebuilder/filesystem/mock_test.go deleted file mode 100644 index e9e7d58ccbf..00000000000 --- a/internal/kubebuilder/filesystem/mock_test.go +++ /dev/null @@ -1,448 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package filesystem - -import ( - "bytes" - "errors" - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -//nolint:dupl -var _ = Describe("MockFileSystem", func() { - var ( - fsi FileSystem - fs mockFileSystem - ok bool - options []MockOptions - testErr = errors.New("test error") - ) - - JustBeforeEach(func() { - fsi = NewMock(options...) - fs, ok = fsi.(mockFileSystem) - }) - - Context("when using no options", func() { - BeforeEach(func() { - options = make([]MockOptions, 0) - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockPath", func() { - var filePath = filepath.Join("path", "to", "file") - - BeforeEach(func() { - options = []MockOptions{MockPath(filePath)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should save the provided path", func() { - Expect(fs.path).To(Equal(filePath)) - }) - }) - - Context("when using MockExists", func() { - BeforeEach(func() { - options = []MockOptions{MockExists(func(_ string) bool { return true })} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeTrue()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockExistsError", func() { - BeforeEach(func() { - options = []MockOptions{MockExistsError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should error when calling Exists", func() { - _, err := fsi.Exists("") - Expect(err).To(MatchError(testErr)) - Expect(IsFileExistsError(err)).To(BeTrue()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockOpenFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockOpenFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should error when calling Open", func() { - _, err := fsi.Open("") - Expect(err).To(MatchError(testErr)) - Expect(IsOpenFileError(err)).To(BeTrue()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockCreateDirError", func() { - BeforeEach(func() { - options = []MockOptions{MockCreateDirError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should error when calling Create", func() { - _, err := fsi.Create("") - Expect(err).To(MatchError(testErr)) - Expect(IsCreateDirectoryError(err)).To(BeTrue()) - }) - }) - - Context("when using MockCreateFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockCreateFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should error when calling Create", func() { - _, err := fsi.Create("") - Expect(err).To(MatchError(testErr)) - Expect(IsCreateFileError(err)).To(BeTrue()) - }) - }) - - Context("when using MockInput", func() { - var ( - input *bytes.Buffer - fileContent = []byte("Hello world!") - ) - - BeforeEach(func() { - input = bytes.NewBufferString("Hello world!") - options = []MockOptions{MockInput(input)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files and the content to be accessible", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - output := make([]byte, len(fileContent)) - n, err := f.Read(output) - Expect(err).NotTo(HaveOccurred()) - Expect(n).To(Equal(len(fileContent))) - Expect(output).To(Equal(fileContent)) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockReadFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockReadFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should error when calling Open().Read", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - output := make([]byte, 0) - _, err = f.Read(output) - Expect(err).To(MatchError(testErr)) - Expect(IsReadFileError(err)).To(BeTrue()) - }) - - It("should create writable files", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - }) - - Context("when using MockOutput", func() { - var ( - output bytes.Buffer - fileContent = []byte("Hello world!") - ) - - BeforeEach(func() { - options = []MockOptions{MockOutput(&output)} - output.Reset() - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should create writable files and the content should be accesible", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - n, err := f.Write(fileContent) - Expect(err).NotTo(HaveOccurred()) - Expect(n).To(Equal(len(fileContent))) - Expect(output.Bytes()).To(Equal(fileContent)) - }) - }) - - Context("when using MockWriteFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockWriteFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should open readable files", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Read([]byte("")) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should error when calling Create().Write", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).To(MatchError(testErr)) - Expect(IsWriteFileError(err)).To(BeTrue()) - }) - }) - - Context("when using MockCloseFileError", func() { - BeforeEach(func() { - options = []MockOptions{MockCloseFileError(testErr)} - }) - - It("should be a mockFileSystem instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should claim that files don't exist", func() { - exists, err := fsi.Exists("") - Expect(err).NotTo(HaveOccurred()) - Expect(exists).To(BeFalse()) - }) - - It("should error when calling Open().Close", func() { - f, err := fsi.Open("") - Expect(err).NotTo(HaveOccurred()) - - err = f.Close() - Expect(err).To(MatchError(testErr)) - Expect(IsCloseFileError(err)).To(BeTrue()) - }) - - It("should error when calling Create().Write", func() { - f, err := fsi.Create("") - Expect(err).NotTo(HaveOccurred()) - - _, err = f.Write([]byte("")) - Expect(err).To(MatchError(testErr)) - Expect(IsCloseFileError(err)).To(BeTrue()) - }) - }) -}) diff --git a/internal/kubebuilder/machinery/errors.go b/internal/kubebuilder/machinery/errors.go deleted file mode 100644 index faba57a1d05..00000000000 --- a/internal/kubebuilder/machinery/errors.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "errors" - "fmt" - - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" -) - -// This file contains the errors returned by the scaffolding machinery -// They are not exported as they should not be created outside of this package -// Exported functions are provided to check which kind of error was returned - -// fileAlreadyExistsError is returned if the file is expected not to exist but it does -type fileAlreadyExistsError struct { - path string -} - -// Error implements error interface -func (e fileAlreadyExistsError) Error() string { - return fmt.Sprintf("failed to create %s: file already exists", e.path) -} - -// IsFileAlreadyExistsError checks if the returned error is because the file already existed when expected not to -func IsFileAlreadyExistsError(err error) bool { - return errors.As(err, &fileAlreadyExistsError{}) -} - -// modelAlreadyExistsError is returned if the file is expected not to exist but a previous model does -type modelAlreadyExistsError struct { - path string -} - -// Error implements error interface -func (e modelAlreadyExistsError) Error() string { - return fmt.Sprintf("failed to create %s: model already exists", e.path) -} - -// IsModelAlreadyExistsError checks if the returned error is because the model already existed when expected not to -func IsModelAlreadyExistsError(err error) bool { - return errors.As(err, &modelAlreadyExistsError{}) -} - -// unknownIfExistsActionError is returned if the if-exists-action is unknown -type unknownIfExistsActionError struct { - path string - ifExistsAction file.IfExistsAction -} - -// Error implements error interface -func (e unknownIfExistsActionError) Error() string { - return fmt.Sprintf("unknown behavior if file exists (%d) for %s", e.ifExistsAction, e.path) -} - -// IsUnknownIfExistsActionError checks if the returned error is because the if-exists-action is unknown -func IsUnknownIfExistsActionError(err error) bool { - return errors.As(err, &unknownIfExistsActionError{}) -} diff --git a/internal/kubebuilder/machinery/errors_test.go b/internal/kubebuilder/machinery/errors_test.go deleted file mode 100644 index 3d6b8ce14e4..00000000000 --- a/internal/kubebuilder/machinery/errors_test.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "errors" - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/ginkgo/extensions/table" - . "github.com/onsi/gomega" -) - -var _ = Describe("Errors", func() { - var ( - path = filepath.Join("path", "to", "file") - err = errors.New("test error") - fileAlreadyExistsErr = fileAlreadyExistsError{path} - modelAlreadyExistsErr = modelAlreadyExistsError{path} - unknownIfExistsActionErr = unknownIfExistsActionError{path, -1} - ) - - DescribeTable("IsXxxxError should return true for themselves and false for the rest", - func(f func(error) bool, itself error, rest ...error) { - Expect(f(itself)).To(BeTrue()) - for _, err := range rest { - Expect(f(err)).To(BeFalse()) - } - }, - Entry("file exists", IsFileAlreadyExistsError, fileAlreadyExistsErr, - err, modelAlreadyExistsErr, unknownIfExistsActionErr), - Entry("model exists", IsModelAlreadyExistsError, modelAlreadyExistsErr, - err, fileAlreadyExistsErr, unknownIfExistsActionErr), - Entry("unknown if exists action", IsUnknownIfExistsActionError, unknownIfExistsActionErr, - err, fileAlreadyExistsErr, modelAlreadyExistsErr), - ) - - DescribeTable("should contain the wrapped error and error message", - func(err error) { - Expect(err).To(MatchError(err)) - Expect(err.Error()).To(ContainSubstring(err.Error())) - }, - ) - - // NOTE: the following test increases coverage - It("should print a descriptive error message", func() { - Expect(fileAlreadyExistsErr.Error()).To(ContainSubstring("file already exists")) - Expect(modelAlreadyExistsErr.Error()).To(ContainSubstring("model already exists")) - Expect(unknownIfExistsActionErr.Error()).To(ContainSubstring("unknown behavior if file exists")) - }) -}) diff --git a/internal/kubebuilder/machinery/machinery_suite_test.go b/internal/kubebuilder/machinery/machinery_suite_test.go deleted file mode 100644 index 107008e04da..00000000000 --- a/internal/kubebuilder/machinery/machinery_suite_test.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestScaffold(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Machinery Suite") -} diff --git a/internal/kubebuilder/machinery/scaffold.go b/internal/kubebuilder/machinery/scaffold.go deleted file mode 100644 index bcd55af132f..00000000000 --- a/internal/kubebuilder/machinery/scaffold.go +++ /dev/null @@ -1,389 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "bufio" - "bytes" - "fmt" - "io/ioutil" - "path/filepath" - "strings" - "text/template" - - "golang.org/x/tools/imports" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" - - "github.com/operator-framework/operator-sdk/internal/kubebuilder/filesystem" -) - -var options = imports.Options{ - Comments: true, - TabIndent: true, - TabWidth: 8, - FormatOnly: true, -} - -// Scaffold uses templates to scaffold new files -type Scaffold interface { - // Execute writes to disk the provided files - Execute(*model.Universe, ...file.Builder) error -} - -// scaffold implements Scaffold interface -type scaffold struct { - // plugins is the list of plugins we should allow to transform our generated scaffolding - plugins []model.Plugin - - // fs allows to mock the file system for tests - fs filesystem.FileSystem -} - -// NewScaffold returns a new Scaffold with the provided plugins -func NewScaffold(plugins ...model.Plugin) Scaffold { - return &scaffold{ - plugins: plugins, - fs: filesystem.New(), - } -} - -// Execute implements Scaffold.Execute -func (s *scaffold) Execute(universe *model.Universe, files ...file.Builder) error { - // Initialize the universe files - universe.Files = make(map[string]*file.File, len(files)) - - // Set the repo as the local prefix so that it knows how to group imports - if universe.Config != nil { - imports.LocalPrefix = universe.Config.GetRepository() - } - - for _, f := range files { - // Inject common fields - universe.InjectInto(f) - - // Validate file builders - if reqValFile, requiresValidation := f.(file.RequiresValidation); requiresValidation { - if err := reqValFile.Validate(); err != nil { - return file.NewValidateError(err) - } - } - - // Build models for Template builders - if t, isTemplate := f.(file.Template); isTemplate { - if err := s.buildFileModel(t, universe.Files); err != nil { - return err - } - } - - // Build models for Inserter builders - if i, isInserter := f.(file.Inserter); isInserter { - if err := s.updateFileModel(i, universe.Files); err != nil { - return err - } - } - } - - // Execute plugins - for _, plugin := range s.plugins { - if err := plugin.Pipe(universe); err != nil { - return model.NewPluginError(err) - } - } - - // Persist the files to disk - for _, f := range universe.Files { - if err := s.writeFile(f); err != nil { - return err - } - } - - return nil -} - -// buildFileModel scaffolds a single file -func (scaffold) buildFileModel(t file.Template, models map[string]*file.File) error { - // Set the template default values - err := t.SetTemplateDefaults() - if err != nil { - return file.NewSetTemplateDefaultsError(err) - } - - // Handle already existing models - if _, found := models[t.GetPath()]; found { - switch t.GetIfExistsAction() { - case file.Skip: - return nil - case file.Error: - return modelAlreadyExistsError{t.GetPath()} - case file.Overwrite: - default: - return unknownIfExistsActionError{t.GetPath(), t.GetIfExistsAction()} - } - } - - m := &file.File{ - Path: t.GetPath(), - IfExistsAction: t.GetIfExistsAction(), - } - - b, err := doTemplate(t) - if err != nil { - return err - } - m.Contents = string(b) - - models[m.Path] = m - return nil -} - -// doTemplate executes the template for a file using the input -func doTemplate(t file.Template) ([]byte, error) { - temp, err := newTemplate(t).Parse(t.GetBody()) - if err != nil { - return nil, err - } - - out := &bytes.Buffer{} - err = temp.Execute(out, t) - if err != nil { - return nil, err - } - b := out.Bytes() - - // TODO(adirio): move go-formatting to write step - // gofmt the imports - if filepath.Ext(t.GetPath()) == ".go" { - b, err = imports.Process(t.GetPath(), b, &options) - if err != nil { - return nil, err - } - } - - return b, nil -} - -// newTemplate a new template with common functions -func newTemplate(t file.Template) *template.Template { - fm := file.DefaultFuncMap() - useFM, ok := t.(file.UseCustomFuncMap) - if ok { - fm = useFM.GetFuncMap() - } - return template.New(fmt.Sprintf("%T", t)).Funcs(fm) -} - -// updateFileModel updates a single file -func (s scaffold) updateFileModel(i file.Inserter, models map[string]*file.File) error { - m, err := s.loadPreviousModel(i, models) - if err != nil { - return err - } - - // Get valid code fragments - codeFragments := getValidCodeFragments(i) - - // Remove code fragments that already were applied - err = filterExistingValues(m.Contents, codeFragments) - if err != nil { - return err - } - - // If no code fragment to insert, we are done - if len(codeFragments) == 0 { - return nil - } - - content, err := insertStrings(m.Contents, codeFragments) - if err != nil { - return err - } - - // TODO(adirio): move go-formatting to write step - formattedContent := content - if ext := filepath.Ext(i.GetPath()); ext == ".go" { - formattedContent, err = imports.Process(i.GetPath(), content, nil) - if err != nil { - return err - } - } - - m.Contents = string(formattedContent) - m.IfExistsAction = file.Overwrite - models[m.Path] = m - return nil -} - -// loadPreviousModel gets the previous model from the models map or the actual file -func (s scaffold) loadPreviousModel(i file.Inserter, models map[string]*file.File) (*file.File, error) { - // Lets see if we already have a model for this file - if m, found := models[i.GetPath()]; found { - // Check if there is already an scaffolded file - exists, err := s.fs.Exists(i.GetPath()) - if err != nil { - return nil, err - } - - // If there is a model but no scaffolded file we return the model - if !exists { - return m, nil - } - - // If both a model and a file are found, check which has preference - switch m.IfExistsAction { - case file.Skip: - // File has preference - fromFile, err := s.loadModelFromFile(i.GetPath()) - if err != nil { - return m, nil - } - return fromFile, nil - case file.Error: - // Writing will result in an error, so we can return error now - return nil, fileAlreadyExistsError{i.GetPath()} - case file.Overwrite: - // Model has preference - return m, nil - default: - return nil, unknownIfExistsActionError{i.GetPath(), m.IfExistsAction} - } - } - - // There was no model - return s.loadModelFromFile(i.GetPath()) -} - -// loadModelFromFile gets the previous model from the actual file -func (s scaffold) loadModelFromFile(path string) (f *file.File, err error) { - reader, err := s.fs.Open(path) - if err != nil { - return - } - defer func() { - closeErr := reader.Close() - if err == nil { - err = closeErr - } - }() - - content, err := ioutil.ReadAll(reader) - if err != nil { - return - } - - f = &file.File{Path: path, Contents: string(content)} - return -} - -// getValidCodeFragments obtains the code fragments from a file.Inserter -func getValidCodeFragments(i file.Inserter) file.CodeFragmentsMap { - // Get the code fragments - codeFragments := i.GetCodeFragments() - - // Validate the code fragments - validMarkers := i.GetMarkers() - for marker := range codeFragments { - valid := false - for _, validMarker := range validMarkers { - if marker == validMarker { - valid = true - break - } - } - if !valid { - delete(codeFragments, marker) - } - } - - return codeFragments -} - -// filterExistingValues removes the single-line values that already exists -// TODO: Add support for multi-line duplicate values -func filterExistingValues(content string, codeFragmentsMap file.CodeFragmentsMap) error { - scanner := bufio.NewScanner(strings.NewReader(content)) - for scanner.Scan() { - line := scanner.Text() - for marker, codeFragments := range codeFragmentsMap { - for i, codeFragment := range codeFragments { - if strings.TrimSpace(line) == strings.TrimSpace(codeFragment) { - codeFragmentsMap[marker] = append(codeFragments[:i], codeFragments[i+1:]...) - } - } - if len(codeFragmentsMap[marker]) == 0 { - delete(codeFragmentsMap, marker) - } - } - } - if err := scanner.Err(); err != nil { - return err - } - return nil -} - -func insertStrings(content string, codeFragmentsMap file.CodeFragmentsMap) ([]byte, error) { - out := new(bytes.Buffer) - - scanner := bufio.NewScanner(strings.NewReader(content)) - for scanner.Scan() { - line := scanner.Text() - - for marker, codeFragments := range codeFragmentsMap { - if strings.TrimSpace(line) == strings.TrimSpace(marker.String()) { - for _, codeFragment := range codeFragments { - _, _ = out.WriteString(codeFragment) // bytes.Buffer.WriteString always returns nil errors - } - } - } - - _, _ = out.WriteString(line + "\n") // bytes.Buffer.WriteString always returns nil errors - } - if err := scanner.Err(); err != nil { - return nil, err - } - - return out.Bytes(), nil -} - -func (s scaffold) writeFile(f *file.File) error { - // Check if the file to write already exists - exists, err := s.fs.Exists(f.Path) - if err != nil { - return err - } - if exists { - switch f.IfExistsAction { - case file.Overwrite: - // By not returning, the file is written as if it didn't exist - case file.Skip: - // By returning nil, the file is not written but the process will carry on - return nil - case file.Error: - // By returning an error, the file is not written and the process will fail - return fileAlreadyExistsError{f.Path} - } - } - - writer, err := s.fs.Create(f.Path) - if err != nil { - return err - } - - _, err = writer.Write([]byte(f.Contents)) - - return err -} diff --git a/internal/kubebuilder/machinery/scaffold_test.go b/internal/kubebuilder/machinery/scaffold_test.go deleted file mode 100644 index d33f36b102d..00000000000 --- a/internal/kubebuilder/machinery/scaffold_test.go +++ /dev/null @@ -1,520 +0,0 @@ -/* -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package machinery - -import ( - "bytes" - "errors" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/ginkgo/extensions/table" - . "github.com/onsi/gomega" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" - - "github.com/operator-framework/operator-sdk/internal/kubebuilder/filesystem" -) - -var _ = Describe("Scaffold", func() { - Describe("NewScaffold", func() { - var ( - si Scaffold - s *scaffold - ok bool - ) - - It("should create a valid scaffold", func() { - By("passing no plugins") - si = NewScaffold() - s, ok = si.(*scaffold) - Expect(ok).To(BeTrue()) - Expect(s.fs).NotTo(BeNil()) - Expect(len(s.plugins)).To(Equal(0)) - - By("passing one plugin") - si = NewScaffold(fakePlugin{}) - s, ok = si.(*scaffold) - Expect(ok).To(BeTrue()) - Expect(s.fs).NotTo(BeNil()) - Expect(len(s.plugins)).To(Equal(1)) - - By("passing multiple plugins") - si = NewScaffold(fakePlugin{}, fakePlugin{}, fakePlugin{}) - s, ok = si.(*scaffold) - Expect(ok).To(BeTrue()) - Expect(s.fs).NotTo(BeNil()) - Expect(len(s.plugins)).To(Equal(3)) - }) - }) - - Describe("Scaffold.Execute", func() { - const fileContent = "Hello world!" - - var ( - output bytes.Buffer - testErr = errors.New("error text") - ) - - BeforeEach(func() { - output.Reset() - }) - - DescribeTable("successes", - func(expected string, files ...file.Builder) { - s := &scaffold{ - fs: filesystem.NewMock( - filesystem.MockOutput(&output), - ), - } - - Expect(s.Execute(model.NewUniverse(), files...)).To(Succeed()) - Expect(output.String()).To(Equal(expected)) - }, - Entry("should write the file", - fileContent, - fakeTemplate{body: fileContent}, - ), - Entry("should skip optional models if already have one", - fileContent, - fakeTemplate{body: fileContent}, - fakeTemplate{}, - ), - Entry("should overwrite required models if already have one", - fileContent, - fakeTemplate{}, - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: fileContent}, - ), - Entry("should format a go file", - "package file\n", - fakeTemplate{fakeBuilder: fakeBuilder{path: "file.go"}, body: "package file"}, - ), - ) - - DescribeTable("file builders related errors", - func(f func(error) bool, files ...file.Builder) { - s := &scaffold{fs: filesystem.NewMock()} - - Expect(f(s.Execute(model.NewUniverse(), files...))).To(BeTrue()) - }, - Entry("should fail if unable to validate a file builder", - file.IsValidateError, - fakeRequiresValidation{validateErr: testErr}, - ), - Entry("should fail if unable to set default values for a template", - file.IsSetTemplateDefaultsError, - fakeTemplate{err: testErr}, - ), - Entry("should fail if an unexpected previous model is found", - IsModelAlreadyExistsError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename"}}, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: file.Error}}, - ), - Entry("should fail if behavior if file exists is not defined", - IsUnknownIfExistsActionError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename"}}, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: -1}}, - ), - ) - - // Following errors are unwrapped, so we need to check for substrings - DescribeTable("template related errors", - func(errMsg string, files ...file.Builder) { - s := &scaffold{fs: filesystem.NewMock()} - - err := s.Execute(model.NewUniverse(), files...) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring(errMsg)) - }, - Entry("should fail if a template is broken", - "template: ", - fakeTemplate{body: "{{ .Field }"}, - ), - Entry("should fail if a template params aren't provided", - "template: ", - fakeTemplate{body: "{{ .Field }}"}, - ), - Entry("should fail if unable to format a go file", - "expected 'package', found ", - fakeTemplate{fakeBuilder: fakeBuilder{path: "file.go"}, body: fileContent}, - ), - ) - - DescribeTable("insert strings", - func(input, expected string, files ...file.Builder) { - s := &scaffold{ - fs: filesystem.NewMock( - filesystem.MockInput(bytes.NewBufferString(input)), - filesystem.MockOutput(&output), - filesystem.MockExists(func(_ string) bool { return len(input) != 0 }), - ), - } - - Expect(s.Execute(model.NewUniverse(), files...)).To(Succeed()) - Expect(output.String()).To(Equal(expected)) - }, - Entry("should insert lines for go files", - ` -//+kubebuilder:scaffold:- -`, - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should insert lines for yaml files", - ` -#+kubebuilder:scaffold:- -`, - ` -1 -2 -#+kubebuilder:scaffold:- -`, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.yaml", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should use models if there is no file", - "", - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: ` -//+kubebuilder:scaffold:- -`}, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should use required models over files", - fileContent, - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: ` -//+kubebuilder:scaffold:- -`}, - fakeInserter{codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}}, - }, - ), - Entry("should use files over optional models", - ` -//+kubebuilder:scaffold:- -`, - ` -1 -2 -//+kubebuilder:scaffold:- -`, - fakeTemplate{body: fileContent}, - fakeInserter{ - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}, - }, - }, - ), - Entry("should filter invalid markers", - ` -//+kubebuilder:scaffold:- -//+kubebuilder:scaffold:* -`, - ` -1 -2 -//+kubebuilder:scaffold:- -//+kubebuilder:scaffold:* -`, - fakeInserter{ - markers: []file.Marker{file.NewMarkerFor("file.go", "-")}, - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}, - file.NewMarkerFor("file.go", "*"): {"3\n", "4\n"}, - }, - }, - ), - Entry("should filter already existing one-line code fragments", - ` -1 -//+kubebuilder:scaffold:- -3 -4 -//+kubebuilder:scaffold:* -`, - ` -1 -2 -//+kubebuilder:scaffold:- -3 -4 -//+kubebuilder:scaffold:* -`, - fakeInserter{ - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {"1\n", "2\n"}, - file.NewMarkerFor("file.go", "*"): {"3\n", "4\n"}, - }, - }, - ), - Entry("should not insert anything if no code fragment", - "", // input is provided through a template as mock fs doesn't copy it to the output buffer if no-op - ` -//+kubebuilder:scaffold:- -`, - fakeTemplate{body: ` -//+kubebuilder:scaffold:- -`}, - fakeInserter{ - codeFragments: file.CodeFragmentsMap{ - file.NewMarkerFor("file.go", "-"): {}, - }, - }, - ), - ) - - DescribeTable("insert strings related errors", - func(f func(error) bool, files ...file.Builder) { - s := &scaffold{ - fs: filesystem.NewMock( - filesystem.MockExists(func(_ string) bool { return true }), - ), - } - - err := s.Execute(model.NewUniverse(), files...) - Expect(err).To(HaveOccurred()) - Expect(f(err)).To(BeTrue()) - }, - Entry("should fail if inserting into a model that fails when a file exists and it does exist", - IsFileAlreadyExistsError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: file.Error}}, - fakeInserter{fakeBuilder: fakeBuilder{path: "filename"}}, - ), - Entry("should fail if inserting into a model with unknown behavior if the file exists and it does exist", - IsUnknownIfExistsActionError, - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: -1}}, - fakeInserter{fakeBuilder: fakeBuilder{path: "filename"}}, - ), - ) - - It("should fail if a plugin fails", func() { - s := &scaffold{ - fs: filesystem.NewMock(), - plugins: []model.Plugin{fakePlugin{err: testErr}}, - } - - err := s.Execute( - model.NewUniverse(), - fakeTemplate{}, - ) - Expect(err).To(MatchError(testErr)) - Expect(model.IsPluginError(err)).To(BeTrue()) - }) - - Context("write when the file already exists", func() { - var s Scaffold - - BeforeEach(func() { - s = &scaffold{ - fs: filesystem.NewMock( - filesystem.MockExists(func(_ string) bool { return true }), - filesystem.MockOutput(&output), - ), - } - }) - - It("should skip the file by default", func() { - Expect(s.Execute( - model.NewUniverse(), - fakeTemplate{body: fileContent}, - )).To(Succeed()) - Expect(output.String()).To(BeEmpty()) - }) - - It("should write the file if configured to do so", func() { - Expect(s.Execute( - model.NewUniverse(), - fakeTemplate{fakeBuilder: fakeBuilder{ifExistsAction: file.Overwrite}, body: fileContent}, - )).To(Succeed()) - Expect(output.String()).To(Equal(fileContent)) - }) - - It("should error if configured to do so", func() { - err := s.Execute( - model.NewUniverse(), - fakeTemplate{fakeBuilder: fakeBuilder{path: "filename", ifExistsAction: file.Error}, body: fileContent}, - ) - Expect(err).To(HaveOccurred()) - Expect(IsFileAlreadyExistsError(err)).To(BeTrue()) - Expect(output.String()).To(BeEmpty()) - }) - }) - - DescribeTable("filesystem errors", - func( - mockErrorF func(error) filesystem.MockOptions, - checkErrorF func(error) bool, - files ...file.Builder, - ) { - s := &scaffold{ - fs: filesystem.NewMock( - mockErrorF(testErr), - ), - } - - err := s.Execute(model.NewUniverse(), files...) - Expect(err).To(HaveOccurred()) - Expect(checkErrorF(err)).To(BeTrue()) - }, - Entry("should fail if fs.Exists failed (at file writing)", - filesystem.MockExistsError, filesystem.IsFileExistsError, - fakeTemplate{}, - ), - Entry("should fail if fs.Exists failed (at model updating)", - filesystem.MockExistsError, filesystem.IsFileExistsError, - fakeTemplate{}, - fakeInserter{}, - ), - Entry("should fail if fs.Open was unable to open the file", - filesystem.MockOpenFileError, filesystem.IsOpenFileError, - fakeInserter{}, - ), - Entry("should fail if fs.Open().Read was unable to read the file", - filesystem.MockReadFileError, filesystem.IsReadFileError, - fakeInserter{}, - ), - Entry("should fail if fs.Open().Close was unable to close the file", - filesystem.MockCloseFileError, filesystem.IsCloseFileError, - fakeInserter{}, - ), - Entry("should fail if fs.Create was unable to create the directory", - filesystem.MockCreateDirError, filesystem.IsCreateDirectoryError, - fakeTemplate{}, - ), - Entry("should fail if fs.Create was unable to create the file", - filesystem.MockCreateFileError, filesystem.IsCreateFileError, - fakeTemplate{}, - ), - Entry("should fail if fs.Create().Write was unable to write the file", - filesystem.MockWriteFileError, filesystem.IsWriteFileError, - fakeTemplate{}, - ), - Entry("should fail if fs.Create().Write was unable to close the file", - filesystem.MockCloseFileError, filesystem.IsCloseFileError, - fakeTemplate{}, - ), - ) - }) -}) - -var _ model.Plugin = fakePlugin{} - -// fakePlugin is used to mock a model.Plugin in order to test Scaffold -type fakePlugin struct { - err error -} - -// Pipe implements model.Plugin -func (f fakePlugin) Pipe(_ *model.Universe) error { - return f.err -} - -var _ file.Builder = fakeBuilder{} - -// fakeBuilder is used to mock a file.Builder -type fakeBuilder struct { - path string - ifExistsAction file.IfExistsAction -} - -// GetPath implements file.Builder -func (f fakeBuilder) GetPath() string { - return f.path -} - -// GetIfExistsAction implements file.Builder -func (f fakeBuilder) GetIfExistsAction() file.IfExistsAction { - return f.ifExistsAction -} - -var _ file.RequiresValidation = fakeRequiresValidation{} - -// fakeRequiresValidation is used to mock a file.RequiresValidation in order to test Scaffold -type fakeRequiresValidation struct { - fakeBuilder - - validateErr error -} - -// Validate implements file.RequiresValidation -func (f fakeRequiresValidation) Validate() error { - return f.validateErr -} - -var _ file.Template = fakeTemplate{} - -// fakeTemplate is used to mock a file.File in order to test Scaffold -type fakeTemplate struct { - fakeBuilder - - body string - err error -} - -// GetBody implements file.Template -func (f fakeTemplate) GetBody() string { - return f.body -} - -// SetTemplateDefaults implements file.Template -func (f fakeTemplate) SetTemplateDefaults() error { - if f.err != nil { - return f.err - } - - return nil -} - -type fakeInserter struct { - fakeBuilder - - markers []file.Marker - codeFragments file.CodeFragmentsMap -} - -// GetMarkers implements file.UpdatableTemplate -func (f fakeInserter) GetMarkers() []file.Marker { - if f.markers != nil { - return f.markers - } - - markers := make([]file.Marker, 0, len(f.codeFragments)) - for marker := range f.codeFragments { - markers = append(markers, marker) - } - return markers -} - -// GetCodeFragments implements file.UpdatableTemplate -func (f fakeInserter) GetCodeFragments() file.CodeFragmentsMap { - return f.codeFragments -} diff --git a/internal/plugins/ansible/v1/api.go b/internal/plugins/ansible/v1/api.go index fed6d81c798..ff52b1a0d59 100644 --- a/internal/plugins/ansible/v1/api.go +++ b/internal/plugins/ansible/v1/api.go @@ -15,43 +15,53 @@ package ansible import ( + "errors" "fmt" - "strings" + "github.com/spf13/afero" "github.com/spf13/pflag" "sigs.k8s.io/kubebuilder/v3/pkg/config" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds" - "github.com/operator-framework/operator-sdk/internal/plugins/manifests" - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" ) const ( - groupFlag = "group" - versionFlag = "version" - kindFlag = "kind" - crdVersionFlag = "crd-version" + crdVersionFlag = "crd-version" + generatePlaybookFlag = "generate-playbook" + generateRoleFlag = "generate-role" - crdVersionV1 = "v1" - crdVersionV1beta1 = "v1beta1" + defaultCrdVersionFlagValue = "v1" ) -type createAPIPSubcommand struct { - config config.Config - createOptions scaffolds.CreateOptions +type createAPIOptions struct { + CRDVersion string + GeneratePlaybook bool + GenerateRole bool } -var ( - _ plugin.CreateAPISubcommand = &createAPIPSubcommand{} - _ cmdutil.RunOptions = &createAPIPSubcommand{} -) +func (opts createAPIOptions) UpdateResource(res *resource.Resource) { + res.API = &resource.API{ + CRDVersion: opts.CRDVersion, + Namespaced: true, + } + + // Ensure that Path is empty and Controller false + res.Path = "" + res.Controller = false +} + +var _ plugin.CreateAPISubcommand = &createAPISubcommand{} + +type createAPISubcommand struct { + config config.Config + resource *resource.Resource + options createAPIOptions +} -// UpdateContext injects documentation for the command -func (p *createAPIPSubcommand) UpdateContext(ctx *plugin.Context) { - ctx.Description = `Scaffold a Kubernetes API in which the controller is an Ansible role or playbook. +func (p *createAPISubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { + subcmdMeta.Description = `Scaffold a Kubernetes API in which the controller is an Ansible role or playbook. - generates a Custom Resource Definition and sample - Updates watches.yaml @@ -61,112 +71,70 @@ func (p *createAPIPSubcommand) UpdateContext(ctx *plugin.Context) { For the scaffolded operator to be runnable with no changes, specify either --generate-role or --generate-playbook. ` - ctx.Examples = fmt.Sprintf(`# Create a new API, without Ansible roles or playbooks - $ %s create api \ + subcmdMeta.Examples = fmt.Sprintf(`# Create a new API, without Ansible roles or playbooks + $ %[1]s create api \ --group=apps --version=v1alpha1 \ --kind=AppService - $ %s create api \ + $ %[1]s create api \ --group=apps --version=v1alpha1 \ --kind=AppService \ --generate-role - $ %s create api \ + $ %[1]s create api \ --group=apps --version=v1alpha1 \ --kind=AppService \ --generate-playbook - $ %s create api \ + $ %[1]s create api \ --group=apps --version=v1alpha1 \ --kind=AppService --generate-playbook --generate-role -`, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ) +`, cliMeta.CommandName) } -func (p *createAPIPSubcommand) BindFlags(fs *pflag.FlagSet) { +func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { fs.SortFlags = false - fs.StringVar(&p.createOptions.GVK.Group, groupFlag, "", "resource group") - fs.StringVar(&p.createOptions.GVK.Version, versionFlag, "", "resource version") - fs.StringVar(&p.createOptions.GVK.Kind, kindFlag, "", "resource kind") - fs.StringVar(&p.createOptions.CRDVersion, crdVersionFlag, crdVersionV1, "crd version to generate") - fs.BoolVarP(&p.createOptions.GeneratePlaybook, "generate-playbook", "", false, "Generate an Ansible playbook. If passed with --generate-role, the playbook will invoke the role.") - fs.BoolVarP(&p.createOptions.GenerateRole, "generate-role", "", false, "Generate an Ansible role skeleton.") + fs.StringVar(&p.options.CRDVersion, crdVersionFlag, defaultCrdVersionFlagValue, "crd version to generate") + fs.BoolVar(&p.options.GeneratePlaybook, generatePlaybookFlag, false, "Generate an Ansible playbook. If passed with --generate-role, the playbook will invoke the role.") + fs.BoolVar(&p.options.GenerateRole, generateRoleFlag, false, "Generate an Ansible role skeleton.") } -func (p *createAPIPSubcommand) InjectConfig(c config.Config) { +func (p *createAPISubcommand) InjectConfig(c config.Config) error { p.config = c -} - -func (p *createAPIPSubcommand) Run() error { - if err := cmdutil.Run(p); err != nil { - return err - } - - // Run SDK phase 2 plugins. - if err := p.runPhase2(); err != nil { - return err - } return nil } -// SDK phase 2 plugins. -func (p *createAPIPSubcommand) runPhase2() error { - ogvk := p.createOptions.GVK - gvk := resource.GVK{Group: ogvk.Group, Version: ogvk.Version, Kind: ogvk.Kind} - - // Initially the ansible/v1 plugin was written to not create a "plugins" config entry - // for any phase 2 plugin because they did not have their own keys. Now there are phase 2 - // plugin keys, so those plugins should be run if keys exist. Otherwise, enact old behavior. - - if manifestsv2.HasPluginConfig(p.config) { - if err := manifestsv2.RunCreateAPI(p.config, gvk); err != nil { - return err - } - } else { - if err := manifests.RunCreateAPI(p.config, gvk); err != nil { - return err - } - } +func (p *createAPISubcommand) InjectResource(res *resource.Resource) error { + p.resource = res - return nil -} + p.options.UpdateResource(p.resource) -func (p *createAPIPSubcommand) Validate() error { - if p.createOptions.CRDVersion != crdVersionV1 && p.createOptions.CRDVersion != crdVersionV1beta1 { - return fmt.Errorf("value of --%s must be either %q or %q", crdVersionFlag, crdVersionV1, crdVersionV1beta1) + if err := p.resource.Validate(); err != nil { + return err } - if len(strings.TrimSpace(p.createOptions.GVK.Group)) == 0 { - return fmt.Errorf("value of --%s must not have empty value", groupFlag) - } - if len(strings.TrimSpace(p.createOptions.GVK.Version)) == 0 { - return fmt.Errorf("value of --%s must not have empty value", versionFlag) - } - if len(strings.TrimSpace(p.createOptions.GVK.Kind)) == 0 { - return fmt.Errorf("value of --%s must not have empty value", kindFlag) + // Check that resource doesn't have the API scaffolded + if res, err := p.config.GetResource(p.resource.GVK); err == nil && res.HasAPI() { + return errors.New("the API resource already exists") } - // Validate the resource. - ogvk := p.createOptions.GVK - gvk := resource.GVK{Group: ogvk.Group, Version: ogvk.Version, Kind: ogvk.Kind} - if err := gvk.Validate(); err != nil { - return err + // Check that the provided group can be added to the project + if !p.config.IsMultiGroup() && p.config.ResourcesLength() != 0 && !p.config.HasGroup(p.resource.Group) { + return fmt.Errorf("multiple groups are not allowed by default, to enable multi-group set 'multigroup: true' in your PROJECT file") } return nil } -func (p *createAPIPSubcommand) GetScaffolder() (cmdutil.Scaffolder, error) { - return scaffolds.NewCreateAPIScaffolder(p.config, p.createOptions), nil -} +func (p *createAPISubcommand) Scaffold(fs afero.Fs) error { + scaffolder := scaffolds.NewCreateAPIScaffolder(p.config, *p.resource, p.options.GeneratePlaybook, p.options.GenerateRole) + scaffolder.InjectFS(fs) + if err := scaffolder.Scaffold(); err != nil { + return err + } -func (p *createAPIPSubcommand) PostScaffold() error { return nil } diff --git a/internal/plugins/ansible/v1/init.go b/internal/plugins/ansible/v1/init.go index 158b5913f2a..6fe55a18cc3 100644 --- a/internal/plugins/ansible/v1/init.go +++ b/internal/plugins/ansible/v1/init.go @@ -20,38 +20,47 @@ import ( "path/filepath" "strings" + "github.com/spf13/afero" "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/util/validation" + "sigs.k8s.io/kubebuilder/v3/pkg/cli" "sigs.k8s.io/kubebuilder/v3/pkg/config" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery/util" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds" - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" - scorecardv2 "github.com/operator-framework/operator-sdk/internal/plugins/scorecard/v2" ) +const ( + groupFlag = "group" + versionFlag = "version" + kindFlag = "kind" + + defaultGroupFlagValue = "" + defaultVersionFlagValue = "" + defaultKindFlagValue = "" +) + +var _ plugin.InitSubcommand = &initSubcommand{} + type initSubcommand struct { - config config.Config - apiPlugin createAPIPSubcommand - options *golang.Options + // Wrapped plugin that we will call at post-scaffold + apiSubcommand createAPISubcommand + + config config.Config // For help text. commandName string // Flags + options cli.ResourceOptions + domain string projectName string } -var ( - _ plugin.InitSubcommand = &initSubcommand{} - _ cmdutil.RunOptions = &initSubcommand{} -) - // UpdateContext injects documentation for the command -func (p *initSubcommand) UpdateContext(ctx *plugin.Context) { - ctx.Description = ` +func (p *initSubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { + subcmdMeta.Description = ` Initialize a new Ansible-based operator project. Writes the following files @@ -62,7 +71,7 @@ Writes the following files Optionally creates a new API, using the same flags as "create api" ` - ctx.Examples = fmt.Sprintf(` + subcmdMeta.Examples = fmt.Sprintf(` # Scaffold a project with no API $ %[1]s init --plugins=%[2]s --domain=my.domain \ @@ -86,106 +95,81 @@ Optionally creates a new API, using the same flags as "create api" --group=apps --version=v1alpha1 --kind=AppService \ --generate-playbook \ --generate-role -`, - ctx.CommandName, pluginKey, - ) - p.commandName = ctx.CommandName +`, cliMeta.CommandName, pluginKey) + + p.commandName = cliMeta.CommandName } func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { fs.SortFlags = false - p.options = &golang.Options{} - fs.StringVar(&p.options.Domain, "domain", "my.domain", "domain for groups") + fs.StringVar(&p.domain, "domain", "my.domain", "domain for groups") fs.StringVar(&p.projectName, "project-name", "", "name of this project, the default being directory name") - p.apiPlugin.BindFlags(fs) -} -func (p *initSubcommand) InjectConfig(c config.Config) { - _ = c.SetLayout(pluginKey) - p.config = c - p.apiPlugin.config = p.config + fs.StringVar(&p.options.Group, "group", "", "resource Group") + fs.StringVar(&p.options.Version, "version", "", "resource Version") + fs.StringVar(&p.options.Kind, "kind", "", "resource Kind") + p.apiSubcommand.BindFlags(fs) } -func (p *initSubcommand) Run() error { - if err := cmdutil.Run(p); err != nil { - return err - } - - // Run SDK phase 2 plugins. - if err := p.runPhase2(); err != nil { - return err - } - - return nil -} - -// SDK phase 2 plugins. -func (p *initSubcommand) runPhase2() error { - if err := manifestsv2.RunInit(p.config); err != nil { - return err - } - if err := scorecardv2.RunInit(p.config); err != nil { - return err - } - - if p.options.DoAPI { - if err := p.apiPlugin.runPhase2(); err != nil { - return err - } - } - - return nil -} +func (p *initSubcommand) InjectConfig(c config.Config) error { + p.config = c -func (p *initSubcommand) Validate() error { - // Set values in the config - if err := p.config.SetProjectName(p.projectName); err != nil { - return err - } - if err := p.config.SetDomain(p.options.Domain); err != nil { + if err := p.config.SetDomain(p.domain); err != nil { return err } - // Check if the project name is a valid k8s namespace (DNS 1123 label). - if p.config.GetProjectName() == "" { + // Assign a default project name + if p.projectName == "" { dir, err := os.Getwd() if err != nil { return fmt.Errorf("error getting current directory: %v", err) } - - if err := p.config.SetProjectName(strings.ToLower(filepath.Base(dir))); err != nil { - return err - } + p.projectName = strings.ToLower(filepath.Base(dir)) } - if err := validation.IsDNS1123Label(p.config.GetProjectName()); err != nil { - return fmt.Errorf("project name (%s) is invalid: %v", p.config.GetProjectName(), err) + // Check if the project name is a valid k8s namespace (DNS 1123 label). + if err := validation.IsDNS1123Label(p.projectName); err != nil { + return fmt.Errorf("project name (%s) is invalid: %v", p.projectName, err) } - - defaultOpts := scaffolds.CreateOptions{CRDVersion: "v1"} - if !p.apiPlugin.createOptions.GVK.Empty() || p.apiPlugin.createOptions != defaultOpts { - p.options.DoAPI = true - return p.apiPlugin.Validate() + if err := p.config.SetProjectName(p.projectName); err != nil { + return err } + return nil } -func (p *initSubcommand) GetScaffolder() (cmdutil.Scaffolder, error) { - var ( - apiScaffolder cmdutil.Scaffolder - err error - ) - if p.options.DoAPI { - apiScaffolder, err = p.apiPlugin.GetScaffolder() - if err != nil { - return nil, err - } - } - return scaffolds.NewInitScaffolder(p.config, apiScaffolder), nil +func (p *initSubcommand) Scaffold(fs afero.Fs) error { + scaffolder := scaffolds.NewInitScaffolder(p.config) + scaffolder.InjectFS(fs) + return scaffolder.Scaffold() } func (p *initSubcommand) PostScaffold() error { - if !p.options.DoAPI { + doAPI := p.options.Group != "" || p.options.Version != "" || p.options.Kind != "" + if !doAPI { fmt.Printf("Next: define a resource with:\n$ %s create api\n", p.commandName) + } else { + args := []string{"create", "api"} + if p.options.Group != defaultGroupFlagValue { + args = append(args, fmt.Sprintf("--%s", groupFlag), p.options.Group) + } + if p.options.Version != defaultVersionFlagValue { + args = append(args, fmt.Sprintf("--%s", versionFlag), p.options.Version) + } + if p.options.Kind != defaultKindFlagValue { + args = append(args, fmt.Sprintf("--%s", kindFlag), p.options.Kind) + } + if p.apiSubcommand.options.CRDVersion != defaultCrdVersionFlagValue { + args = append(args, fmt.Sprintf("--%s", crdVersionFlag), p.apiSubcommand.options.CRDVersion) + } + if p.apiSubcommand.options.GeneratePlaybook { + args = append(args, fmt.Sprintf("--%s", generatePlaybookFlag)) + } + if p.apiSubcommand.options.GenerateRole { + args = append(args, fmt.Sprintf("--%s", generateRoleFlag)) + } + if err := util.RunCmd("Creating the API", os.Args[0], args...); err != nil { + return err + } } return nil diff --git a/internal/plugins/ansible/v1/plugin.go b/internal/plugins/ansible/v1/plugin.go index 5b25a85e961..85b5c256894 100644 --- a/internal/plugins/ansible/v1/plugin.go +++ b/internal/plugins/ansible/v1/plugin.go @@ -16,13 +16,13 @@ package ansible import ( "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" "github.com/operator-framework/operator-sdk/internal/plugins" - cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" ) -const pluginName = "ansible" + plugins.DefaultNameQualifier +const pluginName = "base.ansible" + plugins.DefaultNameQualifier var ( supportedProjectVersions = []config.Version{cfgv3.Version} @@ -38,11 +38,11 @@ var ( type Plugin struct { initSubcommand - createAPIPSubcommand + createAPISubcommand } func (Plugin) Name() string { return pluginName } func (Plugin) Version() plugin.Version { return pluginVersion } func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions } func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { return &p.initSubcommand } -func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { return &p.createAPIPSubcommand } +func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { return &p.createAPISubcommand } diff --git a/internal/plugins/ansible/v1/scaffolds/api.go b/internal/plugins/ansible/v1/scaffolds/api.go index f86ef2784d9..3b3e7a8cf9e 100644 --- a/internal/plugins/ansible/v1/scaffolds/api.go +++ b/internal/plugins/ansible/v1/scaffolds/api.go @@ -18,17 +18,12 @@ limitations under the License. package scaffolds import ( - "errors" - - "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/spf13/afero" "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" + "sigs.k8s.io/kubebuilder/v3/pkg/plugins" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds/internal/templates" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd" @@ -39,94 +34,58 @@ import ( ansibleroles "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds/internal/templates/roles" ) -var _ cmdutil.Scaffolder = &apiScaffolder{} - -type CreateOptions struct { - GVK schema.GroupVersionKind - // CRDVersion is the version of the `apiextensions.k8s.io` API which will be used to generate the CRD. - CRDVersion string - GeneratePlaybook bool - GenerateRole bool -} +var _ plugins.Scaffolder = &apiScaffolder{} type apiScaffolder struct { - config config.Config - opts CreateOptions + fs afero.Fs + + config config.Config + resource resource.Resource + generatePlaybook bool + generateRole bool } -// NewCreateAPIScaffolder returns a new Scaffolder for project initialization operations -func NewCreateAPIScaffolder(config config.Config, opts CreateOptions) cmdutil.Scaffolder { +// NewCreateAPIScaffolder returns a new plugins.Scaffolder for project initialization operations +func NewCreateAPIScaffolder(cfg config.Config, res resource.Resource, generatePlaybook, generateRole bool) plugins.Scaffolder { return &apiScaffolder{ - config: config, - opts: opts, + config: cfg, + resource: res, + generatePlaybook: generatePlaybook, + generateRole: generateRole, } } -func (s *apiScaffolder) newUniverse(r *resource.Resource) *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - model.WithResource(r), - ) +// InjectFS implements plugins.Scaffolder +func (s *apiScaffolder) InjectFS(fs afero.Fs) { + s.fs = fs } -// Scaffold implements Scaffolder +// Scaffold implements plugins.Scaffolder func (s *apiScaffolder) Scaffold() error { - return s.scaffold() -} - -func (s *apiScaffolder) scaffold() error { - resourceOptions := &golang.Options{} - resourceOptions.DoAPI = true - resourceOptions.Group = s.opts.GVK.Group - resourceOptions.Version = s.opts.GVK.Version - resourceOptions.Kind = s.opts.GVK.Kind - - //todo(camilamacedo86): replace the options by kubernetes-sigs/kubebuilder#1974 - if err := resourceOptions.Validate(); err != nil { + if err := s.config.UpdateResource(s.resource); err != nil { return err } - // Check that resource doesn't exist - if s.config.HasResource(resourceOptions.GVK()) { - return errors.New("the API resource already exists") - } - - // Check that the provided group can be added to the project - if !s.config.IsMultiGroup() && s.config.ResourcesLength() != 0 && !s.config.HasGroup(resourceOptions.Group) { - return errors.New("multiple groups are not allowed by default, to enable multi-group set 'multigroup: true' in your PROJECT file") - } - - resource := resourceOptions.NewResource(s.config) - - resource.Domain = s.config.GetDomain() - - // remove the path since is not a Golang project - resource.Path = "" - - // add the resource API info to complain with project-version=3 - // todo: ensure that this information is properly returned from - // resource.newResource in upstream ( see kubernetes-sigs/kubebuilder#1974) - // and then, remove it. - resource.API.Namespaced = true - resource.API.CRDVersion = s.opts.CRDVersion - - if err := s.config.UpdateResource(resource); err != nil { - return err - } + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(s.fs, + machinery.WithConfig(s.config), + machinery.WithResource(&s.resource), + ) - var createAPITemplates []file.Builder + var createAPITemplates []machinery.Builder createAPITemplates = append(createAPITemplates, &rbac.CRDViewerRole{}, &rbac.CRDEditorRole{}, &rbac.ManagerRoleUpdater{}, - &crd.CRD{CRDVersion: s.opts.CRDVersion}, + &crd.CRD{}, &crd.Kustomization{}, &samples.CR{}, - &templates.WatchesUpdater{GeneratePlaybook: s.opts.GeneratePlaybook, GenerateRole: s.opts.GenerateRole, PlaybooksDir: constants.PlaybooksDir}, + &templates.WatchesUpdater{GeneratePlaybook: s.generatePlaybook, GenerateRole: s.generateRole, PlaybooksDir: constants.PlaybooksDir}, &mdefault.ResourceTest{}, ) - if s.opts.GenerateRole { + + if s.generateRole { createAPITemplates = append(createAPITemplates, &ansibleroles.TasksMain{}, &ansibleroles.DefaultsMain{}, @@ -139,12 +98,10 @@ func (s *apiScaffolder) scaffold() error { ) } - if s.opts.GeneratePlaybook { + if s.generatePlaybook { createAPITemplates = append(createAPITemplates, - &playbooks.Playbook{GenerateRole: s.opts.GenerateRole}) + &playbooks.Playbook{GenerateRole: s.generateRole}) } - return machinery.NewScaffold().Execute( - s.newUniverse(&resource), - createAPITemplates..., - ) + + return scaffold.Execute(createAPITemplates...) } diff --git a/internal/plugins/ansible/v1/scaffolds/init.go b/internal/plugins/ansible/v1/scaffolds/init.go index e3c0c4d3b27..1e23a5d4dd7 100644 --- a/internal/plugins/ansible/v1/scaffolds/init.go +++ b/internal/plugins/ansible/v1/scaffolds/init.go @@ -18,11 +18,11 @@ limitations under the License. package scaffolds import ( + "github.com/spf13/afero" "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" + "sigs.k8s.io/kubebuilder/v3/pkg/plugins" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds/internal/templates" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager" @@ -47,41 +47,34 @@ const ( // ansibleOperatorVersion is set to the version of ansible-operator at compile-time. var ansibleOperatorVersion = version.ImageVersion -var _ cmdutil.Scaffolder = &initScaffolder{} +var _ plugins.Scaffolder = &initScaffolder{} type initScaffolder struct { - config config.Config - apiScaffolder cmdutil.Scaffolder + config config.Config + + fs afero.Fs } -// NewInitScaffolder returns a new Scaffolder for project initialization operations -func NewInitScaffolder(config config.Config, apiScaffolder cmdutil.Scaffolder) cmdutil.Scaffolder { +// NewInitScaffolder returns a new plugins.Scaffolder for project initialization operations +func NewInitScaffolder(config config.Config) plugins.Scaffolder { return &initScaffolder{ - config: config, - apiScaffolder: apiScaffolder, + config: config, } } -func (s *initScaffolder) newUniverse() *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - ) +// InjectFS implements plugins.Scaffolder +func (s *initScaffolder) InjectFS(fs afero.Fs) { + s.fs = fs } -// Scaffold implements Scaffolder +// Scaffold implements plugins.Scaffolder func (s *initScaffolder) Scaffold() error { - if err := s.scaffold(); err != nil { - return err - } - if s.apiScaffolder != nil { - return s.apiScaffolder.Scaffold() - } - return nil -} + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(s.fs, + machinery.WithConfig(s.config), + ) -func (s *initScaffolder) scaffold() error { - return machinery.NewScaffold().Execute( - s.newUniverse(), + return scaffold.Execute( &templates.Dockerfile{AnsibleOperatorVersion: ansibleOperatorVersion}, &templates.Makefile{ Image: imageName, diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/crd.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/crd.go index 842a1ae0b85..cbaf6064c10 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/crd.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/crd.go @@ -15,22 +15,19 @@ package crd import ( - "errors" "fmt" "path/filepath" "github.com/kr/text" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRD{} +var _ machinery.Template = &CRD{} // CRD scaffolds a manifest for CRD sample. type CRD struct { - file.TemplateMixin - file.ResourceMixin - - CRDVersion string + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template @@ -40,22 +37,18 @@ func (f *CRD) SetTemplateDefaults() error { } f.Path = f.Resource.Replacer().Replace(f.Path) - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error - if f.CRDVersion == "" { - f.CRDVersion = "v1" - } else if f.CRDVersion != "v1" && f.CRDVersion != "v1beta1" { - return errors.New("the CRD version value must be either 'v1' or 'v1beta1'") - } f.TemplateBody = fmt.Sprintf(crdTemplate, text.Indent(openAPIV3SchemaTemplate, " "), text.Indent(openAPIV3SchemaTemplate, " "), ) + return nil } const crdTemplate = `--- -apiVersion: apiextensions.k8s.io/{{ .CRDVersion }} +apiVersion: apiextensions.k8s.io/{{ .Resource.API.CRDVersion }} kind: CustomResourceDefinition metadata: name: {{ .Resource.Plural }}.{{ .Resource.QualifiedGroup }} @@ -67,7 +60,7 @@ spec: plural: {{ .Resource.Plural }} singular: {{ .Resource.Kind | lower }} scope: Namespaced -{{- if eq .CRDVersion "v1beta1" }} +{{- if eq .Resource.API.CRDVersion "v1beta1" }} subresources: status: {} validation: @@ -75,13 +68,13 @@ spec: {{- end }} versions: - name: {{ .Resource.Version }} -{{- if eq .CRDVersion "v1" }} +{{- if eq .Resource.API.CRDVersion "v1" }} schema: %s {{- end }} served: true storage: true -{{- if eq .CRDVersion "v1" }} +{{- if eq .Resource.API.CRDVersion "v1" }} subresources: status: {} {{- end }} diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/kustomization.go index 7c0cc71def0..246c5c78b8e 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/crd/kustomization.go @@ -21,19 +21,21 @@ import ( "fmt" "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} -var _ file.Inserter = &Kustomization{} +var ( + _ machinery.Template = &Kustomization{} + _ machinery.Inserter = &Kustomization{} +) // Kustomization scaffolds the kustomization file in manager folder. type Kustomization struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } -// SetTemplateDefaults implements file.Template +// SetTemplateDefaults implements machinery.Template func (f *Kustomization) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("config", "crd", "kustomization.yaml") @@ -41,7 +43,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.Path = f.Resource.Replacer().Replace(f.Path) f.TemplateBody = fmt.Sprintf(kustomizationTemplate, - file.NewMarkerFor(f.Path, resourceMarker), + machinery.NewMarkerFor(f.Path, resourceMarker), ) return nil @@ -52,9 +54,9 @@ const ( ) // GetMarkers implements file.Inserter -func (f *Kustomization) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(f.Path, resourceMarker), +func (f *Kustomization) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(f.Path, resourceMarker), } } @@ -64,8 +66,8 @@ const ( ) // GetCodeFragments implements file.Inserter -func (f *Kustomization) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 3) +func (f *Kustomization) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 3) // Generate resource code fragments res := make([]string, 0) @@ -73,7 +75,7 @@ func (f *Kustomization) GetCodeFragments() file.CodeFragmentsMap { // Only store code fragments in the map if the slices are non-empty if len(res) != 0 { - fragments[file.NewMarkerFor(f.Path, resourceMarker)] = res + fragments[machinery.NewMarkerFor(f.Path, resourceMarker)] = res } return fragments diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go index 5c3a108670f..7d7d6be0490 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go @@ -20,16 +20,16 @@ package kdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyPatch{} +var _ machinery.Template = &AuthProxyPatch{} // AuthProxyPatch scaffolds the patch file for enabling // prometheus metrics for manager Pod. type AuthProxyPatch struct { - file.TemplateMixin - file.ProjectNameMixin + machinery.TemplateMixin + machinery.ProjectNameMixin } // SetTemplateDefaults implements input.Template @@ -40,7 +40,7 @@ func (f *AuthProxyPatch) SetTemplateDefaults() error { f.TemplateBody = kustomizeAuthProxyPatchTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/kustomization.go index d989e14e0b1..66815faebe7 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/kdefault/kustomization.go @@ -20,15 +20,15 @@ package kdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomize{} +var _ machinery.Template = &Kustomize{} // Kustomize scaffolds the Kustomization file for the default overlay type Kustomize struct { - file.TemplateMixin - file.ProjectNameMixin + machinery.TemplateMixin + machinery.ProjectNameMixin } // SetTemplateDefaults implements input.Template @@ -39,7 +39,7 @@ func (f *Kustomize) SetTemplateDefaults() error { f.TemplateBody = kustomizeTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/kustomization.go index 93dcfafae83..30b9adbc879 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/kustomization.go @@ -19,14 +19,14 @@ package manager import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the Kustomization file in manager folder. type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -37,7 +37,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.TemplateBody = kustomizeManagerTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/manager.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/manager.go index b9b44fd9b0e..fa03889399c 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/manager.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/manager/manager.go @@ -20,15 +20,15 @@ package manager import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Manager{} +var _ machinery.Template = &Manager{} // Manager scaffolds yaml config for the manager. type Manager struct { - file.TemplateMixin - file.ProjectNameMixin + machinery.TemplateMixin + machinery.ProjectNameMixin // Image is controller manager image name Image string diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/kustomization.go index a794eea1900..ce0149d0a98 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/kustomization.go @@ -19,14 +19,14 @@ package prometheus import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the kustomizaiton in the prometheus folder type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/monitor.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/monitor.go index 2055b94b875..99307ca0928 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/monitor.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/prometheus/monitor.go @@ -19,14 +19,14 @@ package prometheus import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ServiceMonitor{} +var _ machinery.Template = &ServiceMonitor{} // ServiceMonitor scaffolds an issuer CR and a certificate CR type ServiceMonitor struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_client_clusterrole.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_client_clusterrole.go index 6553210ce84..e6607501acf 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_client_clusterrole.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_client_clusterrole.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ClientClusterRole{} +var _ machinery.Template = &ClientClusterRole{} // ClientClusterRole scaffolds the config/rbac/client_clusterrole.yaml file type ClientClusterRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go index 2fb69db5d19..6b37da2a364 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyRole{} +var _ machinery.Template = &AuthProxyRole{} // AuthProxyRole scaffolds the config/rbac/auth_proxy_role.yaml file type AuthProxyRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go index 5c52caec328..3af80a15fdd 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyRoleBinding{} +var _ machinery.Template = &AuthProxyRoleBinding{} // AuthProxyRoleBinding scaffolds the config/rbac/auth_proxy_role_binding_rbac.yaml file type AuthProxyRoleBinding struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go index 25a0a52ac4c..0a64210c3ad 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyService{} +var _ machinery.Template = &AuthProxyService{} // AuthProxyService scaffolds the config/rbac/auth_proxy_service.yaml file type AuthProxyService struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go index 44b02767f2a..f20246b333b 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go @@ -19,15 +19,15 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRDEditorRole{} +var _ machinery.Template = &CRDEditorRole{} // CRDEditorRole scaffolds the config/rbac/_editor_role.yaml type CRDEditorRole struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go index 3dee9614946..171172c4d03 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go @@ -19,15 +19,15 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRDViewerRole{} +var _ machinery.Template = &CRDViewerRole{} // CRDViewerRole scaffolds the config/rbac/_viewer_role.yaml type CRDViewerRole struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go index 74c3ef6e050..7e994edbd06 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the Kustomization file in rbac folder. type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -37,7 +37,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.TemplateBody = kustomizeRBACTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go index f029a4286d3..279991608e6 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &LeaderElectionRole{} +var _ machinery.Template = &LeaderElectionRole{} // LeaderElectionRole scaffolds the config/rbac/leader_election_role.yaml file type LeaderElectionRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go index 994c3179d60..86402225ae7 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &LeaderElectionRoleBinding{} +var _ machinery.Template = &LeaderElectionRoleBinding{} // LeaderElectionRoleBinding scaffolds the config/rbac/leader_election_role_binding.yaml file type LeaderElectionRoleBinding struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go index 8ef6408bd5d..274ccb9f48e 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go @@ -20,16 +20,16 @@ import ( "path/filepath" "text/template" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ManagerRole{} +var _ machinery.Template = &ManagerRole{} var defaultRoleFile = filepath.Join("config", "rbac", "role.yaml") // ManagerRole scaffolds the role.yaml file type ManagerRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -39,16 +39,15 @@ func (f *ManagerRole) SetTemplateDefaults() error { } f.TemplateBody = fmt.Sprintf(roleTemplate, - file.NewMarkerFor(f.Path, rulesMarker), + machinery.NewMarkerFor(f.Path, rulesMarker), ) return nil } -var _ file.Inserter = &ManagerRoleUpdater{} +var _ machinery.Inserter = &ManagerRoleUpdater{} type ManagerRoleUpdater struct { - file.TemplateMixin - file.ResourceMixin + machinery.ResourceMixin SkipDefaultRules bool } @@ -57,22 +56,22 @@ func (*ManagerRoleUpdater) GetPath() string { return defaultRoleFile } -func (*ManagerRoleUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite +func (*ManagerRoleUpdater) GetIfExistsAction() machinery.IfExistsAction { + return machinery.OverwriteFile } const ( rulesMarker = "rules" ) -func (f *ManagerRoleUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(defaultRoleFile, rulesMarker), +func (f *ManagerRoleUpdater) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(defaultRoleFile, rulesMarker), } } -func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) +func (f *ManagerRoleUpdater) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 1) // If resource is not being provided we are creating the file, not updating it if f.Resource == nil { @@ -90,7 +89,7 @@ func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { rules := []string{buf.String()} if len(rules) != 0 { - fragments[file.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules + fragments[machinery.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules } return fragments } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role_binding.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role_binding.go index 0e236df0069..7b0bfc3de0f 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role_binding.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role_binding.go @@ -20,14 +20,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &RoleBinding{} +var _ machinery.Template = &RoleBinding{} // RoleBinding scaffolds the config/rbac/role_binding.yaml file type RoleBinding struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/samples/cr_sample.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/samples/cr_sample.go index d3356e540e4..df5fa59f12f 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/samples/cr_sample.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/samples/cr_sample.go @@ -22,16 +22,18 @@ import ( "strings" "text/template" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CR{} -var _ file.UseCustomFuncMap = &CR{} +var ( + _ machinery.Template = &CR{} + _ machinery.UseCustomFuncMap = &CR{} +) // CR scaffolds a sample manifest for a CRD. type CR struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin Spec string } @@ -43,7 +45,7 @@ func (f *CR) SetTemplateDefaults() error { } f.Path = f.Resource.Replacer().Replace(f.Path) - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error if len(f.Spec) == 0 { f.Spec = defaultSpecTemplate @@ -58,9 +60,9 @@ func indent(spaces int, v string) string { return pad + strings.Replace(v, "\n", "\n"+pad, -1) } -// GetFuncMap implements file.UseCustomFuncMap +// GetFuncMap implements machinery.UseCustomFuncMap func (f *CR) GetFuncMap() template.FuncMap { - fm := file.DefaultFuncMap() + fm := machinery.DefaultFuncMap() fm["indent"] = indent return fm } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/debug_logs_patch.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/debug_logs_patch.go index a93be5a0bde..c6eaf410485 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/debug_logs_patch.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/debug_logs_patch.go @@ -17,15 +17,15 @@ package testing import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &DebugLogsPatch{} +var _ machinery.Template = &DebugLogsPatch{} // DebugLogsPatch scaffolds the patch file for enabling // verbose logs during Ansible testing type DebugLogsPatch struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,7 +36,7 @@ func (f *DebugLogsPatch) SetTemplateDefaults() error { f.TemplateBody = debugLogsPatchTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/kustomization.go index c4894b2cdf5..e11fe8fc1db 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/kustomization.go @@ -17,15 +17,15 @@ package testing import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the kustomization file for use // during Ansible testing type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,7 +36,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.TemplateBody = KustomizationTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/manager_image.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/manager_image.go index 2c6d2e5092f..b4642690162 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/manager_image.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/manager_image.go @@ -17,15 +17,15 @@ package testing import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ManagerImage{} +var _ machinery.Template = &ManagerImage{} // ManagerImage scaffolds the patch file for overriding the // default image during Ansible testing type ManagerImage struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,7 +36,7 @@ func (f *ManagerImage) SetTemplateDefaults() error { f.TemplateBody = managerImageTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/always_pull_patch.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/always_pull_patch.go index f592b42e105..8c4091eab6a 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/always_pull_patch.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/always_pull_patch.go @@ -17,15 +17,15 @@ package pullpolicy import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AlwaysPullPatch{} +var _ machinery.Template = &AlwaysPullPatch{} // AlwaysPullPatch scaffolds the patch file for overriding the // default image pull policy during Ansible testing type AlwaysPullPatch struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,7 +36,7 @@ func (f *AlwaysPullPatch) SetTemplateDefaults() error { f.TemplateBody = alwaysPullPatchTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/ifnotpresent_pull_patch.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/ifnotpresent_pull_patch.go index 61ef319a18a..3227bcf0082 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/ifnotpresent_pull_patch.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/ifnotpresent_pull_patch.go @@ -17,15 +17,15 @@ package pullpolicy import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &IfNotPresentPullPatch{} +var _ machinery.Template = &IfNotPresentPullPatch{} // IfNotPresentPullPatch scaffolds the patch file for overriding the // default image pull policy during Ansible testing type IfNotPresentPullPatch struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,7 +36,7 @@ func (f *IfNotPresentPullPatch) SetTemplateDefaults() error { f.TemplateBody = ifNotPresentPullPatchTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/never_pull_patch.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/never_pull_patch.go index 5e65ed7694d..ab8b970957c 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/never_pull_patch.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/testing/pullpolicy/never_pull_patch.go @@ -17,15 +17,15 @@ package pullpolicy import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &NeverPullPatch{} +var _ machinery.Template = &NeverPullPatch{} // NeverPullPatch scaffolds the patch file for overriding the // default image pull policy during Ansible testing type NeverPullPatch struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,7 +36,7 @@ func (f *NeverPullPatch) SetTemplateDefaults() error { f.TemplateBody = neverPullPatchTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/dockerfile.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/dockerfile.go index e430bc29479..7589c4e2136 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/dockerfile.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/dockerfile.go @@ -17,16 +17,17 @@ package templates import ( "errors" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) -var _ file.Template = &Dockerfile{} +var _ machinery.Template = &Dockerfile{} // Dockerfile scaffolds a Dockerfile for building a main type Dockerfile struct { - file.TemplateMixin + machinery.TemplateMixin + // AnsibleOperatorVersion is the version of the Dockerfile's base image. AnsibleOperatorVersion string diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/gitignore.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/gitignore.go index 64cc86d9ce7..a2216975178 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/gitignore.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/gitignore.go @@ -18,14 +18,14 @@ limitations under the License. package templates import ( - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &GitIgnore{} +var _ machinery.Template = &GitIgnore{} // GitIgnore scaffolds the .gitignore file type GitIgnore struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/makefile.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/makefile.go index 48783d276eb..b5ced0a09de 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/makefile.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/makefile.go @@ -20,14 +20,14 @@ package templates import ( "errors" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Makefile{} +var _ machinery.Template = &Makefile{} // Makefile scaffolds the Makefile type Makefile struct { - file.TemplateMixin + machinery.TemplateMixin // Image is controller manager image name Image string @@ -47,7 +47,7 @@ func (f *Makefile) SetTemplateDefaults() error { f.TemplateBody = makefileTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error if f.Image == "" { f.Image = "controller:latest" diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/converge.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/converge.go index efd51727146..786631d7612 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/converge.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/converge.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Converge{} +var _ machinery.Template = &Converge{} // Converge scaffolds a Converge for building a main type Converge struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/create.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/create.go index e61a23d5c7d..6b19b0aa0e4 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/create.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/create.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Create{} +var _ machinery.Template = &Create{} // Create scaffolds a Create for building a main type Create struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/destroy.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/destroy.go index 69cbf44eb3c..0d095206262 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/destroy.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/destroy.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Destroy{} +var _ machinery.Template = &Destroy{} // Destroy scaffolds a Destroy for building a main type Destroy struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/kustomize.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/kustomize.go index 8e2f07bdc42..385800b5b05 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/kustomize.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/kustomize.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomize{} +var _ machinery.Template = &Kustomize{} // Kustomize scaffolds a Kustomize for building a main type Kustomize struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/molecule.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/molecule.go index 5da3e3fdfc2..b3c6d812d0f 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/molecule.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/molecule.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Molecule{} +var _ machinery.Template = &Molecule{} // Molecule scaffolds a Molecule for building a main type Molecule struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/prepare.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/prepare.go index 877fb98510d..8f2ef2e33f8 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/prepare.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/prepare.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Prepare{} +var _ machinery.Template = &Prepare{} // Prepare scaffolds a Prepare for building a main type Prepare struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/tasks_test_resource.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/tasks_test_resource.go index 0ce1afc557a..6453a23ec65 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/tasks_test_resource.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/tasks_test_resource.go @@ -17,15 +17,15 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ResourceTest{} +var _ machinery.Template = &ResourceTest{} // ResourceTest scaffolds a ResourceTest for building a main type ResourceTest struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin SampleFile string } @@ -42,7 +42,7 @@ func (f *ResourceTest) SetTemplateDefaults() error { } const resourceTestTemplate = `--- -- name: Create the {{.Resource.QualifiedGroup}}/{{.Resource.Version}}.{{.Resource.Kind}} +- name: Create the {{ .Resource.QualifiedGroup }}/{{ .Resource.Version }}.{{ .Resource.Kind }} k8s: state: present namespace: '{{ "{{ namespace }}" }}' diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/verify.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/verify.go index b7cb2bc0255..b9c86afa0cc 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/verify.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mdefault/verify.go @@ -17,14 +17,14 @@ package mdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Verify{} +var _ machinery.Template = &Verify{} // Verify scaffolds a Verify for building a main type Verify struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/converge.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/converge.go index 97ce83b1f20..f2aa8e9ce99 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/converge.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/converge.go @@ -17,14 +17,14 @@ package mkind import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Converge{} +var _ machinery.Template = &Converge{} // Converge scaffolds a Converge for building a main type Converge struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/create.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/create.go index c553ac6a9ee..dc71e06afb0 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/create.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/create.go @@ -17,14 +17,14 @@ package mkind import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Create{} +var _ machinery.Template = &Create{} // Create scaffolds a Create for building a main type Create struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/destroy.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/destroy.go index 87ecced83cf..d672b1b603a 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/destroy.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/destroy.go @@ -17,14 +17,14 @@ package mkind import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Destroy{} +var _ machinery.Template = &Destroy{} // Destroy scaffolds a Destroy for building a main type Destroy struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/molecule.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/molecule.go index 9ea33cb2ef5..3376746cef3 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/molecule.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/molecule/mkind/molecule.go @@ -17,14 +17,14 @@ package mkind import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Molecule{} +var _ machinery.Template = &Molecule{} // Molecule scaffolds a Molecule for building a main type Molecule struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/placeholder.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/placeholder.go index 05ec3d17952..6e8eb47321e 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/placeholder.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/placeholder.go @@ -15,7 +15,7 @@ package playbooks import ( - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) @@ -23,7 +23,7 @@ import ( const placeholderPath = "playbooks" + constants.FilePathSep + ".placeholder" type Placeholder struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/playbook.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/playbook.go index c7df1d9b6c0..8722c5d189d 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/playbook.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/playbooks/playbook.go @@ -17,12 +17,12 @@ package playbooks import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) type Playbook struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin GenerateRole bool } @@ -30,12 +30,11 @@ type Playbook struct { func (f *Playbook) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("playbooks", "%[kind].yml") - f.Path = f.Resource.Replacer().Replace(f.Path) - } - if f.Path == "" { - f.Path = "playbook.yml" } + f.Path = f.Resource.Replacer().Replace(f.Path) + f.TemplateBody = playbookTmpl + return nil } @@ -49,7 +48,7 @@ const playbookTmpl = `--- {{- if .GenerateRole }} tasks: - import_role: - name: "{{.Resource.Kind | lower }}" + name: "{{ lower .Resource.Kind }}" {{- else }} tasks: [] {{- end }} diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/requirements.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/requirements.go index 5b3762a1d93..e099440c0ec 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/requirements.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/requirements.go @@ -15,12 +15,12 @@ package templates import ( - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) // RequirementsYml - A requirements file for Ansible collection dependencies type RequirementsYml struct { - file.TemplateMixin + machinery.TemplateMixin } func (f *RequirementsYml) SetTemplateDefaults() error { diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/defaults_main.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/defaults_main.go index a4bf7819e9c..9f867731877 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/defaults_main.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/defaults_main.go @@ -17,16 +17,18 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const defaultsMainPath = "defaults" + constants.FilePathSep + "main.yml" +var _ machinery.Template = &DefaultsMain{} + type DefaultsMain struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template @@ -40,5 +42,5 @@ func (f *DefaultsMain) SetTemplateDefaults() error { } const defaultsMainAnsibleTmpl = `--- -# defaults file for {{ .Resource.Kind}} +# defaults file for {{ .Resource.Kind }} ` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/files_dir.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/files_dir.go index 119a321641f..733d778e215 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/files_dir.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/files_dir.go @@ -17,16 +17,18 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const filesPath = "files" + constants.FilePathSep + ".placeholder" +var _ machinery.Template = &RoleFiles{} + type RoleFiles struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/handlers_main.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/handlers_main.go index 306948a8ccf..8816cc3e564 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/handlers_main.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/handlers_main.go @@ -17,16 +17,18 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const handlersMainPath = "handlers" + constants.FilePathSep + "main.yml" +var _ machinery.Template = &HandlersMain{} + type HandlersMain struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template @@ -41,5 +43,5 @@ func (f *HandlersMain) SetTemplateDefaults() error { } const handlersMainAnsibleTmpl = `--- -# handlers file for {{ .Resource.Kind}} +# handlers file for {{ .Resource.Kind }} ` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/meta_main.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/meta_main.go index 00059e3e2ad..fbc48d234fb 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/meta_main.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/meta_main.go @@ -17,24 +17,26 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const metaMainPath = "meta" + constants.FilePathSep + "main.yml" +var _ machinery.Template = &MetaMain{} + type MetaMain struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template func (f *MetaMain) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join(constants.RolesDir, "%[kind]", metaMainPath) - f.Path = f.Resource.Replacer().Replace(f.Path) } + f.Path = f.Resource.Replacer().Replace(f.Path) f.TemplateBody = metaMainAnsibleTmpl return nil diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/placeholder.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/placeholder.go index dd7f33a0c5c..b0bdb1ac302 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/placeholder.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/placeholder.go @@ -15,7 +15,7 @@ package roles import ( - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) @@ -23,7 +23,7 @@ import ( const placeholderPath = "roles" + constants.FilePathSep + ".placeholder" type Placeholder struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/readme.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/readme.go index 73c786d9aef..2253824d374 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/readme.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/readme.go @@ -17,23 +17,25 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const ReadmePath = "README.md" +var _ machinery.Template = &Readme{} + type Readme struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } func (f *Readme) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join(constants.RolesDir, "%[kind]", ReadmePath) - f.Path = f.Resource.Replacer().Replace(f.Path) } + f.Path = f.Resource.Replacer().Replace(f.Path) f.TemplateBody = readmeAnsibleTmpl return nil diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/tasks_main.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/tasks_main.go index bdb73c282b2..6446d667454 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/tasks_main.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/tasks_main.go @@ -17,16 +17,18 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const tasksMainPath = "tasks" + constants.FilePathSep + "main.yml" +var _ machinery.Template = &TasksMain{} + type TasksMain struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template @@ -41,5 +43,5 @@ func (f *TasksMain) SetTemplateDefaults() error { } const tasksMainAnsibleTmpl = `--- -# tasks file for {{ .Resource.Kind}} +# tasks file for {{ .Resource.Kind }} ` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/templates_dir.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/templates_dir.go index d5c771cc951..d0e364f9bd5 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/templates_dir.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/templates_dir.go @@ -17,24 +17,26 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const templatesPath = "templates" + constants.FilePathSep + ".placeholder" +var _ machinery.Template = &RoleTemplates{} + type RoleTemplates struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template func (f *RoleTemplates) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join(constants.RolesDir, "%[kind]", templatesPath) - f.Path = f.Resource.Replacer().Replace(f.Path) } + f.Path = f.Resource.Replacer().Replace(f.Path) f.TemplateBody = templatesDirPlaceholder return nil diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/vars_main.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/vars_main.go index 7db0f372005..deed9d356e1 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/vars_main.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/roles/vars_main.go @@ -17,29 +17,31 @@ package roles import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/ansible/v1/constants" ) const varsMainPath = "vars" + constants.FilePathSep + "main.yml" +var _ machinery.Template = &VarsMain{} + type VarsMain struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template func (f *VarsMain) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join(constants.RolesDir, "%[kind]", varsMainPath) - f.Path = f.Resource.Replacer().Replace(f.Path) } + f.Path = f.Resource.Replacer().Replace(f.Path) f.TemplateBody = varsMainAnsibleTmpl return nil } const varsMainAnsibleTmpl = `--- -# vars file for {{ .Resource.Kind}} +# vars file for {{ .Resource.Kind }} ` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/watches.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/watches.go index 157931ce6ba..73f75fad4d6 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/watches.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/watches.go @@ -19,10 +19,10 @@ import ( "fmt" "text/template" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Watches{} +var _ machinery.Template = &Watches{} const ( defaultWatchesFile = "watches.yaml" @@ -31,7 +31,7 @@ const ( // Watches scaffolds the watches.yaml file type Watches struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -41,16 +41,15 @@ func (f *Watches) SetTemplateDefaults() error { } f.TemplateBody = fmt.Sprintf(watchesTemplate, - file.NewMarkerFor(f.Path, watchMarker), + machinery.NewMarkerFor(f.Path, watchMarker), ) return nil } -var _ file.Inserter = &WatchesUpdater{} +var _ machinery.Inserter = &WatchesUpdater{} type WatchesUpdater struct { - file.TemplateMixin - file.ResourceMixin + machinery.ResourceMixin GeneratePlaybook bool GenerateRole bool @@ -61,18 +60,18 @@ func (*WatchesUpdater) GetPath() string { return defaultWatchesFile } -func (*WatchesUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite +func (*WatchesUpdater) GetIfExistsAction() machinery.IfExistsAction { + return machinery.OverwriteFile } -func (f *WatchesUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(defaultWatchesFile, watchMarker), +func (f *WatchesUpdater) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(defaultWatchesFile, watchMarker), } } -func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) +func (f *WatchesUpdater) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 1) // If resource is not being provided we are creating the file, not updating it if f.Resource == nil { @@ -85,7 +84,7 @@ func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { // TODO(asmacdo) Move template execution into a function, executed by the apiScaffolder.scaffold() // DefaultFuncMap used provide the function "lower", used in the watch fragment. - tmpl := template.Must(template.New("rules").Funcs(file.DefaultFuncMap()).Parse(watchFragment)) + tmpl := template.Must(template.New("rules").Funcs(machinery.DefaultFuncMap()).Parse(watchFragment)) err := tmpl.Execute(buf, f) if err != nil { panic(err) @@ -93,7 +92,7 @@ func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { watches = append(watches, buf.String()) if len(watches) != 0 { - fragments[file.NewMarkerFor(defaultWatchesFile, watchMarker)] = watches + fragments[machinery.NewMarkerFor(defaultWatchesFile, watchMarker)] = watches } return fragments } @@ -103,13 +102,13 @@ const watchesTemplate = `--- %s ` -const watchFragment = `- version: {{.Resource.Version}} - group: {{.Resource.QualifiedGroup}} - kind: {{.Resource.Kind}} +const watchFragment = `- version: {{ .Resource.Version }} + group: {{ .Resource.QualifiedGroup }} + kind: {{ .Resource.Kind }} {{- if .GeneratePlaybook }} - playbook: {{ .PlaybooksDir }}/{{ .Resource.Kind | lower }}.yml + playbook: {{ .PlaybooksDir }}/{{ lower .Resource.Kind }}.yml {{- else if .GenerateRole}} - role: {{ .Resource.Kind | lower }} + role: {{ lower .Resource.Kind }} {{- else }} # FIXME: Specify the role or playbook for this resource. {{- end }} diff --git a/internal/plugins/envtest/init.go b/internal/plugins/envtest/init.go deleted file mode 100644 index f13d0ca5aad..00000000000 --- a/internal/plugins/envtest/init.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// TODO: This implementation is already done for v3+. Also, it might be -// addressed on v2 as well. More info: https://github.com/kubernetes-sigs/kubebuilder/pull/1711 -package envtest - -import ( - "fmt" - "io/ioutil" - "os" - "strings" - - cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" - - "sigs.k8s.io/kubebuilder/v3/pkg/config" -) - -// controllerRuntimeVersion version to be used to download the envtest setup script -const controllerRuntimeVersion = "v0.6.3" - -// RunInit modifies the project scaffolded by kubebuilder's Init plugin. -func RunInit(cfg config.Config) error { - // Only run these if project version is v3. - isV3 := cfg.GetVersion().Compare(cfgv3.Version) == 0 - if !isV3 { - return nil - } - - // Update the scaffolded Makefile with operator-sdk recipes. - if err := initUpdateMakefile("Makefile"); err != nil { - return fmt.Errorf("error updating Makefile: %v", err) - } - return nil -} - -// initUpdateMakefile updates a vanilla kubebuilder Makefile with operator-sdk recipes. -func initUpdateMakefile(filePath string) error { - makefileBytes, err := ioutil.ReadFile(filePath) - if err != nil { - return err - } - - makefileBytes = []byte(strings.Replace(string(makefileBytes), - "# Run tests\ntest: manifests generate fmt vet\n\tgo test ./... -coverprofile cover.out", - fmt.Sprintf(makefileTestTarget, controllerRuntimeVersion), 1)) - - var mode os.FileMode = 0644 - if info, err := os.Stat(filePath); err != nil { - mode = info.Mode() - } - return ioutil.WriteFile(filePath, makefileBytes, mode) -} - -const makefileTestTarget = `# Run tests -ENVTEST_ASSETS_DIR = $(shell pwd)/testbin -test: manifests generate fmt vet - mkdir -p $(ENVTEST_ASSETS_DIR) - test -f $(ENVTEST_ASSETS_DIR)/setup-envtest.sh || curl -sSLo $(ENVTEST_ASSETS_DIR)/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/%s/hack/setup-envtest.sh - source $(ENVTEST_ASSETS_DIR)/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out` diff --git a/internal/plugins/envtest/v1/init.go b/internal/plugins/envtest/v1/init.go new file mode 100644 index 00000000000..3bc0fdb002f --- /dev/null +++ b/internal/plugins/envtest/v1/init.go @@ -0,0 +1,67 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/spf13/afero" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" +) + +const ( + // controllerRuntimeVersion version to be used to download the envtest setup script + controllerRuntimeVersion = "v0.6.3" + + filePath = "Makefile" +) + +var _ plugin.InitSubcommand = &initSubcommand{} + +type initSubcommand struct{} + +func (s *initSubcommand) Scaffold(fs afero.Fs) error { + makefileBytes, err := afero.ReadFile(fs, filePath) + if err != nil { + return err + } + + makefileBytes = []byte(strings.Replace(string(makefileBytes), oldMakefileTestTarget, fmt.Sprintf(makefileTestTarget, controllerRuntimeVersion), 1)) + + var mode os.FileMode = 0644 + if info, err := fs.Stat(filePath); err == nil { + mode = info.Mode() + } + if err := ioutil.WriteFile(filePath, makefileBytes, mode); err != nil { + return fmt.Errorf("error updating Makefile: %w", err) + } + + return nil +} + +const ( + oldMakefileTestTarget = `# Run tests +test: manifests generate fmt vet + go test ./... -coverprofile cover.out` + makefileTestTarget = `# Run tests +ENVTEST_ASSETS_DIR = $(shell pwd)/testbin +test: manifests generate fmt vet + mkdir -p $(ENVTEST_ASSETS_DIR) + test -f $(ENVTEST_ASSETS_DIR)/setup-envtest.sh || curl -sSLo $(ENVTEST_ASSETS_DIR)/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/%s/hack/setup-envtest.sh + source $(ENVTEST_ASSETS_DIR)/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out` +) diff --git a/internal/plugins/envtest/v1/plugin.go b/internal/plugins/envtest/v1/plugin.go new file mode 100644 index 00000000000..c0e9591bcb2 --- /dev/null +++ b/internal/plugins/envtest/v1/plugin.go @@ -0,0 +1,46 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This plugin replaces the test target of go/v2 plugins to match that of go/v3. +// More info: https://github.com/kubernetes-sigs/kubebuilder/pull/1711 +package v1 + +import ( + "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" + + "github.com/operator-framework/operator-sdk/internal/plugins" +) + +const pluginName = "envtest" + plugins.DefaultNameQualifier + +var ( + supportedProjectVersions = []config.Version{cfgv3.Version} + pluginVersion = plugin.Version{Number: 1} +) + +var ( + _ plugin.Plugin = Plugin{} + _ plugin.Init = Plugin{} +) + +type Plugin struct { + initSubcommand +} + +func (Plugin) Name() string { return pluginName } +func (Plugin) Version() plugin.Version { return pluginVersion } +func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions } +func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { return &p.initSubcommand } diff --git a/internal/plugins/golang/v2/api.go b/internal/plugins/golang/v2/api.go deleted file mode 100644 index 3ed69247ccb..00000000000 --- a/internal/plugins/golang/v2/api.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "github.com/spf13/pflag" - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - - "github.com/operator-framework/operator-sdk/internal/plugins/manifests" - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" -) - -type createAPISubcommand struct { - plugin.CreateAPISubcommand - - config config.Config -} - -var _ plugin.CreateAPISubcommand = &createAPISubcommand{} - -func (p *createAPISubcommand) UpdateContext(ctx *plugin.Context) { - p.CreateAPISubcommand.UpdateContext(ctx) -} -func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { p.CreateAPISubcommand.BindFlags(fs) } - -func (p *createAPISubcommand) InjectConfig(c config.Config) { - p.CreateAPISubcommand.InjectConfig(c) - p.config = c -} - -func (p *createAPISubcommand) Run() error { - // Run() may add a new resource to the config, so we can compare resources before/after to get the new resource. - oldResources, err := p.config.GetResources() - if err != nil { - return err - } - - if err := p.CreateAPISubcommand.Run(); err != nil { - return err - } - - // Find the new resource. Here we shouldn't worry about checking if one was found, - // since downstream plugins will do so. - newResources, err := p.config.GetResources() - if err != nil { - return err - } - var newResource resource.Resource - for _, newR := range newResources { - newResource = newR - for _, oldR := range oldResources { - if !oldR.GVK.IsEqualTo(newR.GVK) { - newResource = newR - break - } - } - } - - // Run SDK phase 2 plugins. - return p.runPhase2(newResource.GVK) -} - -// SDK phase 2 plugins. -func (p *createAPISubcommand) runPhase2(gvk resource.GVK) error { - // Check if the generic "go" operator-sdk plugin (legacy) exists first. - if hasPluginConfig(p.config) { - if err := manifests.RunCreateAPI(p.config, gvk); err != nil { - return err - } - return nil - } - - // v2 plugins will handle checking p.config for their key so we can call all of them below. - if err := manifestsv2.RunCreateAPI(p.config, gvk); err != nil { - return err - } - - return nil -} diff --git a/internal/plugins/golang/v2/config.go b/internal/plugins/golang/v2/config.go deleted file mode 100644 index f6467a06d4f..00000000000 --- a/internal/plugins/golang/v2/config.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "sigs.k8s.io/kubebuilder/v3/pkg/config" -) - -// Config configures this plugin, and is saved in the project config file. -// Deprecated: use scorecard and manifests plugin configs directly. -type Config struct{} - -// hasPluginConfig returns true if cfg.Layout contains an exact match for this plugin's key. -func hasPluginConfig(cfg config.Config) bool { - info := Config{} - return cfg.DecodePluginConfig(pluginConfigKey, &info) == nil -} diff --git a/internal/plugins/golang/v2/init.go b/internal/plugins/golang/v2/init.go deleted file mode 100644 index bf2914b1355..00000000000 --- a/internal/plugins/golang/v2/init.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "github.com/spf13/pflag" - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - - "github.com/operator-framework/operator-sdk/internal/plugins/envtest" - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" - scorecardv2 "github.com/operator-framework/operator-sdk/internal/plugins/scorecard/v2" -) - -type initSubcommand struct { - plugin.InitSubcommand - - config config.Config -} - -var _ plugin.InitSubcommand = &initSubcommand{} - -func (p *initSubcommand) UpdateContext(ctx *plugin.Context) { p.InitSubcommand.UpdateContext(ctx) } -func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { p.InitSubcommand.BindFlags(fs) } - -func (p *initSubcommand) InjectConfig(c config.Config) { - p.InitSubcommand.InjectConfig(c) - p.config = c -} - -func (p *initSubcommand) Run() error { - if err := p.InitSubcommand.Run(); err != nil { - return err - } - - // Run SDK phase 2 plugins. - if err := p.runPhase2(); err != nil { - return err - } - - return nil -} - -// SDK phase 2 plugins. -func (p *initSubcommand) runPhase2() error { - if err := envtest.RunInit(p.config); err != nil { - return err - } - if err := manifestsv2.RunInit(p.config); err != nil { - return err - } - if err := scorecardv2.RunInit(p.config); err != nil { - return err - } - return nil -} diff --git a/internal/plugins/golang/v2/plugin.go b/internal/plugins/golang/v2/plugin.go deleted file mode 100644 index 1404fbcfe2a..00000000000 --- a/internal/plugins/golang/v2/plugin.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model/stage" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - kbgov2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2" - - "github.com/operator-framework/operator-sdk/internal/plugins" -) - -// Plugin name/version used in this file will also be used in phase 2 plugins when we can -// pipe kubebuilder's init/create api output into our scaffold modification -// plugins. In phase 1 we wrap kubebuilder's Go plugin to have the same effect. - -const ( - pluginName = "go" + plugins.DefaultNameQualifier -) - -var ( - pluginVersion = plugin.Version{Number: 2, Stage: stage.Alpha} - pluginConfigKey = plugin.Key(pluginName, pluginVersion.String()) -) - -var ( - _ plugin.Plugin = Plugin{} - _ plugin.Full = Plugin{} -) - -// Plugin defines an Operator SDK Go scaffold and CLI plugin. Its current purpose is to -// add operator-framework features to the base kubebuilder Go scaffold and CLI. -type Plugin struct{} - -func (Plugin) Name() string { return (kbgov2.Plugin{}).Name() } -func (Plugin) Version() plugin.Version { return (kbgov2.Plugin{}).Version() } -func (Plugin) SupportedProjectVersions() []config.Version { - return (kbgov2.Plugin{}).SupportedProjectVersions() -} - -func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { - return &initSubcommand{ - InitSubcommand: (kbgov2.Plugin{}).GetInitSubcommand(), - } -} - -func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { - return &createAPISubcommand{ - CreateAPISubcommand: (kbgov2.Plugin{}).GetCreateAPISubcommand(), - } -} - -func (p Plugin) GetCreateWebhookSubcommand() plugin.CreateWebhookSubcommand { - return (kbgov2.Plugin{}).GetCreateWebhookSubcommand() -} - -func (p Plugin) GetEditSubcommand() plugin.EditSubcommand { - return (kbgov2.Plugin{}).GetEditSubcommand() -} diff --git a/internal/plugins/golang/v3/api.go b/internal/plugins/golang/v3/api.go deleted file mode 100644 index 5b9caaf52a2..00000000000 --- a/internal/plugins/golang/v3/api.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v3 - -import ( - "github.com/spf13/pflag" - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" -) - -type createAPISubcommand struct { - plugin.CreateAPISubcommand - - config config.Config -} - -var _ plugin.CreateAPISubcommand = &createAPISubcommand{} - -func (p *createAPISubcommand) UpdateContext(ctx *plugin.Context) { - p.CreateAPISubcommand.UpdateContext(ctx) -} -func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { p.CreateAPISubcommand.BindFlags(fs) } - -func (p *createAPISubcommand) InjectConfig(c config.Config) { - p.CreateAPISubcommand.InjectConfig(c) - p.config = c -} - -func (p *createAPISubcommand) Run() error { - // Run() may add a new resource to the config, so we can compare resources before/after to get the new resource. - oldResources, err := p.config.GetResources() - if err != nil { - return err - } - - if err := p.CreateAPISubcommand.Run(); err != nil { - return err - } - - // Find the new resource. Here we shouldn't worry about checking if one was found, - // since downstream plugins will do so. - newResources, err := p.config.GetResources() - if err != nil { - return err - } - var newResource resource.Resource - for _, newR := range newResources { - newResource = newR - for _, oldR := range oldResources { - if !oldR.GVK.IsEqualTo(newR.GVK) { - newResource = newR - break - } - } - } - - // Run SDK phase 2 plugins. - return p.runPhase2(newResource.GVK) -} - -// SDK phase 2 plugins. -func (p *createAPISubcommand) runPhase2(gvk resource.GVK) error { - return manifestsv2.RunCreateAPI(p.config, gvk) -} diff --git a/internal/plugins/golang/v3/init.go b/internal/plugins/golang/v3/init.go deleted file mode 100644 index cda5af2c791..00000000000 --- a/internal/plugins/golang/v3/init.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v3 - -import ( - "github.com/spf13/pflag" - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" - scorecardv2 "github.com/operator-framework/operator-sdk/internal/plugins/scorecard/v2" -) - -type initSubcommand struct { - plugin.InitSubcommand - - config config.Config -} - -var _ plugin.InitSubcommand = &initSubcommand{} - -func (p *initSubcommand) UpdateContext(ctx *plugin.Context) { p.InitSubcommand.UpdateContext(ctx) } -func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { p.InitSubcommand.BindFlags(fs) } - -func (p *initSubcommand) InjectConfig(c config.Config) { - p.InitSubcommand.InjectConfig(c) - p.config = c -} - -func (p *initSubcommand) Run() error { - if err := p.InitSubcommand.Run(); err != nil { - return err - } - - // Run SDK phase 2 plugins. - if err := p.runPhase2(); err != nil { - return err - } - - return nil -} - -// SDK phase 2 plugins. -func (p *initSubcommand) runPhase2() error { - if err := manifestsv2.RunInit(p.config); err != nil { - return err - } - if err := scorecardv2.RunInit(p.config); err != nil { - return err - } - return nil -} diff --git a/internal/plugins/golang/v3/plugin.go b/internal/plugins/golang/v3/plugin.go deleted file mode 100644 index 54f178b407c..00000000000 --- a/internal/plugins/golang/v3/plugin.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v3 - -import ( - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - kbgov3 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3" -) - -var ( - _ plugin.Plugin = Plugin{} - _ plugin.Full = Plugin{} -) - -// Plugin defines an Operator SDK Go scaffold and CLI plugin. Its current purpose is to -// add operator-framework features to the base kubebuilder Go scaffold and CLI. -type Plugin struct{} - -func (Plugin) Name() string { return (kbgov3.Plugin{}).Name() } -func (Plugin) Version() plugin.Version { return (kbgov3.Plugin{}).Version() } -func (Plugin) SupportedProjectVersions() []config.Version { - return (kbgov3.Plugin{}).SupportedProjectVersions() -} - -func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { - return &initSubcommand{ - InitSubcommand: (kbgov3.Plugin{}).GetInitSubcommand(), - } -} - -func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { - return &createAPISubcommand{ - CreateAPISubcommand: (kbgov3.Plugin{}).GetCreateAPISubcommand(), - } -} - -func (p Plugin) GetCreateWebhookSubcommand() plugin.CreateWebhookSubcommand { - return (kbgov3.Plugin{}).GetCreateWebhookSubcommand() -} - -func (p Plugin) GetEditSubcommand() plugin.EditSubcommand { - return (kbgov3.Plugin{}).GetEditSubcommand() -} diff --git a/internal/plugins/helm/v1/api.go b/internal/plugins/helm/v1/api.go index 3463692ea19..cccc836ad6e 100644 --- a/internal/plugins/helm/v1/api.go +++ b/internal/plugins/helm/v1/api.go @@ -15,189 +15,196 @@ package v1 import ( + "errors" "fmt" + "os" "strings" + "github.com/iancoleman/strcase" + "github.com/spf13/afero" "github.com/spf13/pflag" + "helm.sh/helm/v3/pkg/chart" "sigs.k8s.io/kubebuilder/v3/pkg/config" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/chartutil" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds" - "github.com/operator-framework/operator-sdk/internal/plugins/manifests" - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" ) -type createAPISubcommand struct { - config config.Config - createOptions chartutil.CreateOptions -} +const ( + crdVersionFlag = "crd-version" + helmChartFlag = "helm-chart" + helmChartRepoFlag = "helm-chart-repo" + helmChartVersionFlag = "helm-chart-version" + + defaultCrdVersionFlagValue = "v1" + defaultHelmChartFlagValue = "" + defaultHelmChartRepoFlagValue = "" + defaultHelmChartVersionFlagValue = "" -var ( - _ plugin.CreateAPISubcommand = &createAPISubcommand{} - _ cmdutil.RunOptions = &createAPISubcommand{} + // defaultGroup is the Kubernetes CRD API Group used for fetched charts when the --group flag is not specified + defaultGroup = "charts" + // defaultVersion is the Kubernetes CRD API Version used for fetched charts when the --version flag is not specified + defaultVersion = "v1alpha1" ) -// UpdateContext define plugin context -func (p createAPISubcommand) UpdateContext(ctx *plugin.Context) { - ctx.Description = `Scaffold a Kubernetes API that is backed by a Helm chart. +type createAPIOptions struct { + // CRDVersion is the version of the `apiextensions.k8s.io` API which will be used to generate the CRD. + CRDVersion string + + chartOptions chartutil.Options +} + +// UpdateResource updates the base resource with the information obtained from the flags +func (opts createAPIOptions) UpdateResource(res *resource.Resource) { + res.API = &resource.API{ + CRDVersion: opts.CRDVersion, + Namespaced: true, + } + + // Ensure that Path is empty and Controller false + res.Path = "" + res.Controller = false +} + +var _ plugin.CreateAPISubcommand = &createAPISubcommand{} + +type createAPISubcommand struct { + config config.Config + resource *resource.Resource + chart *chart.Chart + options createAPIOptions +} + +func (p *createAPISubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { + subcmdMeta.Description = `Scaffold a Kubernetes API that is backed by a Helm chart. ` - ctx.Examples = fmt.Sprintf(` $ %s create api \ + subcmdMeta.Examples = fmt.Sprintf(` $ %s create api \ --group=apps --version=v1alpha1 \ --kind=AppService - $ %s create api \ + $ %[1]s create api \ --group=apps --version=v1alpha1 \ --kind=AppService \ --helm-chart=myrepo/app - $ %s create api \ + $ %[1]s create api \ --helm-chart=myrepo/app - $ %s create api \ + $ %[1]s create api \ --helm-chart=myrepo/app \ --helm-chart-version=1.2.3 - $ %s create api \ + $ %[1]s create api \ --helm-chart=app \ --helm-chart-repo=https://charts.mycompany.com/ - $ %s create api \ + $ %[1]s create api \ --helm-chart=app \ --helm-chart-repo=https://charts.mycompany.com/ \ --helm-chart-version=1.2.3 - $ %s create api \ + $ %[1]s create api \ --helm-chart=/path/to/local/chart-directories/app/ - $ %s create api \ + $ %[1]s create api \ --helm-chart=/path/to/local/chart-archives/app-1.2.3.tgz -`, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ctx.CommandName, - ) +`, cliMeta.CommandName) } -const ( - groupFlag = "group" - versionFlag = "version" - kindFlag = "kind" - helmChartFlag = "helm-chart" - helmChartRepoFlag = "helm-chart-repo" - helmChartVersionFlag = "helm-chart-version" - crdVersionFlag = "crd-version" - - crdVersionV1 = "v1" - crdVersionV1beta1 = "v1beta1" -) - // BindFlags will set the flags for the plugin func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { - p.createOptions = chartutil.CreateOptions{} fs.SortFlags = false - fs.StringVar(&p.createOptions.GVK.Group, groupFlag, "", "resource group") - fs.StringVar(&p.createOptions.GVK.Version, versionFlag, "", "resource version") - fs.StringVar(&p.createOptions.GVK.Kind, kindFlag, "", "resource kind") - - fs.StringVar(&p.createOptions.Chart, helmChartFlag, "", "helm chart") - fs.StringVar(&p.createOptions.Repo, helmChartRepoFlag, "", "helm chart repository") - fs.StringVar(&p.createOptions.Version, helmChartVersionFlag, "", "helm chart version (default: latest)") - - fs.StringVar(&p.createOptions.CRDVersion, crdVersionFlag, crdVersionV1, "crd version to generate") + fs.StringVar(&p.options.CRDVersion, crdVersionFlag, defaultCrdVersionFlagValue, "crd version to generate") + fs.StringVar(&p.options.chartOptions.Chart, helmChartFlag, defaultHelmChartFlagValue, "helm chart") + fs.StringVar(&p.options.chartOptions.Repo, helmChartRepoFlag, defaultHelmChartRepoFlagValue, "helm chart repository") + fs.StringVar(&p.options.chartOptions.Version, helmChartVersionFlag, defaultHelmChartVersionFlagValue, "helm chart version (default: latest)") } -// InjectConfig will inject the PROJECT file/config in the plugin -func (p *createAPISubcommand) InjectConfig(c config.Config) { +func (p *createAPISubcommand) InjectConfig(c config.Config) error { p.config = c + + return nil } -// Run will call the plugin actions according to the definitions done in RunOptions interface -func (p *createAPISubcommand) Run() error { - if err := cmdutil.Run(p); err != nil { - return err - } +func (p *createAPISubcommand) InjectResource(res *resource.Resource) error { + p.resource = res - // Run SDK phase 2 plugins. - if err := p.runPhase2(); err != nil { + // The following checks and the chart creation would be a better fit for PreScaffold method + // but, as having a chart sets some default values for the resource's GVK, we need to do it here. + projectDir, err := os.Getwd() + if err != nil { return err } + if len(strings.TrimSpace(p.options.chartOptions.Chart)) == 0 { + // Chart repo and version can only be provided if chart was provided. + if len(strings.TrimSpace(p.options.chartOptions.Repo)) != 0 { + return fmt.Errorf("value of --%s can only be used with --%s", helmChartRepoFlag, helmChartFlag) + } + if len(p.options.chartOptions.Version) != 0 { + return fmt.Errorf("value of --%s can only be used with --%s", helmChartVersionFlag, helmChartFlag) + } - return nil -} - -// SDK phase 2 plugins. -func (p *createAPISubcommand) runPhase2() error { - ogvk := p.createOptions.GVK - gvk := resource.GVK{Group: ogvk.Group, Version: ogvk.Version, Kind: ogvk.Kind} - - // Initially the helm/v1 plugin was written to not create a "plugins" config entry - // for any phase 2 plugin because they did not have their own keys. Now there are phase 2 - // plugin keys, so those plugins should be run if keys exist. Otherwise, enact old behavior. + // Kind is required if no chart was provided as it is used for the chart name. + // While the resource validation will detect this, the error yielded would not + // mention the option of providing the chart flag. Additionally, by checking it + // here we can create the new chart before resource validation. + if len(p.resource.Kind) == 0 { + return fmt.Errorf("either --%s or --%s need to be provided", kindFlag, helmChartFlag) + } - if manifestsv2.HasPluginConfig(p.config) { - if err := manifestsv2.RunCreateAPI(p.config, gvk); err != nil { + p.chart, err = chartutil.NewChart(projectDir, strings.ToLower(p.resource.Kind)) + if err != nil { return err } } else { - if err := manifests.RunCreateAPI(p.config, gvk); err != nil { + p.chart, err = chartutil.LoadChart(projectDir, p.options.chartOptions) + if err != nil { return err } + + // In case we loaded a chart and some resource flags were not set we will set defaults. + if p.resource.Group == "" { + p.resource.Group = defaultGroup + } + if p.resource.Version == "" { + p.resource.Version = defaultVersion + } + if p.resource.Kind == "" { + p.resource.Kind = strcase.ToCamel(p.chart.Name()) + if p.resource.Plural == "" { + p.resource.Plural = resource.RegularPlural(p.resource.Kind) + } + } } - return nil -} + p.options.UpdateResource(p.resource) -// Validate perform the required validations for this plugin -func (p *createAPISubcommand) Validate() error { - if p.createOptions.CRDVersion != crdVersionV1 && p.createOptions.CRDVersion != crdVersionV1beta1 { - return fmt.Errorf("value of --%s must be either %q or %q", crdVersionFlag, crdVersionV1, crdVersionV1beta1) + if err := p.resource.Validate(); err != nil { + return err } - if len(strings.TrimSpace(p.createOptions.Chart)) == 0 { - if len(strings.TrimSpace(p.createOptions.Repo)) != 0 { - return fmt.Errorf("value of --%s can only be used with --%s", helmChartRepoFlag, helmChartFlag) - } else if len(p.createOptions.Version) != 0 { - return fmt.Errorf("value of --%s can only be used with --%s", helmChartVersionFlag, helmChartFlag) - } + // Check that resource doesn't have the API scaffolded + if res, err := p.config.GetResource(p.resource.GVK); err == nil && res.HasAPI() { + return errors.New("the API resource already exists") } - if len(strings.TrimSpace(p.createOptions.Chart)) == 0 { - if len(strings.TrimSpace(p.createOptions.GVK.Group)) == 0 { - return fmt.Errorf("value of --%s must not have empty value", groupFlag) - } - if len(strings.TrimSpace(p.createOptions.GVK.Version)) == 0 { - return fmt.Errorf("value of --%s must not have empty value", versionFlag) - } - if len(strings.TrimSpace(p.createOptions.GVK.Kind)) == 0 { - return fmt.Errorf("value of --%s must not have empty value", kindFlag) - } - - // Validate the resource. - ogvk := p.createOptions.GVK - gvk := resource.GVK{Group: ogvk.Group, Version: ogvk.Version, Kind: ogvk.Kind} - if err := gvk.Validate(); err != nil { - return err - } + // Check that the provided group can be added to the project + if !p.config.IsMultiGroup() && p.config.ResourcesLength() != 0 && !p.config.HasGroup(p.resource.Group) { + return fmt.Errorf("multiple groups are not allowed by default, to enable multi-group set 'multigroup: true' in your PROJECT file") } return nil } -// GetScaffolder returns cmdutil.Scaffolder which will be executed due the RunOptions interface implementation -func (p *createAPISubcommand) GetScaffolder() (cmdutil.Scaffolder, error) { - return scaffolds.NewAPIScaffolder(p.config, p.createOptions), nil -} +func (p *createAPISubcommand) Scaffold(fs afero.Fs) error { + scaffolder := scaffolds.NewAPIScaffolder(p.config, *p.resource, p.chart) + scaffolder.InjectFS(fs) + if err := scaffolder.Scaffold(); err != nil { + return err + } -// PostScaffold runs all actions that should be executed after the default plugin scaffold -func (p *createAPISubcommand) PostScaffold() error { return nil } diff --git a/internal/plugins/helm/v1/chartutil/chart.go b/internal/plugins/helm/v1/chartutil/chart.go index 671a1cce736..ca92f83fa31 100644 --- a/internal/plugins/helm/v1/chartutil/chart.go +++ b/internal/plugins/helm/v1/chartutil/chart.go @@ -20,9 +20,7 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" - "github.com/iancoleman/strcase" log "github.com/sirupsen/logrus" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" @@ -31,30 +29,16 @@ import ( "helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/repo" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" ) const ( - - // HelmChartsDir is the relative directory within an SDK project where Helm - // charts are stored. - HelmChartsDir string = "helm-charts" - - // DefaultGroup is the Kubernetes CRD API Group used for fetched - // charts when the --group flag is not specified - DefaultGroup string = "charts" - - // DefaultVersion is the Kubernetes CRD API Version used for fetched - // charts when the --version flag is not specified - DefaultVersion string = "v1alpha1" + // HelmChartsDir is the relative directory within a SDK project where Helm charts are stored. + HelmChartsDir = "helm-charts" ) -// CreateOptions is used to configure how a Helm chart is scaffolded +// Options is used to configure how a Helm chart is scaffolded // for a new Helm operator project. -type CreateOptions struct { - GVK schema.GroupVersionKind - +type Options struct { // Chart is a chart reference for a local or remote chart. Chart string @@ -63,39 +47,60 @@ type CreateOptions struct { // Version is the version of the chart to fetch. Version string +} + +// NewChart scaffolds a new helm chart for the project rooted in projectDir +// from helm's default template. It returns a chart.Chart that references the +// newly created chart or an error. +func NewChart(projectDir, name string) (*chart.Chart, error) { + // Ensure that the directory exists as chartutil.Create will fail if it doesn't + chartsDir := filepath.Join(projectDir, HelmChartsDir) + err := os.MkdirAll(chartsDir, 0755) + if err != nil { + return nil, fmt.Errorf("failed to create helm-charts directory: %v", err) + } + + // Create a new chart + chartPath, err := chartutil.Create(name, chartsDir) + if err != nil { + return nil, err + } + + // Load the new chart + chrt, err := loader.Load(chartPath) + if err != nil { + return nil, err + } - // CRDVersion is the version of the `apiextensions.k8s.io` API which will be used to generate the CRD. - CRDVersion string + chartDir := filepath.Join(chartsDir, chrt.Name()) - // Domain is the domain of the project - Domain string + // Fetch dependencies + if err := fetchChartDependencies(chartDir); err != nil { + return nil, fmt.Errorf("failed to fetch chart dependencies: %w", err) + } + + // Reload chart in case dependencies changed + chrt, err = loader.Load(chartDir) + if err != nil { + return nil, fmt.Errorf("failed to load chart: %v", err) + } + + fmt.Printf("Created %s\n", filepath.Join(HelmChartsDir, chrt.Name())) + return chrt, nil } -// CreateChart scaffolds a new helm chart for the project rooted in projectDir -// based on the passed opts. -// -// It returns a scaffold.Resource that can be used by the caller to create -// other related files. opts.ResourceAPIVersion and opts.ResourceKind are -// used to create the resource and must be specified if opts.Chart is empty. -// -// If opts.Chart is not empty, opts.ResourceAPIVersion and opts.Kind can be -// left unset: opts.ResourceAPIVersion defaults to "charts.helm.k8s.io/v1alpha1" -// and opts.ResourceKind is deduced from the specified opts.Chart. -// -// CreateChart also returns a chart.Chart that references the newly created -// chart. +// LoadChart scaffolds a new helm chart for the project rooted in projectDir +// based on the passed opts. It returns a chart.Chart that references the newly +// created chart or an error. // -// If opts.Chart is empty, CreateChart scaffolds the default chart from helm's -// default template. +// If opts.Chart is a local file, it verifies that it is a valid helm chart +// archive and unpacks it into the project's helm charts directory. // -// If opts.Chart is a local file, CreateChart verifies that it is a valid helm -// chart archive and unpacks it into the project's helm charts directory. +// If opts.Chart is a local directory, it verifies that it is a valid helm chart +// directory and copies it into the project's helm charts directory. // -// If opts.Chart is a local directory, CreateChart verifies that it is a valid -// helm chart directory and copies it into the project's helm charts directory. -// -// For any other value of opts.Chart, CreateChart attempts to fetch the helm chart -// from a remote repository. +// For any other value of opts.Chart, it attempts to fetch the helm chart from a +// remote repository. // // If opts.Repo is not specified, the following chart reference formats are supported: // @@ -110,125 +115,58 @@ type CreateOptions struct { // - : Fetch the helm chart named chartName in the helm chart repository // specified by opts.Repo // -// If opts.Version is not set, CreateChart will fetch the latest available version of -// the helm chart. Otherwise, CreateChart will fetch the specified version. +// If opts.Version is not set, it will fetch the latest available version of +// the helm chart. Otherwise, it will fetch the specified version. // opts.Version is not used when opts.Chart itself refers to a specific version, for // example when it is a local path or a URL. -// -// CreateChart returns an error if an error occurs creating the scaffold.Resource or -// creating the chart. -func CreateChart(projectDir string, opts CreateOptions) (*golang.Options, *chart.Chart, error) { - chartsDir := filepath.Join(projectDir, HelmChartsDir) - err := os.MkdirAll(chartsDir, 0755) - if err != nil { - return nil, nil, fmt.Errorf("failed to create helm-charts directory: %v", err) - } +func LoadChart(projectDir string, opts Options) (*chart.Chart, error) { + chartPath := opts.Chart - var ( - r *golang.Options - c *chart.Chart - ) - - // If we don't have a helm chart reference, scaffold the default chart - // from Helm's default template. Otherwise, fetch it. - if len(opts.Chart) == 0 { - r, c, err = scaffoldChart(chartsDir, opts) + // If it is a remote chart, download it to a temp dir first + if _, err := os.Stat(opts.Chart); err != nil { + var tmpDir string + chartPath, tmpDir, err = downloadChart(opts) if err != nil { - return nil, nil, fmt.Errorf("failed to scaffold default chart: %v", err) - } - } else { - r, c, err = fetchChart(chartsDir, opts) - if err != nil { - return nil, nil, fmt.Errorf("failed to fetch chart: %v", err) + return nil, err } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + log.Errorf("Failed to remove temporary directory %s: %v", tmpDir, err) + } + }() } - relChartPath := filepath.Join(HelmChartsDir, c.Name()) - absChartPath := filepath.Join(projectDir, relChartPath) - if err := fetchChartDependencies(absChartPath); err != nil { - return nil, nil, fmt.Errorf("failed to fetch chart dependencies: %v", err) - } - - // Reload chart in case dependencies changed - c, err = loader.Load(absChartPath) - if err != nil { - return nil, nil, fmt.Errorf("failed to load chart: %v", err) - } - - fmt.Printf("Created %s\n", relChartPath) - return r, c, nil -} - -func scaffoldChart(destDir string, opts CreateOptions) (*golang.Options, *chart.Chart, error) { - r := &golang.Options{} - r.Namespaced = true - r.Domain = opts.Domain - r.Group = opts.GVK.Group - r.Version = opts.GVK.Version - r.Kind = opts.GVK.Kind + chartsDir := filepath.Join(projectDir, HelmChartsDir) - chartPath, err := chartutil.Create(strings.ToLower(r.Kind), destDir) + // Load the local/downloaded chart + chrt, err := loader.Load(chartPath) if err != nil { - return nil, nil, err + return nil, err } - chart, err := loader.Load(chartPath) - if err != nil { - return nil, nil, err + // Save it into our project's helm-charts directory. + if err := chartutil.SaveDir(chrt, chartsDir); err != nil { + return nil, err } - return r, chart, nil -} - -func fetchChart(destDir string, opts CreateOptions) (*golang.Options, *chart.Chart, error) { - var ( - chart *chart.Chart - err error - ) - if _, err = os.Stat(opts.Chart); err == nil { - chart, err = createChartFromDisk(destDir, opts.Chart) - } else { - chart, err = createChartFromRemote(destDir, opts) - } - if err != nil { - return nil, nil, err - } + chartDir := filepath.Join(chartsDir, chrt.Name()) - chartName := chart.Name() - if len(opts.GVK.Group) == 0 { - opts.GVK.Group = DefaultGroup - } - if len(opts.GVK.Version) == 0 { - opts.GVK.Version = DefaultVersion - } - if len(opts.GVK.Kind) == 0 { - opts.GVK.Kind = strcase.ToCamel(chartName) + // Fetch dependencies + if err := fetchChartDependencies(chartDir); err != nil { + return nil, fmt.Errorf("failed to fetch chart dependencies: %w", err) } - r := &golang.Options{} - r.Namespaced = true - r.Domain = opts.Domain - r.Group = opts.GVK.Group - r.Version = opts.GVK.Version - r.Kind = opts.GVK.Kind - - return r, chart, nil -} - -func createChartFromDisk(destDir, source string) (*chart.Chart, error) { - chart, err := loader.Load(source) + // Reload chart in case dependencies changed + chrt, err = loader.Load(chartDir) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to reload chart: %w", err) } - // Save it into our project's helm-charts directory. - if err := chartutil.SaveDir(chart, destDir); err != nil { - return nil, err - } - return chart, nil + fmt.Printf("Created %s\n", filepath.Join(HelmChartsDir, chrt.Name())) + return chrt, nil } -func createChartFromRemote(destDir string, opts CreateOptions) (*chart.Chart, error) { +func downloadChart(opts Options) (string, string, error) { settings := cli.New() getters := getter.All(settings) c := downloader.ChartDownloader{ @@ -241,27 +179,22 @@ func createChartFromRemote(destDir string, opts CreateOptions) (*chart.Chart, er if opts.Repo != "" { chartURL, err := repo.FindChartInRepoURL(opts.Repo, opts.Chart, opts.Version, "", "", "", getters) if err != nil { - return nil, err + return "", "", err } opts.Chart = chartURL } tmpDir, err := ioutil.TempDir("", "osdk-helm-chart") if err != nil { - return nil, err + return "", "", err } - defer func() { - if err := os.RemoveAll(tmpDir); err != nil { - log.Errorf("Failed to remove temporary directory %s: %s", tmpDir, err) - } - }() chartArchive, _, err := c.DownloadTo(opts.Chart, opts.Version, tmpDir) if err != nil { - return nil, err + return "", "", err } - return createChartFromDisk(destDir, chartArchive) + return chartArchive, tmpDir, nil } func fetchChartDependencies(chartPath string) error { diff --git a/internal/plugins/helm/v1/chartutil/chart_test.go b/internal/plugins/helm/v1/chartutil/chart_test.go index bd12af2374e..4ef279b73a1 100644 --- a/internal/plugins/helm/v1/chartutil/chart_test.go +++ b/internal/plugins/helm/v1/chartutil/chart_test.go @@ -18,18 +18,18 @@ import ( "fmt" "os" "path/filepath" + "strings" "testing" "github.com/stretchr/testify/assert" + "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/repo/repotest" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/chartutil" ) -func TestCreateChart(t *testing.T) { +func TestNewOrLoadChart(t *testing.T) { srv, err := repotest.NewTempServerWithCleanup(t, "testdata/*.tgz") if err != nil { t.Fatalf("Failed to create new temp server: %s", err) @@ -45,11 +45,8 @@ func TestCreateChart(t *testing.T) { latestVersion = "1.2.3" previousVersion = "1.2.0" nonExistentVersion = "0.0.1" - customGroup = "example.com" - customVersion = "v1" customKind = "MyApp" customExpectName = "myapp" - expectDerivedKind = "TestChart" ) testCases := []createChartTestCase{ @@ -57,10 +54,6 @@ func TestCreateChart(t *testing.T) { name: "from scaffold no apiVersion", expectErr: true, }, - { - name: "from scaffold no kind", - expectErr: true, - }, { name: "version without helm chart", helmChartVersion: latestVersion, @@ -78,48 +71,32 @@ func TestCreateChart(t *testing.T) { expectErr: true, }, { - name: "from scaffold with apiVersion and kind", - group: customGroup, - version: customVersion, + name: "from scaffold with kind", kind: customKind, - expectResource: mustNewResource(customGroup, customVersion, customKind), expectChartName: customExpectName, expectChartVersion: "0.1.0", }, { name: "from directory", helmChart: filepath.Join(".", "testdata", chartName), - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, { name: "from archive", helmChart: filepath.Join(".", "testdata", fmt.Sprintf("%s-%s.tgz", chartName, latestVersion)), - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, { name: "from url", helmChart: fmt.Sprintf("%s/%s-%s.tgz", srv.URL(), chartName, latestVersion), - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, { name: "from repo and name implicit latest", helmChart: "test/" + chartName, - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), - expectChartName: chartName, - expectChartVersion: latestVersion, - }, - { - name: "from repo and name implicit latest with apiVersion", - helmChart: "test/" + chartName, - group: customGroup, - version: customVersion, - expectResource: mustNewResource(customGroup, customVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -127,17 +104,6 @@ func TestCreateChart(t *testing.T) { name: "from repo and name implicit latest with kind", helmChart: "test/" + chartName, kind: customKind, - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, customKind), - expectChartName: chartName, - expectChartVersion: latestVersion, - }, - { - name: "from repo and name implicit latest with apiVersion and kind", - helmChart: "test/" + chartName, - group: customGroup, - version: customVersion, - kind: customKind, - expectResource: mustNewResource(customGroup, customVersion, customKind), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -145,7 +111,6 @@ func TestCreateChart(t *testing.T) { name: "from repo and name explicit latest", helmChart: "test/" + chartName, helmChartVersion: latestVersion, - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -153,7 +118,6 @@ func TestCreateChart(t *testing.T) { name: "from repo and name explicit previous", helmChart: "test/" + chartName, helmChartVersion: previousVersion, - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: previousVersion, }, @@ -161,7 +125,6 @@ func TestCreateChart(t *testing.T) { name: "from name and repo url implicit latest", helmChart: chartName, helmChartRepo: srv.URL(), - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -170,7 +133,6 @@ func TestCreateChart(t *testing.T) { helmChart: chartName, helmChartRepo: srv.URL(), helmChartVersion: latestVersion, - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: latestVersion, }, @@ -179,7 +141,6 @@ func TestCreateChart(t *testing.T) { helmChart: chartName, helmChartRepo: srv.URL(), helmChartVersion: previousVersion, - expectResource: mustNewResource(chartutil.DefaultGroup, chartutil.DefaultVersion, expectDerivedKind), expectChartName: chartName, expectChartVersion: previousVersion, }, @@ -195,29 +156,16 @@ func TestCreateChart(t *testing.T) { type createChartTestCase struct { name string - group string - version string kind string helmChart string helmChartVersion string helmChartRepo string - expectResource *golang.Options expectChartName string expectChartVersion string expectErr bool } -func mustNewResource(group, version, kind string) *golang.Options { - r := &golang.Options{ - Namespaced: true, - Group: group, - Version: version, - Kind: kind, - } - return r -} - func runTestCase(t *testing.T, testDir string, tc createChartTestCase) { outputDir := filepath.Join(testDir, "output") assert.NoError(t, os.Mkdir(outputDir, 0755)) @@ -232,17 +180,20 @@ func runTestCase(t *testing.T, testDir string, tc createChartTestCase) { defer os.Unsetenv("HELM_REPOSITORY_CONFIG") defer os.Unsetenv("HELM_REPOSITORY_CACHE") - opts := chartutil.CreateOptions{ - GVK: schema.GroupVersionKind{ - Group: tc.group, - Version: tc.version, - Kind: tc.kind, - }, - Chart: tc.helmChart, - Version: tc.helmChartVersion, - Repo: tc.helmChartRepo, + var ( + chrt *chart.Chart + err error + ) + if tc.helmChart != "" { + opts := chartutil.Options{ + Chart: tc.helmChart, + Version: tc.helmChartVersion, + Repo: tc.helmChartRepo, + } + chrt, err = chartutil.LoadChart(outputDir, opts) + } else { + chrt, err = chartutil.NewChart(outputDir, strings.ToLower(tc.kind)) } - resource, chrt, err := chartutil.CreateChart(outputDir, opts) if tc.expectErr { assert.Error(t, err) return @@ -251,7 +202,6 @@ func runTestCase(t *testing.T, testDir string, tc createChartTestCase) { if !assert.NoError(t, err) { return } - assert.Equal(t, tc.expectResource, resource) assert.Equal(t, tc.expectChartName, chrt.Name()) assert.Equal(t, tc.expectChartVersion, chrt.Metadata.Version) diff --git a/internal/plugins/helm/v1/init.go b/internal/plugins/helm/v1/init.go index 9b75c74f037..9186c5d3bc5 100644 --- a/internal/plugins/helm/v1/init.go +++ b/internal/plugins/helm/v1/init.go @@ -20,39 +20,46 @@ import ( "path/filepath" "strings" + "github.com/spf13/afero" "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/util/validation" + "sigs.k8s.io/kubebuilder/v3/pkg/cli" "sigs.k8s.io/kubebuilder/v3/pkg/config" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery/util" "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" - "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/chartutil" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds" - manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2" - scorecardv2 "github.com/operator-framework/operator-sdk/internal/plugins/scorecard/v2" +) + +const ( + groupFlag = "group" + versionFlag = "version" + kindFlag = "kind" + + defaultGroupFlagValue = "" + defaultVersionFlagValue = "" + defaultKindFlagValue = "" ) type initSubcommand struct { - config config.Config - options *golang.Options - apiPlugin createAPISubcommand + apiSubcommand createAPISubcommand + + config config.Config // For help text. commandName string // Flags + options cli.ResourceOptions + domain string projectName string } -var ( - _ plugin.InitSubcommand = &initSubcommand{} - _ cmdutil.RunOptions = &initSubcommand{} -) +var _ plugin.InitSubcommand = &initSubcommand{} // UpdateContext define plugin context -func (p *initSubcommand) UpdateContext(ctx *plugin.Context) { - ctx.Description = `Initialize a new Helm-based operator project. +func (p *initSubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { + subcmdMeta.Description = `Initialize a new Helm-based operator project. Writes the following files: - a helm-charts directory with the chart(s) to build releases from @@ -63,7 +70,7 @@ Writes the following files: - a Patch file for customizing image for manager manifests - a Patch file for enabling prometheus metrics ` - ctx.Examples = fmt.Sprintf(` $ %[1]s init --plugins=%[2]s \ + subcmdMeta.Examples = fmt.Sprintf(` $ %[1]s init --plugins=%[2]s \ --domain=example.com \ --group=apps \ --version=v1alpha1 \ @@ -110,118 +117,89 @@ Writes the following files: $ %[1]s init --plugins=%[2]s \ --domain=example.com \ --helm-chart=/path/to/local/chart-archives/app-1.2.3.tgz -`, - ctx.CommandName, pluginKey, - ) +`, cliMeta.CommandName, pluginKey) - p.commandName = ctx.CommandName + p.commandName = cliMeta.CommandName } -// BindFlags will set the flags for the plugin func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) { fs.SortFlags = false - p.options = &golang.Options{} - fs.StringVar(&p.options.Domain, "domain", "my.domain", "domain for groups") + fs.StringVar(&p.domain, "domain", "my.domain", "domain for groups") fs.StringVar(&p.projectName, "project-name", "", "name of this project, the default being directory name") - p.apiPlugin.BindFlags(fs) -} - -// InjectConfig will inject the PROJECT file/config in the plugin -func (p *initSubcommand) InjectConfig(c config.Config) { - // v3 project configs get a 'layout' value. - _ = c.SetLayout(pluginKey) - p.config = c - p.apiPlugin.config = p.config -} - -// Run will call the plugin actions -func (p *initSubcommand) Run() error { - if err := cmdutil.Run(p); err != nil { - return err - } - - // Run SDK phase 2 plugins. - if err := p.runPhase2(); err != nil { - return err - } - return nil + fs.StringVar(&p.options.Group, groupFlag, defaultGroupFlagValue, "resource Group") + fs.StringVar(&p.options.Version, versionFlag, defaultVersionFlagValue, "resource Version") + fs.StringVar(&p.options.Kind, kindFlag, defaultKindFlagValue, "resource Kind") + p.apiSubcommand.BindFlags(fs) } -// SDK phase 2 plugins. -func (p *initSubcommand) runPhase2() error { - if err := manifestsv2.RunInit(p.config); err != nil { - return err - } - if err := scorecardv2.RunInit(p.config); err != nil { - return err - } - - if p.options.DoAPI { - if err := p.apiPlugin.runPhase2(); err != nil { - return err - } - } - - return nil -} +func (p *initSubcommand) InjectConfig(c config.Config) error { + p.config = c -// Validate perform the required validations for this plugin -func (p *initSubcommand) Validate() error { - // Set values in the config - if err := p.config.SetProjectName(p.projectName); err != nil { - return err - } - if err := p.config.SetDomain(p.options.Domain); err != nil { + if err := p.config.SetDomain(p.domain); err != nil { return err } - // Check if the project name is a valid k8s namespace (DNS 1123 label). - if p.config.GetProjectName() == "" { + // Assign a default project name + if p.projectName == "" { dir, err := os.Getwd() if err != nil { return fmt.Errorf("error getting current directory: %v", err) } - if err = p.config.SetProjectName(strings.ToLower(filepath.Base(dir))); err != nil { - return err - } + p.projectName = strings.ToLower(filepath.Base(dir)) } - - if err := validation.IsDNS1123Label(p.config.GetProjectName()); err != nil { - return fmt.Errorf("project name (%s) is invalid: %v", p.config.GetProjectName(), err) + // Check if the project name is a valid k8s namespace (DNS 1123 label). + if err := validation.IsDNS1123Label(p.projectName); err != nil { + return fmt.Errorf("project name (%s) is invalid: %v", p.projectName, err) } - - defaultOpts := chartutil.CreateOptions{CRDVersion: "v1"} - if !p.apiPlugin.createOptions.GVK.Empty() || p.apiPlugin.createOptions != defaultOpts { - p.options.DoAPI = true - return p.apiPlugin.Validate() + if err := p.config.SetProjectName(p.projectName); err != nil { + return err } return nil } -// GetScaffolder returns cmdutil.Scaffolder which will be executed due the RunOptions interface implementation -func (p *initSubcommand) GetScaffolder() (cmdutil.Scaffolder, error) { - var ( - apiScaffolder cmdutil.Scaffolder - err error - ) - if p.options.DoAPI { - apiScaffolder, err = p.apiPlugin.GetScaffolder() - if err != nil { - return nil, err - } - } - return scaffolds.NewInitScaffolder(p.config, apiScaffolder), nil +func (p *initSubcommand) Scaffold(fs afero.Fs) error { + scaffolder := scaffolds.NewInitScaffolder(p.config) + scaffolder.InjectFS(fs) + return scaffolder.Scaffold() } // PostScaffold will run the required actions after the default plugin scaffold func (p *initSubcommand) PostScaffold() error { - - if p.options.DoAPI { - return p.apiPlugin.PostScaffold() + doAPI := p.options.Group != defaultGroupFlagValue || + p.options.Version != defaultVersionFlagValue || + p.options.Kind != defaultKindFlagValue || + p.apiSubcommand.options.chartOptions.Chart != defaultHelmChartFlagValue + if !doAPI { + fmt.Printf("Next: define a resource with:\n$ %s create api\n", p.commandName) + } else { + args := []string{"create", "api"} + if p.options.Group != defaultGroupFlagValue { + args = append(args, fmt.Sprintf("--%s", groupFlag), p.options.Group) + } + if p.options.Version != defaultVersionFlagValue { + args = append(args, fmt.Sprintf("--%s", versionFlag), p.options.Version) + } + if p.options.Kind != defaultKindFlagValue { + args = append(args, fmt.Sprintf("--%s", kindFlag), p.options.Kind) + } + if p.apiSubcommand.options.CRDVersion != defaultCrdVersionFlagValue { + args = append(args, fmt.Sprintf("--%s", crdVersionFlag), p.apiSubcommand.options.CRDVersion) + } + if p.apiSubcommand.options.chartOptions.Chart != defaultHelmChartFlagValue { + args = append(args, fmt.Sprintf("--%s", helmChartFlag), p.apiSubcommand.options.chartOptions.Chart) + } + if p.apiSubcommand.options.chartOptions.Repo != defaultHelmChartRepoFlagValue { + args = append(args, fmt.Sprintf("--%s", helmChartRepoFlag), p.apiSubcommand.options.chartOptions.Repo) + } + if p.apiSubcommand.options.chartOptions.Version != defaultHelmChartVersionFlagValue { + args = append(args, fmt.Sprintf("--%s", helmChartVersionFlag), p.apiSubcommand.options.chartOptions.Version) + } + if err := util.RunCmd("Creating the API", os.Args[0], args...); err != nil { + return err + } } - fmt.Printf("Next: define a resource with:\n$ %s create api\n", p.commandName) return nil } diff --git a/internal/plugins/helm/v1/plugin.go b/internal/plugins/helm/v1/plugin.go index 6f956f6a7f3..7ca3ec963a4 100644 --- a/internal/plugins/helm/v1/plugin.go +++ b/internal/plugins/helm/v1/plugin.go @@ -22,7 +22,7 @@ import ( "github.com/operator-framework/operator-sdk/internal/plugins" ) -const pluginName = "helm" + plugins.DefaultNameQualifier +const pluginName = "base.helm" + plugins.DefaultNameQualifier var ( supportedProjectVersions = []config.Version{cfgv3.Version} diff --git a/internal/plugins/helm/v1/scaffolds/api.go b/internal/plugins/helm/v1/scaffolds/api.go index 29c7db31843..34abcd2e478 100644 --- a/internal/plugins/helm/v1/scaffolds/api.go +++ b/internal/plugins/helm/v1/scaffolds/api.go @@ -18,17 +18,16 @@ limitations under the License. package scaffolds import ( - "errors" "fmt" - "os" "path/filepath" + "github.com/spf13/afero" + "helm.sh/helm/v3/pkg/chart" "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" + "sigs.k8s.io/kubebuilder/v3/pkg/plugins" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/chartutil" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds/internal/templates" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd" @@ -36,91 +35,55 @@ import ( "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds/internal/templates/config/samples" ) -var _ cmdutil.Scaffolder = &apiScaffolder{} +var _ plugins.Scaffolder = &apiScaffolder{} // apiScaffolder contains configuration for generating scaffolding for Go type // representing the API and controller that implements the behavior for the API. type apiScaffolder struct { - config config.Config - opts chartutil.CreateOptions + fs afero.Fs + + config config.Config + resource resource.Resource + chart *chart.Chart } -// NewAPIScaffolder returns a new Scaffolder for API/controller creation operations -func NewAPIScaffolder(config config.Config, opts chartutil.CreateOptions) cmdutil.Scaffolder { +// NewAPIScaffolder returns a new plugins.Scaffolder for API/controller creation operations +func NewAPIScaffolder(cfg config.Config, res resource.Resource, chrt *chart.Chart) plugins.Scaffolder { return &apiScaffolder{ - config: config, - opts: opts, + config: cfg, + resource: res, + chart: chrt, } } -// Scaffold implements Scaffolder -func (s *apiScaffolder) Scaffold() error { - return s.scaffold() -} - -func (s *apiScaffolder) newUniverse(r *resource.Resource) *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - model.WithResource(r), - ) +// InjectFS implements plugins.Scaffolder +func (s *apiScaffolder) InjectFS(fs afero.Fs) { + s.fs = fs } -func (s *apiScaffolder) scaffold() error { - projectDir, err := os.Getwd() - if err != nil { - return err - } - resourceOptions, chrt, err := chartutil.CreateChart(projectDir, s.opts) - if err != nil { - return err - } - - resourceOptions.DoAPI = true - //todo(camilamacedo86): replace the options by kubernetes-sigs/kubebuilder#1974 - if err := resourceOptions.Validate(); err != nil { +// Scaffold implements plugins.Scaffolder +func (s *apiScaffolder) Scaffold() error { + if err := s.config.UpdateResource(s.resource); err != nil { return err } - // Check that resource doesn't exist - if s.config.HasResource(resourceOptions.GVK()) { - return errors.New("the API resource already exists") - } - - // Check that the provided group can be added to the project - if !s.config.IsMultiGroup() && s.config.ResourcesLength() != 0 && !s.config.HasGroup(resourceOptions.Group) { - return errors.New("multiple groups are not allowed by default, to enable multi-group set 'multigroup: true' in your PROJECT file") - } - - resource := resourceOptions.NewResource(s.config) - - resource.Domain = s.config.GetDomain() - - // remove the path since is not a Golang project - resource.Path = "" - - // add the resource API info to complain with project-version=3 - // todo: ensure that this information is properly returned from - // resource.newResource in upstream ( see kubernetes-sigs/kubebuilder#1974) - // and then, remove it. - resource.API.Namespaced = true - resource.API.CRDVersion = s.opts.CRDVersion - - if err := s.config.UpdateResource(resource); err != nil { - return err - } + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(s.fs, + machinery.WithConfig(s.config), + machinery.WithResource(&s.resource), + ) - chartPath := filepath.Join(chartutil.HelmChartsDir, chrt.Metadata.Name) - if err := machinery.NewScaffold().Execute( - s.newUniverse(&resource), + chartPath := filepath.Join(chartutil.HelmChartsDir, s.chart.Name()) + if err := scaffold.Execute( &templates.WatchesUpdater{ChartPath: chartPath}, - &crd.CRD{CRDVersion: s.opts.CRDVersion}, + &crd.CRD{}, &crd.Kustomization{}, &rbac.CRDEditorRole{}, &rbac.CRDViewerRole{}, - &rbac.ManagerRoleUpdater{Chart: chrt}, - &samples.CRDSample{ChartPath: chartPath, Chart: chrt}, + &rbac.ManagerRoleUpdater{Chart: s.chart}, + &samples.CRDSample{ChartPath: chartPath, Chart: s.chart}, ); err != nil { - return fmt.Errorf("error scaffolding APIs: %v", err) + return fmt.Errorf("error scaffolding APIs: %w", err) } return nil diff --git a/internal/plugins/helm/v1/scaffolds/init.go b/internal/plugins/helm/v1/scaffolds/init.go index a696f681b93..48558a8d271 100644 --- a/internal/plugins/helm/v1/scaffolds/init.go +++ b/internal/plugins/helm/v1/scaffolds/init.go @@ -20,11 +20,11 @@ package scaffolds import ( "os" + "github.com/spf13/afero" "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" + "sigs.k8s.io/kubebuilder/v3/pkg/plugins" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/cmdutil" - "github.com/operator-framework/operator-sdk/internal/kubebuilder/machinery" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/chartutil" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds/internal/templates" "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault" @@ -44,44 +44,37 @@ const ( // helmOperatorVersion is set to the version of helm-operator at compile-time. var helmOperatorVersion = version.ImageVersion -var _ cmdutil.Scaffolder = &initScaffolder{} +var _ plugins.Scaffolder = &initScaffolder{} type initScaffolder struct { - config config.Config - apiScaffolder cmdutil.Scaffolder + config config.Config + + fs afero.Fs } -// NewInitScaffolder returns a new Scaffolder for project initialization operations -func NewInitScaffolder(config config.Config, apiScaffolder cmdutil.Scaffolder) cmdutil.Scaffolder { +// NewInitScaffolder returns a new plugins.Scaffolder for project initialization operations +func NewInitScaffolder(config config.Config) plugins.Scaffolder { return &initScaffolder{ - config: config, - apiScaffolder: apiScaffolder, + config: config, } } -func (s *initScaffolder) newUniverse() *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - ) +// InjectFS implements plugins.Scaffolder +func (s *initScaffolder) InjectFS(fs afero.Fs) { + s.fs = fs } // Scaffold implements Scaffolder func (s *initScaffolder) Scaffold() error { - if err := s.scaffold(); err != nil { - return err - } - if s.apiScaffolder != nil { - return s.apiScaffolder.Scaffold() - } - return nil -} + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(s.fs, + machinery.WithConfig(s.config), + ) -func (s *initScaffolder) scaffold() error { if err := os.MkdirAll(chartutil.HelmChartsDir, 0755); err != nil { return err } - return machinery.NewScaffold().Execute( - s.newUniverse(), + return scaffold.Execute( &templates.Dockerfile{ HelmOperatorVersion: helmOperatorVersion, }, diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/crd.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/crd.go index 842a1ae0b85..71a4152546f 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/crd.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/crd.go @@ -15,22 +15,19 @@ package crd import ( - "errors" "fmt" "path/filepath" "github.com/kr/text" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRD{} +var _ machinery.Template = &CRD{} // CRD scaffolds a manifest for CRD sample. type CRD struct { - file.TemplateMixin - file.ResourceMixin - - CRDVersion string + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template @@ -40,13 +37,8 @@ func (f *CRD) SetTemplateDefaults() error { } f.Path = f.Resource.Replacer().Replace(f.Path) - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error - if f.CRDVersion == "" { - f.CRDVersion = "v1" - } else if f.CRDVersion != "v1" && f.CRDVersion != "v1beta1" { - return errors.New("the CRD version value must be either 'v1' or 'v1beta1'") - } f.TemplateBody = fmt.Sprintf(crdTemplate, text.Indent(openAPIV3SchemaTemplate, " "), text.Indent(openAPIV3SchemaTemplate, " "), @@ -55,7 +47,7 @@ func (f *CRD) SetTemplateDefaults() error { } const crdTemplate = `--- -apiVersion: apiextensions.k8s.io/{{ .CRDVersion }} +apiVersion: apiextensions.k8s.io/{{ .Resource.API.CRDVersion }} kind: CustomResourceDefinition metadata: name: {{ .Resource.Plural }}.{{ .Resource.QualifiedGroup }} @@ -67,7 +59,7 @@ spec: plural: {{ .Resource.Plural }} singular: {{ .Resource.Kind | lower }} scope: Namespaced -{{- if eq .CRDVersion "v1beta1" }} +{{- if eq .Resource.API.CRDVersion "v1beta1" }} subresources: status: {} validation: @@ -75,13 +67,13 @@ spec: {{- end }} versions: - name: {{ .Resource.Version }} -{{- if eq .CRDVersion "v1" }} +{{- if eq .Resource.API.CRDVersion "v1" }} schema: %s {{- end }} served: true storage: true -{{- if eq .CRDVersion "v1" }} +{{- if eq .Resource.API.CRDVersion "v1" }} subresources: status: {} {{- end }} diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/kustomization.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/kustomization.go index 7c0cc71def0..9e8b20d263d 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/kustomization.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/crd/kustomization.go @@ -21,19 +21,19 @@ import ( "fmt" "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} -var _ file.Inserter = &Kustomization{} +var _ machinery.Template = &Kustomization{} +var _ machinery.Inserter = &Kustomization{} // Kustomization scaffolds the kustomization file in manager folder. type Kustomization struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } -// SetTemplateDefaults implements file.Template +// SetTemplateDefaults implements machinery.Template func (f *Kustomization) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("config", "crd", "kustomization.yaml") @@ -41,7 +41,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.Path = f.Resource.Replacer().Replace(f.Path) f.TemplateBody = fmt.Sprintf(kustomizationTemplate, - file.NewMarkerFor(f.Path, resourceMarker), + machinery.NewMarkerFor(f.Path, resourceMarker), ) return nil @@ -52,9 +52,9 @@ const ( ) // GetMarkers implements file.Inserter -func (f *Kustomization) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(f.Path, resourceMarker), +func (f *Kustomization) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(f.Path, resourceMarker), } } @@ -64,8 +64,8 @@ const ( ) // GetCodeFragments implements file.Inserter -func (f *Kustomization) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 3) +func (f *Kustomization) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 3) // Generate resource code fragments res := make([]string, 0) @@ -73,7 +73,7 @@ func (f *Kustomization) GetCodeFragments() file.CodeFragmentsMap { // Only store code fragments in the map if the slices are non-empty if len(res) != 0 { - fragments[file.NewMarkerFor(f.Path, resourceMarker)] = res + fragments[machinery.NewMarkerFor(f.Path, resourceMarker)] = res } return fragments diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go index 5c3a108670f..7d7d6be0490 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/auth_proxy_patch.go @@ -20,16 +20,16 @@ package kdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyPatch{} +var _ machinery.Template = &AuthProxyPatch{} // AuthProxyPatch scaffolds the patch file for enabling // prometheus metrics for manager Pod. type AuthProxyPatch struct { - file.TemplateMixin - file.ProjectNameMixin + machinery.TemplateMixin + machinery.ProjectNameMixin } // SetTemplateDefaults implements input.Template @@ -40,7 +40,7 @@ func (f *AuthProxyPatch) SetTemplateDefaults() error { f.TemplateBody = kustomizeAuthProxyPatchTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/kustomization.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/kustomization.go index a5745e7c9a5..fd4d8552e81 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/kustomization.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/kdefault/kustomization.go @@ -20,15 +20,15 @@ package kdefault import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the Kustomization file for the default overlay type Kustomization struct { - file.TemplateMixin - file.ProjectNameMixin + machinery.TemplateMixin + machinery.ProjectNameMixin } // SetTemplateDefaults implements input.Template @@ -39,7 +39,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.TemplateBody = kustomizeTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/kustomization.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/kustomization.go index 93dcfafae83..30b9adbc879 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/kustomization.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/kustomization.go @@ -19,14 +19,14 @@ package manager import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the Kustomization file in manager folder. type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -37,7 +37,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.TemplateBody = kustomizeManagerTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/manager.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/manager.go index 6c59d16fc82..5f54a8ca73d 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/manager.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/manager/manager.go @@ -20,15 +20,15 @@ package manager import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Manager{} +var _ machinery.Template = &Manager{} // Manager scaffolds yaml config for the manager. type Manager struct { - file.TemplateMixin - file.ProjectNameMixin + machinery.TemplateMixin + machinery.ProjectNameMixin // Image is controller manager image name Image string diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/kustomization.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/kustomization.go index a794eea1900..ce0149d0a98 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/kustomization.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/kustomization.go @@ -19,14 +19,14 @@ package prometheus import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the kustomizaiton in the prometheus folder type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/monitor.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/monitor.go index d092c6b8a2a..375e91cda58 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/monitor.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/prometheus/monitor.go @@ -19,14 +19,14 @@ package prometheus import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ServiceMonitor{} +var _ machinery.Template = &ServiceMonitor{} // ServiceMonitor scaffolds an issuer CR and a certificate CR type ServiceMonitor struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go index 2fb69db5d19..6b37da2a364 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyRole{} +var _ machinery.Template = &AuthProxyRole{} // AuthProxyRole scaffolds the config/rbac/auth_proxy_role.yaml file type AuthProxyRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go index 5c52caec328..3af80a15fdd 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_role_binding.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyRoleBinding{} +var _ machinery.Template = &AuthProxyRoleBinding{} // AuthProxyRoleBinding scaffolds the config/rbac/auth_proxy_role_binding_rbac.yaml file type AuthProxyRoleBinding struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go index 25a0a52ac4c..0a64210c3ad 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/auth_proxy_service.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &AuthProxyService{} +var _ machinery.Template = &AuthProxyService{} // AuthProxyService scaffolds the config/rbac/auth_proxy_service.yaml file type AuthProxyService struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go index 6553210ce84..e6607501acf 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/client_cluster_role.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ClientClusterRole{} +var _ machinery.Template = &ClientClusterRole{} // ClientClusterRole scaffolds the config/rbac/client_clusterrole.yaml file type ClientClusterRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go index 44b02767f2a..f20246b333b 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go @@ -19,15 +19,15 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRDEditorRole{} +var _ machinery.Template = &CRDEditorRole{} // CRDEditorRole scaffolds the config/rbac/_editor_role.yaml type CRDEditorRole struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go index 3dee9614946..171172c4d03 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go @@ -19,15 +19,15 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &CRDViewerRole{} +var _ machinery.Template = &CRDViewerRole{} // CRDViewerRole scaffolds the config/rbac/_viewer_role.yaml type CRDViewerRole struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/kustomization.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/kustomization.go index 74c3ef6e050..7e994edbd06 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/kustomization.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/kustomization.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Kustomization{} +var _ machinery.Template = &Kustomization{} // Kustomization scaffolds the Kustomization file in rbac folder. type Kustomization struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -37,7 +37,7 @@ func (f *Kustomization) SetTemplateDefaults() error { f.TemplateBody = kustomizeRBACTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error return nil } diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go index f029a4286d3..279991608e6 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &LeaderElectionRole{} +var _ machinery.Template = &LeaderElectionRole{} // LeaderElectionRole scaffolds the config/rbac/leader_election_role.yaml file type LeaderElectionRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go index 994c3179d60..86402225ae7 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/leader_election_role_binding.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &LeaderElectionRoleBinding{} +var _ machinery.Template = &LeaderElectionRoleBinding{} // LeaderElectionRoleBinding scaffolds the config/rbac/leader_election_role_binding.yaml file type LeaderElectionRoleBinding struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role.go index 8472ff19c75..2b8a6bffe62 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role.go @@ -32,17 +32,17 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/discovery" crconfig "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/yaml" ) -var _ file.Template = &ManagerRole{} +var _ machinery.Template = &ManagerRole{} var defaultRoleFile = filepath.Join("config", "rbac", "role.yaml") // ManagerRole scaffolds the role.yaml file type ManagerRole struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -52,16 +52,16 @@ func (f *ManagerRole) SetTemplateDefaults() error { } f.TemplateBody = fmt.Sprintf(roleTemplate, - file.NewMarkerFor(f.Path, rulesMarker), + machinery.NewMarkerFor(f.Path, rulesMarker), ) return nil } -var _ file.Inserter = &ManagerRoleUpdater{} +var _ machinery.Inserter = &ManagerRoleUpdater{} type ManagerRoleUpdater struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin Chart *chart.Chart SkipDefaultRules bool @@ -72,22 +72,22 @@ func (*ManagerRoleUpdater) GetPath() string { return defaultRoleFile } -func (*ManagerRoleUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite +func (*ManagerRoleUpdater) GetIfExistsAction() machinery.IfExistsAction { + return machinery.OverwriteFile } const ( rulesMarker = "rules" ) -func (f *ManagerRoleUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(defaultRoleFile, rulesMarker), +func (f *ManagerRoleUpdater) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(defaultRoleFile, rulesMarker), } } -func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) +func (f *ManagerRoleUpdater) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 1) // If resource is not being provided we are creating the file, not updating it if f.Resource == nil { @@ -113,7 +113,7 @@ func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { rules := []string{buf.String()} if len(rules) != 0 { - fragments[file.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules + fragments[machinery.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules } return fragments } diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go index 544f465635b..53dfd877bb5 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/rbac/manager_role_binding.go @@ -19,14 +19,14 @@ package rbac import ( "path/filepath" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &ManagerRoleBinding{} +var _ machinery.Template = &ManagerRoleBinding{} // ManagerRoleBinding scaffolds the config/rbac/role_binding.yaml file type ManagerRoleBinding struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/config/samples/crd_sample.go b/internal/plugins/helm/v1/scaffolds/internal/templates/config/samples/crd_sample.go index b33681fb427..10b2daef6a1 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/config/samples/crd_sample.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/config/samples/crd_sample.go @@ -24,17 +24,17 @@ import ( "text/template" "helm.sh/helm/v3/pkg/chart" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" "sigs.k8s.io/yaml" ) -var _ file.Template = &CRDSample{} -var _ file.UseCustomFuncMap = &CRDSample{} +var _ machinery.Template = &CRDSample{} +var _ machinery.UseCustomFuncMap = &CRDSample{} // CRDSample scaffolds a manifest for CRD sample. type CRDSample struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin ChartPath string Chart *chart.Chart @@ -48,7 +48,7 @@ func (f *CRDSample) SetTemplateDefaults() error { } f.Path = f.Resource.Replacer().Replace(f.Path) - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error if len(f.Spec) == 0 { f.Spec = defaultSpecTemplate @@ -74,9 +74,9 @@ func indent(spaces int, v string) string { return pad + strings.Replace(v, "\n", "\n"+pad, -1) } -// GetFuncMap implements file.UseCustomFuncMap +// GetFuncMap implements machinery.UseCustomFuncMap func (f *CRDSample) GetFuncMap() template.FuncMap { - fm := file.DefaultFuncMap() + fm := machinery.DefaultFuncMap() fm["indent"] = indent return fm } diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/dockerfile.go b/internal/plugins/helm/v1/scaffolds/internal/templates/dockerfile.go index 14f17dfc39f..c3541f04b20 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/dockerfile.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/dockerfile.go @@ -17,14 +17,14 @@ package templates import ( "errors" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Dockerfile{} +var _ machinery.Template = &Dockerfile{} // Dockerfile scaffolds a Dockerfile for building a main type Dockerfile struct { - file.TemplateMixin + machinery.TemplateMixin // HelmOperatorVersion is the version of the Dockerfile's base image. HelmOperatorVersion string diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/gitignore.go b/internal/plugins/helm/v1/scaffolds/internal/templates/gitignore.go index 64cc86d9ce7..a2216975178 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/gitignore.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/gitignore.go @@ -18,14 +18,14 @@ limitations under the License. package templates import ( - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &GitIgnore{} +var _ machinery.Template = &GitIgnore{} // GitIgnore scaffolds the .gitignore file type GitIgnore struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/makefile.go b/internal/plugins/helm/v1/scaffolds/internal/templates/makefile.go index a38f8a6ee1e..d983943964a 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/makefile.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/makefile.go @@ -20,14 +20,14 @@ package templates import ( "errors" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Makefile{} +var _ machinery.Template = &Makefile{} // Makefile scaffolds the Makefile type Makefile struct { - file.TemplateMixin + machinery.TemplateMixin // Image is controller manager image name Image string @@ -47,7 +47,7 @@ func (f *Makefile) SetTemplateDefaults() error { f.TemplateBody = makefileTemplate - f.IfExistsAction = file.Error + f.IfExistsAction = machinery.Error if f.Image == "" { f.Image = "controller:latest" diff --git a/internal/plugins/helm/v1/scaffolds/internal/templates/watches.go b/internal/plugins/helm/v1/scaffolds/internal/templates/watches.go index 5269ae1fd28..b9d337fc86e 100644 --- a/internal/plugins/helm/v1/scaffolds/internal/templates/watches.go +++ b/internal/plugins/helm/v1/scaffolds/internal/templates/watches.go @@ -17,16 +17,16 @@ package templates import ( "fmt" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &Watches{} +var _ machinery.Template = &Watches{} const defaultWatchesFile = "watches.yaml" // Watches scaffolds the watches.yaml file type Watches struct { - file.TemplateMixin + machinery.TemplateMixin } // SetTemplateDefaults implements input.Template @@ -36,16 +36,16 @@ func (f *Watches) SetTemplateDefaults() error { } f.TemplateBody = fmt.Sprintf(watchesTemplate, - file.NewMarkerFor(f.Path, watchMarker), + machinery.NewMarkerFor(f.Path, watchMarker), ) return nil } -var _ file.Inserter = &WatchesUpdater{} +var _ machinery.Inserter = &WatchesUpdater{} type WatchesUpdater struct { - file.TemplateMixin - file.ResourceMixin + machinery.TemplateMixin + machinery.ResourceMixin ChartPath string } @@ -54,22 +54,22 @@ func (*WatchesUpdater) GetPath() string { return defaultWatchesFile } -func (*WatchesUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite +func (*WatchesUpdater) GetIfExistsAction() machinery.IfExistsAction { + return machinery.OverwriteFile } const ( watchMarker = "watch" ) -func (f *WatchesUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(defaultWatchesFile, watchMarker), +func (f *WatchesUpdater) GetMarkers() []machinery.Marker { + return []machinery.Marker{ + machinery.NewMarkerFor(defaultWatchesFile, watchMarker), } } -func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) +func (f *WatchesUpdater) GetCodeFragments() machinery.CodeFragmentsMap { + fragments := make(machinery.CodeFragmentsMap, 1) // If resource is not being provided we are creating the file, not updating it if f.Resource == nil { @@ -82,7 +82,7 @@ func (f *WatchesUpdater) GetCodeFragments() file.CodeFragmentsMap { fmt.Sprintf(watchFragment, f.Resource.QualifiedGroup(), f.Resource.Version, f.Resource.Kind, f.ChartPath)) if len(watches) != 0 { - fragments[file.NewMarkerFor(defaultWatchesFile, watchMarker)] = watches + fragments[machinery.NewMarkerFor(defaultWatchesFile, watchMarker)] = watches } return fragments } diff --git a/internal/plugins/manifests/api.go b/internal/plugins/manifests/api.go deleted file mode 100644 index 91ad9c1c635..00000000000 --- a/internal/plugins/manifests/api.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// TODO: rewrite this when plugins phase 2 is implemented. -package manifests - -import ( - "fmt" - - "sigs.k8s.io/kubebuilder/v3/pkg/config" - cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" - "sigs.k8s.io/kubebuilder/v3/pkg/model" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - - "github.com/operator-framework/operator-sdk/internal/kubebuilder/machinery" -) - -// RunCreateAPI runs the manifests SDK phase 2 plugin. -func RunCreateAPI(cfg config.Config, gvk resource.GVK) error { - // Only run these if project version is v3. - isV3 := cfg.GetVersion().Compare(cfgv3.Version) == 0 - if !isV3 { - return nil - } - - if err := newAPIScaffolder(cfg, gvk).scaffold(); err != nil { - return err - } - - return nil -} - -type apiScaffolder struct { - config config.Config - gvk resource.GVK -} - -func newAPIScaffolder(config config.Config, gvk resource.GVK) *apiScaffolder { - return &apiScaffolder{ - config: config, - gvk: gvk, - } -} - -func (s *apiScaffolder) newUniverse() *model.Universe { - return model.NewUniverse( - model.WithConfig(s.config), - ) -} - -func (s *apiScaffolder) scaffold() error { - var builders []file.Builder - // If the gvk is non-empty, add relevant builders. - if s.gvk.Group != "" || s.gvk.Version != "" || s.gvk.Kind != "" { - builders = append(builders, &kustomization{GroupVersionKind: s.gvk}) - } - - err := machinery.NewScaffold().Execute(s.newUniverse(), builders...) - if err != nil { - return fmt.Errorf("error scaffolding manifests: %v", err) - } - - return nil -} diff --git a/internal/plugins/manifests/v1/api.go b/internal/plugins/manifests/v1/api.go new file mode 100644 index 00000000000..6b660aa9607 --- /dev/null +++ b/internal/plugins/manifests/v1/api.go @@ -0,0 +1,63 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import ( + "fmt" + + "github.com/spf13/afero" + "sigs.k8s.io/kubebuilder/v3/pkg/config" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" + "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" + + "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v1/internal/templates/config/samples" +) + +var _ plugin.CreateAPISubcommand = &createAPISubcommand{} + +type createAPISubcommand struct { + config config.Config + resource *resource.Resource +} + +func (s *createAPISubcommand) InjectConfig(c config.Config) error { + s.config = c + + return nil +} + +func (s *createAPISubcommand) InjectResource(res *resource.Resource) error { + s.resource = res + + return nil +} + +func (s *createAPISubcommand) Scaffold(fs afero.Fs) error { + // Initialize the machinery.Scaffold that will write the files to disk + scaffold := machinery.NewScaffold(fs, + machinery.WithConfig(s.config), + machinery.WithResource(s.resource), + ) + + // If the gvk is non-empty + if s.resource.Group != "" || s.resource.Version != "" || s.resource.Kind != "" { + if err := scaffold.Execute(&samples.Kustomization{}); err != nil { + return fmt.Errorf("error scaffolding manifests: %v", err) + } + } + + return nil +} diff --git a/internal/plugins/manifests/init.go b/internal/plugins/manifests/v1/init.go similarity index 79% rename from internal/plugins/manifests/init.go rename to internal/plugins/manifests/v1/init.go index cdf877ded06..a2941cebc62 100644 --- a/internal/plugins/manifests/init.go +++ b/internal/plugins/manifests/v1/init.go @@ -1,4 +1,4 @@ -// Copyright 2020 The Operator-SDK Authors +// Copyright 2021 The Operator-SDK Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,38 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: rewrite this when plugins phase 2 is implemented. -package manifests +package v1 import ( "fmt" "io/ioutil" "os" + "github.com/spf13/afero" "sigs.k8s.io/kubebuilder/v3/pkg/config" - cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" "github.com/operator-framework/operator-sdk/internal/util/projutil" ) -// RunInit modifies the project scaffolded by kubebuilder's Init plugin. -func RunInit(cfg config.Config) error { - // Only run these if project version is v3. - isV3 := cfg.GetVersion().Compare(cfgv3.Version) == 0 - if !isV3 { - return nil - } +const filePath = "Makefile" + +var _ plugin.InitSubcommand = &initSubcommand{} + +type initSubcommand struct { + config config.Config +} + +func (s *initSubcommand) InjectConfig(c config.Config) error { + s.config = c - // Update the scaffolded Makefile with operator-sdk recipes. - if err := initUpdateMakefile(cfg, "Makefile"); err != nil { - return fmt.Errorf("error updating Makefile: %v", err) - } return nil } -// initUpdateMakefile updates a vanilla kubebuilder Makefile with operator-sdk recipes. -func initUpdateMakefile(cfg config.Config, filePath string) error { - makefileBytes, err := ioutil.ReadFile(filePath) +func (s *initSubcommand) Scaffold(fs afero.Fs) error { + makefileBytes, err := afero.ReadFile(fs, filePath) if err != nil { return err } @@ -52,10 +50,9 @@ func initUpdateMakefile(cfg config.Config, filePath string) error { makefileBytes = append([]byte(makefileBundleVarFragment), makefileBytes...) // Append bundle recipes. - operatorType := projutil.PluginKeyToOperatorType(cfg.GetLayout()) - switch operatorType { + switch projutil.LayoutToOperatorType(s.config.GetLayout()) { case projutil.OperatorTypeUnknown: - return fmt.Errorf("unsupported plugin key %q", cfg.GetLayout()) + return fmt.Errorf("none of the required plugins detected in %q", s.config.GetLayout()) case projutil.OperatorTypeGo: makefileBytes = append(makefileBytes, []byte(makefileBundleFragmentGo)...) default: @@ -65,10 +62,14 @@ func initUpdateMakefile(cfg config.Config, filePath string) error { makefileBytes = append(makefileBytes, []byte(makefileBundleBuildFragment)...) var mode os.FileMode = 0644 - if info, err := os.Stat(filePath); err != nil { + if info, err := fs.Stat(filePath); err == nil { mode = info.Mode() } - return ioutil.WriteFile(filePath, makefileBytes, mode) + if err := ioutil.WriteFile(filePath, makefileBytes, mode); err != nil { + return fmt.Errorf("error updating Makefile: %w", err) + } + + return nil } // Makefile fragments to add to the base Makefile. diff --git a/internal/plugins/manifests/samples.go b/internal/plugins/manifests/v1/internal/templates/config/samples/kustomization.go similarity index 52% rename from internal/plugins/manifests/samples.go rename to internal/plugins/manifests/v1/internal/templates/config/samples/kustomization.go index 9c7c3b2edc5..f75ce966072 100644 --- a/internal/plugins/manifests/samples.go +++ b/internal/plugins/manifests/v1/internal/templates/config/samples/kustomization.go @@ -11,35 +11,34 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package manifests +package samples import ( "fmt" "path/filepath" - "strings" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" ) -var _ file.Template = &kustomization{} -var _ file.Inserter = &kustomization{} - -// kustomization scaffolds or updates the kustomization.yaml in config/samples. -type kustomization struct { - file.TemplateMixin +var ( + _ machinery.Template = &Kustomization{} + _ machinery.Inserter = &Kustomization{} +) - // GroupVersionKind is the sample's gvk to add to this scaffold. - GroupVersionKind resource.GVK +// Kustomization scaffolds or updates the kustomization.yaml in config/samples. +type Kustomization struct { + machinery.TemplateMixin + machinery.ResourceMixin } -// SetTemplateDefaults implements file.Template -func (f *kustomization) SetTemplateDefaults() error { +// SetTemplateDefaults implements machinery.Template +func (f *Kustomization) SetTemplateDefaults() error { if f.Path == "" { f.Path = filepath.Join("config", "samples", "kustomization.yaml") } + f.Path = f.Resource.Replacer().Replace(f.Path) - f.TemplateBody = fmt.Sprintf(kustomizationTemplate, file.NewMarkerFor(f.Path, samplesMarker)) + f.TemplateBody = fmt.Sprintf(kustomizationTemplate, machinery.NewMarkerFor(f.Path, samplesMarker)) return nil } @@ -49,8 +48,8 @@ const ( ) // GetMarkers implements file.Inserter -func (f *kustomization) GetMarkers() []file.Marker { - return []file.Marker{file.NewMarkerFor(f.Path, samplesMarker)} +func (f *Kustomization) GetMarkers() []machinery.Marker { + return []machinery.Marker{machinery.NewMarkerFor(f.Path, samplesMarker)} } const samplesCodeFragment = `- %s @@ -58,14 +57,14 @@ const samplesCodeFragment = `- %s // makeCRFileName returns a Custom Resource example file name in the same format // as kubebuilder's CreateAPI plugin for a gvk. -func makeCRFileName(gvk resource.GVK) string { - return fmt.Sprintf("%s_%s_%s.yaml", gvk.Group, gvk.Version, strings.ToLower(gvk.Kind)) +func (f Kustomization) makeCRFileName() string { + return f.Resource.Replacer().Replace("%[group]_%[version]_%[kind].yaml") } // GetCodeFragments implements file.Inserter -func (f *kustomization) GetCodeFragments() file.CodeFragmentsMap { - return file.CodeFragmentsMap{ - file.NewMarkerFor(f.Path, samplesMarker): []string{fmt.Sprintf(samplesCodeFragment, makeCRFileName(f.GroupVersionKind))}, +func (f *Kustomization) GetCodeFragments() machinery.CodeFragmentsMap { + return machinery.CodeFragmentsMap{ + machinery.NewMarkerFor(f.Path, samplesMarker): []string{fmt.Sprintf(samplesCodeFragment, f.makeCRFileName())}, } } diff --git a/internal/plugins/manifests/v1/plugin.go b/internal/plugins/manifests/v1/plugin.go new file mode 100644 index 00000000000..dd8f12e59ec --- /dev/null +++ b/internal/plugins/manifests/v1/plugin.go @@ -0,0 +1,47 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import ( + "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" + + "github.com/operator-framework/operator-sdk/internal/plugins" +) + +const pluginName = "manifests" + plugins.DefaultNameQualifier + +var ( + supportedProjectVersions = []config.Version{cfgv3.Version} + pluginVersion = plugin.Version{Number: 1} +) + +var ( + _ plugin.Plugin = Plugin{} + _ plugin.Init = Plugin{} + _ plugin.CreateAPI = Plugin{} +) + +type Plugin struct { + initSubcommand + createAPISubcommand +} + +func (Plugin) Name() string { return pluginName } +func (Plugin) Version() plugin.Version { return pluginVersion } +func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions } +func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { return &p.initSubcommand } +func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { return &p.createAPISubcommand } diff --git a/internal/plugins/manifests/v2/plugin.go b/internal/plugins/manifests/v2/plugin.go deleted file mode 100644 index 2365431d250..00000000000 --- a/internal/plugins/manifests/v2/plugin.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "fmt" - - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - - "github.com/operator-framework/operator-sdk/internal/plugins" - "github.com/operator-framework/operator-sdk/internal/plugins/manifests" -) - -const ( - pluginName = "manifests" + plugins.DefaultNameQualifier -) - -var ( - pluginVersion = plugin.Version{Number: 2} - pluginConfigKey = plugin.Key(pluginName, pluginVersion.String()) -) - -// Config configures this plugin, and is saved in the project config file. -type Config struct{} - -// HasPluginConfig returns true if cfg.Layout contains an exact match for this plugin's key. -func HasPluginConfig(cfg config.Config) bool { - info := Config{} - return cfg.DecodePluginConfig(pluginConfigKey, &info) == nil -} - -// RunInit modifies the project scaffolded by kubebuilder's Init plugin. -func RunInit(cfg config.Config) error { - // Only run these if project version is v3. - if err := manifests.RunInit(cfg); err != nil { - return err - } - - // Update the plugin config section with this plugin's configuration. - mCfg := Config{} - if err := cfg.EncodePluginConfig(pluginConfigKey, mCfg); err != nil { - return fmt.Errorf("error writing plugin config for %s: %v", pluginConfigKey, err) - } - - return nil -} - -// RunCreateAPI runs the manifests SDK phase 2 plugin. -func RunCreateAPI(cfg config.Config, gvk resource.GVK) error { - if !HasPluginConfig(cfg) { - return nil - } - return manifests.RunCreateAPI(cfg, gvk) -} diff --git a/internal/plugins/scorecard/init.go b/internal/plugins/scorecard/v1/init.go similarity index 67% rename from internal/plugins/scorecard/init.go rename to internal/plugins/scorecard/v1/init.go index d8cd46bfc37..70e98eed422 100644 --- a/internal/plugins/scorecard/init.go +++ b/internal/plugins/scorecard/v1/init.go @@ -1,4 +1,4 @@ -// Copyright 2020 The Operator-SDK Authors +// Copyright 2021 The Operator-SDK Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,19 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -package scorecard +package v1 import ( "fmt" - "io/ioutil" - "os" "path/filepath" + "github.com/spf13/afero" "sigs.k8s.io/kubebuilder/v3/pkg/config" - cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" - "sigs.k8s.io/kubebuilder/v3/pkg/model/file" + "sigs.k8s.io/kubebuilder/v3/pkg/machinery" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - "github.com/operator-framework/operator-sdk/internal/plugins/util/kustomize" "github.com/operator-framework/operator-sdk/internal/scorecard" "github.com/operator-framework/operator-sdk/internal/version" ) @@ -33,55 +31,54 @@ var ( // defaultTestImageTag points to the latest released scorecard-test image. defaultTestImageTag = fmt.Sprintf("quay.io/operator-framework/scorecard-test:%s", version.ImageVersion) - // defaultDir is the default directory in which to generate kustomize bases and the kustomization.yaml. - defaultDir = filepath.Join("config", "scorecard") + // Directories + outputDir = filepath.Join("config", "scorecard") + basesDir = filepath.Join(outputDir, "bases") + patchesDir = filepath.Join(outputDir, "patches") ) -// RunInit scaffolds kustomize files for kustomizing a scorecard componentconfig. -func RunInit(cfg config.Config) error { - // Only run these if project version is v3. - isV3 := cfg.GetVersion().Compare(cfgv3.Version) == 0 - if !isV3 { - return nil - } +var _ plugin.InitSubcommand = &initSubcommand{} - return generateInit(defaultDir) +type initSubcommand struct { + config config.Config } -// generateInit scaffolds kustomize bundle bases and a kustomization.yaml. -// TODO(estroz): refactor this to be testable (in-mem fs) and easier to read. -func generateInit(outputDir string) error { +func (s *initSubcommand) InjectConfig(c config.Config) error { + s.config = c + + return nil +} - basesDir := filepath.Join(outputDir, "bases") - patchesDir := filepath.Join(outputDir, "patches") +func (s *initSubcommand) Scaffold(fs afero.Fs) error { + // TODO: convert all these files to templates + + // Create the directories for _, dir := range []string{basesDir, patchesDir} { - if err := os.MkdirAll(dir, 0755); err != nil { + if err := fs.MkdirAll(dir, 0755); err != nil { return err } } // Write the scorecard config base. - baseFilePath := filepath.Join(basesDir, scorecard.ConfigFileName) - if err := ioutil.WriteFile(baseFilePath, []byte(configBaseFile), 0666); err != nil { - return fmt.Errorf("error writing default scorecard config: %v", err) + if err := afero.WriteFile(fs, filepath.Join(basesDir, scorecard.ConfigFileName), []byte(configBaseFile), 0666); err != nil { + return fmt.Errorf("error writing default scorecard config: %w", err) } - // Write each patch in patchSet to ".config.yaml" + // Write a ".config.yaml" for each patch in patchSet. patchSet := map[string]string{ "basic": fmt.Sprintf(basicPatchFile, defaultTestImageTag), "olm": fmt.Sprintf(olmPatchFile, defaultTestImageTag), } for name, patchStr := range patchSet { - patchFileName := fmt.Sprintf("%s.config.yaml", name) - if err := ioutil.WriteFile(filepath.Join(patchesDir, patchFileName), []byte(patchStr), 0666); err != nil { - return fmt.Errorf("error writing %s scorecard config patch: %v", name, err) + if err := afero.WriteFile(fs, filepath.Join(patchesDir, fmt.Sprintf("%s.config.yaml", name)), []byte(patchStr), 0666); err != nil { + return fmt.Errorf("error writing %s scorecard config patch: %w", name, err) } } - // Write a kustomization.yaml to outputDir. - markerStr := file.NewMarkerFor("kustomization.yaml", patchesJSON6902Marker).String() - if err := kustomize.Write(outputDir, fmt.Sprintf(scorecardKustomizationFile, markerStr)); err != nil { - return fmt.Errorf("error writing scorecard kustomization.yaml: %v", err) + // Write "kustomization.yaml". + kustomizeContent := fmt.Sprintf(scorecardKustomizationFile, machinery.NewMarkerFor("kustomization.yaml", patchesJSON6902Marker)) + if err := afero.WriteFile(fs, filepath.Join(outputDir, "kustomization.yaml"), []byte(kustomizeContent), 0666); err != nil { + return fmt.Errorf("error writing scorecard kustomization.yaml: %w", err) } return nil @@ -110,9 +107,7 @@ patchesJson6902: // YAML file marker to append to kustomization.yaml files. patchesJSON6902Marker = "patchesJson6902" -) -const ( // configBaseFile is an empty scorecard componentconfig with parallel stages. configBaseFile = `apiVersion: scorecard.operatorframework.io/v1alpha3 kind: Configuration diff --git a/internal/plugins/scorecard/v1/plugin.go b/internal/plugins/scorecard/v1/plugin.go new file mode 100644 index 00000000000..b3c6947657f --- /dev/null +++ b/internal/plugins/scorecard/v1/plugin.go @@ -0,0 +1,44 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1 + +import ( + "sigs.k8s.io/kubebuilder/v3/pkg/config" + cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3" + "sigs.k8s.io/kubebuilder/v3/pkg/plugin" + + "github.com/operator-framework/operator-sdk/internal/plugins" +) + +const pluginName = "scorecard" + plugins.DefaultNameQualifier + +var ( + supportedProjectVersions = []config.Version{cfgv3.Version} + pluginVersion = plugin.Version{Number: 1} +) + +var ( + _ plugin.Plugin = Plugin{} + _ plugin.Init = Plugin{} +) + +type Plugin struct { + initSubcommand +} + +func (Plugin) Name() string { return pluginName } +func (Plugin) Version() plugin.Version { return pluginVersion } +func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions } +func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { return &p.initSubcommand } diff --git a/internal/plugins/scorecard/v2/plugin.go b/internal/plugins/scorecard/v2/plugin.go deleted file mode 100644 index fbce6c3e0a1..00000000000 --- a/internal/plugins/scorecard/v2/plugin.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 The Operator-SDK Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v2 - -import ( - "fmt" - - "sigs.k8s.io/kubebuilder/v3/pkg/config" - "sigs.k8s.io/kubebuilder/v3/pkg/plugin" - - "github.com/operator-framework/operator-sdk/internal/plugins" - "github.com/operator-framework/operator-sdk/internal/plugins/scorecard" -) - -const ( - pluginName = "scorecard" + plugins.DefaultNameQualifier -) - -var ( - pluginVersion = plugin.Version{Number: 2} - pluginConfigKey = plugin.Key(pluginName, pluginVersion.String()) -) - -// Config configures this plugin, and is saved in the project config file. -type Config struct{} - -// RunInit scaffolds kustomize files for kustomizing a scorecard componentconfig. -func RunInit(cfg config.Config) error { - - if err := scorecard.RunInit(cfg); err != nil { - return err - } - - // Update the plugin config section with this plugin's configuration. - mCfg := Config{} - if err := cfg.EncodePluginConfig(pluginConfigKey, mCfg); err != nil { - return fmt.Errorf("error writing plugin config for %s: %v", pluginConfigKey, err) - } - - return nil -} diff --git a/internal/util/projutil/project_util.go b/internal/util/projutil/project_util.go index c40ad137be6..1e3d5d31275 100644 --- a/internal/util/projutil/project_util.go +++ b/internal/util/projutil/project_util.go @@ -116,6 +116,17 @@ func ReadConfig() (config.Config, error) { return c, nil } +// LayoutToOperatorType converts a layout string to an operator project type. +func LayoutToOperatorType(layout string) OperatorType { + for _, pluginKey := range strings.Split(layout, ",") { + operatorType := PluginKeyToOperatorType(pluginKey) + if operatorType != OperatorTypeUnknown { + return operatorType + } + } + return OperatorTypeUnknown +} + // PluginKeyToOperatorType converts a plugin key string to an operator project type. // TODO(estroz): this can probably be made more robust by checking known plugin keys directly. func PluginKeyToOperatorType(pluginKey string) OperatorType { diff --git a/testdata/ansible/memcached-operator/PROJECT b/testdata/ansible/memcached-operator/PROJECT index b2e2c54a2ed..3ed283c56a9 100644 --- a/testdata/ansible/memcached-operator/PROJECT +++ b/testdata/ansible/memcached-operator/PROJECT @@ -1,8 +1,5 @@ domain: example.com layout: ansible.sdk.operatorframework.io/v1 -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} projectName: memcached-operator resources: - api: diff --git a/testdata/go/v2/memcached-operator/PROJECT b/testdata/go/v2/memcached-operator/PROJECT index b5b8ede3711..62b5ab5e26b 100644 --- a/testdata/go/v2/memcached-operator/PROJECT +++ b/testdata/go/v2/memcached-operator/PROJECT @@ -1,8 +1,5 @@ domain: example.com -layout: go.kubebuilder.io/v2 -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} +layout: go.sdk.operatorframework.io/v2 projectName: memcached-operator repo: github.com/example/memcached-operator resources: diff --git a/testdata/go/v3/memcached-operator/PROJECT b/testdata/go/v3/memcached-operator/PROJECT index 96a8ba9a91c..0509ecfb2fb 100644 --- a/testdata/go/v3/memcached-operator/PROJECT +++ b/testdata/go/v3/memcached-operator/PROJECT @@ -1,8 +1,5 @@ domain: example.com -layout: go.kubebuilder.io/v3 -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} +layout: go.sdk.operatorframework.io/v3 projectName: memcached-operator repo: github.com/example/memcached-operator resources: diff --git a/testdata/helm/memcached-operator/PROJECT b/testdata/helm/memcached-operator/PROJECT index d41963fdf33..8ef5472f871 100644 --- a/testdata/helm/memcached-operator/PROJECT +++ b/testdata/helm/memcached-operator/PROJECT @@ -1,8 +1,5 @@ domain: example.com layout: helm.sdk.operatorframework.io/v1 -plugins: - manifests.sdk.operatorframework.io/v2: {} - scorecard.sdk.operatorframework.io/v2: {} projectName: memcached-operator resources: - api: diff --git a/website/content/en/docs/cli/operator-sdk.md b/website/content/en/docs/cli/operator-sdk.md index 5f5e8bc5421..23cfd6b6a6a 100644 --- a/website/content/en/docs/cli/operator-sdk.md +++ b/website/content/en/docs/cli/operator-sdk.md @@ -18,24 +18,28 @@ operator-sdk [flags] ``` The first step is to initialize your project: - operator-sdk init --project-version= --plugins= + operator-sdk init [--plugins= [--project-version=]] is a comma-separated list of plugin keys from the following table and a supported project version for these plugins. - Plugin keys | Supported project versions --------------------------------------+---------------------------- - ansible.sdk.operatorframework.io/v1 | 3 - go.kubebuilder.io/v2 | 2, 3 - go.kubebuilder.io/v3 | 3 - helm.sdk.operatorframework.io/v1 | 3 + Plugin keys | Supported project versions +---------------------------------------+---------------------------- + ansible.sdk.operatorframework.io/v1 | 3 + envtest.sdk.operatorframework.io/v1 | 3 + go.kubebuilder.io/v2 | 2, 3 + go.kubebuilder.io/v3 | 3 + helm.sdk.operatorframework.io/v1 | 3 + manifests.sdk.operatorframework.io/v1 | 3 + scorecard.sdk.operatorframework.io/v1 | 3 For more specific help for the init command of a certain plugins and project version configuration please run: - operator-sdk init --help --project-version= --plugins= + operator-sdk init --help --plugins= [--project-version=] -Default project version: 3 -Default plugin keys: "go.kubebuilder.io/v3" +Default plugin keys: "go.kubebuilder.io/v3,manifests.sdk.operatorframework.io/v1,scorecard.sdk.operatorframework.io/v1" + +Default project version: "3" After the project has been initialized, run operator-sdk --help @@ -46,8 +50,8 @@ to obtain further info about available commands. ``` -h, --help help for operator-sdk - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version + --plugins strings plugin keys to be used for this subcommand execution + --project-version string project version (default "3") --verbose Enable verbose logging ``` @@ -55,7 +59,7 @@ to obtain further info about available commands. * [operator-sdk bundle](../operator-sdk_bundle) - Manage operator bundle metadata * [operator-sdk cleanup](../operator-sdk_cleanup) - Clean up an Operator deployed with the 'run' subcommand -* [operator-sdk completion](../operator-sdk_completion) - Generators for shell completions +* [operator-sdk completion](../operator-sdk_completion) - Load completions for the specified shell * [operator-sdk create](../operator-sdk_create) - Scaffold a Kubernetes API or webhook * [operator-sdk edit](../operator-sdk_edit) - This command will edit the project configuration * [operator-sdk generate](../operator-sdk_generate) - Invokes a specific generator diff --git a/website/content/en/docs/cli/operator-sdk_bundle.md b/website/content/en/docs/cli/operator-sdk_bundle.md index 752caaf7b18..73eb72163e1 100644 --- a/website/content/en/docs/cli/operator-sdk_bundle.md +++ b/website/content/en/docs/cli/operator-sdk_bundle.md @@ -27,9 +27,8 @@ https://sdk.operatorframework.io/docs/olm-integration ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_bundle_validate.md b/website/content/en/docs/cli/operator-sdk_bundle_validate.md index 54a36326410..c4717a06f37 100644 --- a/website/content/en/docs/cli/operator-sdk_bundle_validate.md +++ b/website/content/en/docs/cli/operator-sdk_bundle_validate.md @@ -77,9 +77,8 @@ To validate a bundle against the validator for operatorhub.io specifically, in a ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_cleanup.md b/website/content/en/docs/cli/operator-sdk_cleanup.md index 89b74ffea1e..dbd8fed5fce 100644 --- a/website/content/en/docs/cli/operator-sdk_cleanup.md +++ b/website/content/en/docs/cli/operator-sdk_cleanup.md @@ -25,9 +25,8 @@ operator-sdk cleanup [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_completion.md b/website/content/en/docs/cli/operator-sdk_completion.md index fc7aaf3f96b..005845f84fe 100644 --- a/website/content/en/docs/cli/operator-sdk_completion.md +++ b/website/content/en/docs/cli/operator-sdk_completion.md @@ -3,7 +3,14 @@ title: "operator-sdk completion" --- ## operator-sdk completion -Generators for shell completions +Load completions for the specified shell + +### Synopsis + +Output shell completion code for the specified shell. +The shell code must be evaluated to provide interactive completion of operator-sdk commands. +Detailed instructions on how to do this for each shell are provided in their own commands. + ### Options @@ -14,14 +21,14 @@ Generators for shell completions ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO * [operator-sdk](../operator-sdk) - -* [operator-sdk completion bash](../operator-sdk_completion_bash) - Generate bash completions -* [operator-sdk completion zsh](../operator-sdk_completion_zsh) - Generate zsh completions +* [operator-sdk completion bash](../operator-sdk_completion_bash) - Load bash completions +* [operator-sdk completion powershell](../operator-sdk_completion_powershell) - Load powershell completions +* [operator-sdk completion zsh](../operator-sdk_completion_zsh) - Load zsh completions diff --git a/website/content/en/docs/cli/operator-sdk_completion_bash.md b/website/content/en/docs/cli/operator-sdk_completion_bash.md index 0e19d0041f4..18b7f6f3e12 100644 --- a/website/content/en/docs/cli/operator-sdk_completion_bash.md +++ b/website/content/en/docs/cli/operator-sdk_completion_bash.md @@ -3,12 +3,26 @@ title: "operator-sdk completion bash" --- ## operator-sdk completion bash -Generate bash completions +Load bash completions ``` operator-sdk completion bash [flags] ``` +### Examples + +``` +# To load completion for this session, execute: +$ source <(operator-sdk completion bash) + +# To load completions for each session, execute once: +Linux: + $ operator-sdk completion bash > /etc/bash_completion.d/operator-sdk +MacOS: + $ operator-sdk completion bash > /usr/local/etc/bash_completion.d/operator-sdk + +``` + ### Options ``` @@ -18,12 +32,11 @@ operator-sdk completion bash [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO -* [operator-sdk completion](../operator-sdk_completion) - Generators for shell completions +* [operator-sdk completion](../operator-sdk_completion) - Load completions for the specified shell diff --git a/website/content/en/docs/cli/operator-sdk_completion_powershell.md b/website/content/en/docs/cli/operator-sdk_completion_powershell.md new file mode 100644 index 00000000000..e43b3de74ce --- /dev/null +++ b/website/content/en/docs/cli/operator-sdk_completion_powershell.md @@ -0,0 +1,28 @@ +--- +title: "operator-sdk completion powershell" +--- +## operator-sdk completion powershell + +Load powershell completions + +``` +operator-sdk completion powershell [flags] +``` + +### Options + +``` + -h, --help help for powershell +``` + +### Options inherited from parent commands + +``` + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging +``` + +### SEE ALSO + +* [operator-sdk completion](../operator-sdk_completion) - Load completions for the specified shell + diff --git a/website/content/en/docs/cli/operator-sdk_completion_zsh.md b/website/content/en/docs/cli/operator-sdk_completion_zsh.md index d6a37a678b4..e0f64ef1011 100644 --- a/website/content/en/docs/cli/operator-sdk_completion_zsh.md +++ b/website/content/en/docs/cli/operator-sdk_completion_zsh.md @@ -3,12 +3,26 @@ title: "operator-sdk completion zsh" --- ## operator-sdk completion zsh -Generate zsh completions +Load zsh completions ``` operator-sdk completion zsh [flags] ``` +### Examples + +``` +# If shell completion is not already enabled in your environment you will need +# to enable it. You can execute the following once: +$ echo "autoload -U compinit; compinit" >> ~/.zshrc + +# To load completions for each session, execute once: +$ operator-sdk completion zsh > "${fpath[1]}/_operator-sdk" + +# You will need to start a new shell for this setup to take effect. + +``` + ### Options ``` @@ -18,12 +32,11 @@ operator-sdk completion zsh [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO -* [operator-sdk completion](../operator-sdk_completion) - Generators for shell completions +* [operator-sdk completion](../operator-sdk_completion) - Load completions for the specified shell diff --git a/website/content/en/docs/cli/operator-sdk_create.md b/website/content/en/docs/cli/operator-sdk_create.md index 46f97d0e775..abaf571f9f3 100644 --- a/website/content/en/docs/cli/operator-sdk_create.md +++ b/website/content/en/docs/cli/operator-sdk_create.md @@ -18,9 +18,8 @@ Scaffold a Kubernetes API or webhook. ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_create_api.md b/website/content/en/docs/cli/operator-sdk_create_api.md index 54a99272eef..436efb62076 100644 --- a/website/content/en/docs/cli/operator-sdk_create_api.md +++ b/website/content/en/docs/cli/operator-sdk_create_api.md @@ -7,26 +7,63 @@ Scaffold a Kubernetes API ### Synopsis -Scaffold a Kubernetes API. +Scaffold a Kubernetes API by creating a Resource definition and / or a Controller. + +create resource will prompt the user for if it should scaffold the Resource and / or Controller. To only +scaffold a Controller for an existing Resource, select "n" for Resource. To only define +the schema for a Resource without writing a Controller, select "n" for Controller. + +After the scaffold is written, api will run make on the project. -Note: unable to find configuration file, project must be initialized ``` operator-sdk create api [flags] ``` +### Examples + +``` + # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate + operator-sdk create api --group ship --version v1beta1 --kind Frigate + + # Edit the API Scheme + nano api/v1beta1/frigate_types.go + + # Edit the Controller + nano controllers/frigate/frigate_controller.go + + # Edit the Controller Test + nano controllers/frigate/frigate_controller_test.go + + # Install CRDs into the Kubernetes cluster using kubectl apply + make install + + # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config + make run + +``` + ### Options ``` - -h, --help help for api + --controller if set, generate the controller without prompting the user (default true) + --crd-version string version of CustomResourceDefinition to scaffold. Options: [v1, v1beta1] (default "v1") + --force attempt to create resource even if it already exists + --group string resource Group + -h, --help help for api + --kind string resource Kind + --make make generate if true, run make generate after generating files (default true) + --namespaced resource is namespaced (default true) + --plural string resource irregular plural form + --resource if set, generate the resource without prompting the user (default true) + --version string resource Version ``` ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_create_webhook.md b/website/content/en/docs/cli/operator-sdk_create_webhook.md index 80d10749a2d..18395e1288c 100644 --- a/website/content/en/docs/cli/operator-sdk_create_webhook.md +++ b/website/content/en/docs/cli/operator-sdk_create_webhook.md @@ -7,26 +7,46 @@ Scaffold a webhook for an API resource ### Synopsis -Scaffold a webhook for an API resource. +Scaffold a webhook for an API resource. You can choose to scaffold defaulting, +validating and (or) conversion webhooks. -Note: unable to find configuration file, project must be initialized ``` operator-sdk create webhook [flags] ``` +### Examples + +``` + # Create defaulting and validating webhooks for CRD of group ship, version v1beta1 + # and kind Frigate. + operator-sdk create webhook --group ship --version v1beta1 --kind Frigate --defaulting --programmatic-validation + + # Create conversion webhook for CRD of group ship, version v1beta1 and kind Frigate. + operator-sdk create webhook --group ship --version v1beta1 --kind Frigate --conversion + +``` + ### Options ``` - -h, --help help for webhook + --conversion if set, scaffold the conversion webhook + --defaulting if set, scaffold the defaulting webhook + --force attempt to create resource even if it already exists + --group string resource Group + -h, --help help for webhook + --kind string resource Kind + --plural string resource irregular plural form + --programmatic-validation if set, scaffold the validating webhook + --version string resource Version + --webhook-version string version of {Mutating,Validating}WebhookConfigurations to scaffold. Options: [v1, v1beta1] (default "v1") ``` ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_edit.md b/website/content/en/docs/cli/operator-sdk_edit.md index 9d79d0b1b9c..5e89820f765 100644 --- a/website/content/en/docs/cli/operator-sdk_edit.md +++ b/website/content/en/docs/cli/operator-sdk_edit.md @@ -7,26 +7,38 @@ This command will edit the project configuration ### Synopsis -Edit the project configuration. +This command will edit the project configuration. +Features supported: + - Toggle between single or multi group projects. -Note: unable to find configuration file, project must be initialized ``` operator-sdk edit [flags] ``` +### Examples + +``` +# Enable the multigroup layout + operator-sdk edit --multigroup + + # Disable the multigroup layout + operator-sdk edit --multigroup=false + +``` + ### Options ``` - -h, --help help for edit + -h, --help help for edit + --multigroup enable or disable multigroup layout ``` ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_generate.md b/website/content/en/docs/cli/operator-sdk_generate.md index 0c15a9c4707..2c1c0eac9ed 100644 --- a/website/content/en/docs/cli/operator-sdk_generate.md +++ b/website/content/en/docs/cli/operator-sdk_generate.md @@ -19,9 +19,8 @@ code or manifests. ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_generate_bundle.md b/website/content/en/docs/cli/operator-sdk_generate_bundle.md index ce99b4fd427..8b28f9bb616 100644 --- a/website/content/en/docs/cli/operator-sdk_generate_bundle.md +++ b/website/content/en/docs/cli/operator-sdk_generate_bundle.md @@ -108,9 +108,8 @@ operator-sdk generate bundle [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_generate_kustomize.md b/website/content/en/docs/cli/operator-sdk_generate_kustomize.md index 9f307f46288..b132c7e31f4 100644 --- a/website/content/en/docs/cli/operator-sdk_generate_kustomize.md +++ b/website/content/en/docs/cli/operator-sdk_generate_kustomize.md @@ -14,9 +14,8 @@ Contains subcommands that generate operator-framework kustomize data for the ope ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_generate_kustomize_manifests.md b/website/content/en/docs/cli/operator-sdk_generate_kustomize_manifests.md index a9384f1e653..1cb37a24b3c 100644 --- a/website/content/en/docs/cli/operator-sdk_generate_kustomize_manifests.md +++ b/website/content/en/docs/cli/operator-sdk_generate_kustomize_manifests.md @@ -59,9 +59,8 @@ operator-sdk generate kustomize manifests [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_generate_packagemanifests.md b/website/content/en/docs/cli/operator-sdk_generate_packagemanifests.md index df42ad895dd..380d41215ef 100644 --- a/website/content/en/docs/cli/operator-sdk_generate_packagemanifests.md +++ b/website/content/en/docs/cli/operator-sdk_generate_packagemanifests.md @@ -102,9 +102,8 @@ operator-sdk generate packagemanifests [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_init.md b/website/content/en/docs/cli/operator-sdk_init.md index 89727024972..5bbef9afd11 100644 --- a/website/content/en/docs/cli/operator-sdk_init.md +++ b/website/content/en/docs/cli/operator-sdk_init.md @@ -14,7 +14,7 @@ Writes the following files: - a PROJECT file with the domain and repo - a Makefile to build the project - a go.mod with project dependencies -- a Kustomization.yaml for customizating manifests +- a Kustomization.yaml for customizing manifests - a Patch file for customizing image for manager manifests - a Patch file for enabling prometheus metrics - a main.go to run @@ -28,30 +28,30 @@ operator-sdk init [flags] ``` # Scaffold a project using the apache2 license with "The Kubernetes authors" as owners - operator-sdk init --project-version=2 --domain example.org --license apache2 --owner "The Kubernetes authors" + operator-sdk init --project-version=3-alpha --domain example.org --license apache2 --owner "The Kubernetes authors" ``` ### Options ``` - --component-config create a versioned ComponentConfig file, may be 'true' or 'false' - --domain string domain for groups (default "my.domain") - --fetch-deps ensure dependencies are downloaded (default true) - -h, --help help for init - --license string license to use to boilerplate, may be one of 'apache2', 'none' (default "apache2") - --owner string owner to add to the copyright - --project-name string name of this project - --repo string name to use for go module (e.g., github.com/user/repo), defaults to the go package of the current working directory. - --skip-go-version-check if specified, skip checking the Go version + --component-config create a versioned ComponentConfig file, may be 'true' or 'false' + --domain string domain for groups (default "my.domain") + --fetch-deps ensure dependencies are downloaded (default true) + -h, --help help for init + --license string license to use to boilerplate, may be one of 'apache2', 'none' (default "apache2") + --owner string owner to add to the copyright + --project-name string name of this project + --project-version string project version (default "3") + --repo string name to use for go module (e.g., github.com/user/repo), defaults to the go package of the current working directory. + --skip-go-version-check if specified, skip checking the Go version ``` ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_olm.md b/website/content/en/docs/cli/operator-sdk_olm.md index 5447cf0fb79..53ba6fb0d1b 100644 --- a/website/content/en/docs/cli/operator-sdk_olm.md +++ b/website/content/en/docs/cli/operator-sdk_olm.md @@ -14,9 +14,8 @@ Manage the Operator Lifecycle Manager installation in your cluster ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_olm_install.md b/website/content/en/docs/cli/operator-sdk_olm_install.md index f7e5c6b87fe..92422e7a711 100644 --- a/website/content/en/docs/cli/operator-sdk_olm_install.md +++ b/website/content/en/docs/cli/operator-sdk_olm_install.md @@ -20,9 +20,8 @@ operator-sdk olm install [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_olm_status.md b/website/content/en/docs/cli/operator-sdk_olm_status.md index a453503d7d6..d2ad7a35ff6 100644 --- a/website/content/en/docs/cli/operator-sdk_olm_status.md +++ b/website/content/en/docs/cli/operator-sdk_olm_status.md @@ -21,9 +21,8 @@ operator-sdk olm status [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_olm_uninstall.md b/website/content/en/docs/cli/operator-sdk_olm_uninstall.md index 0646ec9ac33..cd0b95e20c8 100644 --- a/website/content/en/docs/cli/operator-sdk_olm_uninstall.md +++ b/website/content/en/docs/cli/operator-sdk_olm_uninstall.md @@ -21,9 +21,8 @@ operator-sdk olm uninstall [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_run.md b/website/content/en/docs/cli/operator-sdk_run.md index c53d925de62..6bd5b6fa56c 100644 --- a/website/content/en/docs/cli/operator-sdk_run.md +++ b/website/content/en/docs/cli/operator-sdk_run.md @@ -18,9 +18,8 @@ This command has subcommands that will deploy your Operator with OLM. ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_run_bundle-upgrade.md b/website/content/en/docs/cli/operator-sdk_run_bundle-upgrade.md index 09666185c62..3cd0395a58e 100644 --- a/website/content/en/docs/cli/operator-sdk_run_bundle-upgrade.md +++ b/website/content/en/docs/cli/operator-sdk_run_bundle-upgrade.md @@ -21,9 +21,8 @@ operator-sdk run bundle-upgrade [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_run_bundle.md b/website/content/en/docs/cli/operator-sdk_run_bundle.md index 960a9661d47..3734baa0a64 100644 --- a/website/content/en/docs/cli/operator-sdk_run_bundle.md +++ b/website/content/en/docs/cli/operator-sdk_run_bundle.md @@ -23,9 +23,8 @@ operator-sdk run bundle [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md b/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md index 72d0851073b..80012216efe 100644 --- a/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md +++ b/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md @@ -29,9 +29,8 @@ operator-sdk run packagemanifests [packagemanifests-root-dir] [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_scorecard.md b/website/content/en/docs/cli/operator-sdk_scorecard.md index b2e23f5d0f2..e81739253c9 100644 --- a/website/content/en/docs/cli/operator-sdk_scorecard.md +++ b/website/content/en/docs/cli/operator-sdk_scorecard.md @@ -33,9 +33,8 @@ operator-sdk scorecard [flags] ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO diff --git a/website/content/en/docs/cli/operator-sdk_version.md b/website/content/en/docs/cli/operator-sdk_version.md index f2d22ad18f5..243570f68f3 100644 --- a/website/content/en/docs/cli/operator-sdk_version.md +++ b/website/content/en/docs/cli/operator-sdk_version.md @@ -28,9 +28,8 @@ operator-sdk version ### Options inherited from parent commands ``` - --plugins strings plugin keys of the plugin to initialize the project with - --project-version string project version - --verbose Enable verbose logging + --plugins strings plugin keys to be used for this subcommand execution + --verbose Enable verbose logging ``` ### SEE ALSO