From 2bb09697ce766f37cd4131eb8240d3fdad364cfb Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Mon, 7 Dec 2020 17:30:41 +0000 Subject: [PATCH] Centralise adapter types Since the generic commands tend to share a few of the methods they need -- at least AsClientObject -- it's worth having just one wrapper struct for each API type, and adding methods to it where necessary. For the automation types, I put these in auto.go. While doing this I also did some tidying: - I changed the name of the wrappers to `Adapter`, and the generic adapter to `universalAdapter` (it's only needed for delete, so far). - I de-exported and renamed some interface methods e.g., `exportItem`. They aren't needed outside the package. Signed-off-by: Michael Bridgen --- cmd/flux/auto.go | 99 +++++++++++++++++++++++++ cmd/flux/delete.go | 8 +- cmd/flux/delete_auto_imagepolicy.go | 2 +- cmd/flux/delete_auto_imagerepository.go | 2 +- cmd/flux/delete_auto_imageupdateauto.go | 2 +- cmd/flux/export.go | 28 +++---- cmd/flux/export_auto_imagepolicy.go | 33 ++------- cmd/flux/export_auto_imagerepository.go | 33 ++------- cmd/flux/export_auto_imageupdateauto.go | 33 ++------- cmd/flux/get.go | 18 ++--- cmd/flux/get_auto_imagepolicy.go | 19 +---- cmd/flux/get_auto_imagerepository.go | 19 +---- cmd/flux/get_auto_imageupdateauto.go | 19 +---- cmd/flux/object.go | 22 +++--- 14 files changed, 167 insertions(+), 170 deletions(-) create mode 100644 cmd/flux/auto.go diff --git a/cmd/flux/auto.go b/cmd/flux/auto.go new file mode 100644 index 00000000..280b7d57 --- /dev/null +++ b/cmd/flux/auto.go @@ -0,0 +1,99 @@ +/* +Copyright 2020 The Flux 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 main + +import ( + "k8s.io/apimachinery/pkg/runtime" + + autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1" + imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" +) + +// These are general-purpose adapters for attaching methods to, for +// the various commands. The *List adapters implement len(), since +// it's used in at least a couple of commands. + +// imagev1.ImageRepository +type imageRepositoryAdapter struct { + *imagev1.ImageRepository +} + +func (a imageRepositoryAdapter) asRuntimeObject() runtime.Object { + return a.ImageRepository +} + +// imagev1.ImageRepositoryList + +type imageRepositoryListAdapter struct { + *imagev1.ImageRepositoryList +} + +func (a imageRepositoryListAdapter) asRuntimeObject() runtime.Object { + return a.ImageRepositoryList +} + +func (a imageRepositoryListAdapter) len() int { + return len(a.ImageRepositoryList.Items) +} + +// imagev1.ImagePolicy + +type imagePolicyAdapter struct { + *imagev1.ImagePolicy +} + +func (a imagePolicyAdapter) asRuntimeObject() runtime.Object { + return a.ImagePolicy +} + +// imagev1.ImagePolicyList + +type imagePolicyListAdapter struct { + *imagev1.ImagePolicyList +} + +func (a imagePolicyListAdapter) asRuntimeObject() runtime.Object { + return a.ImagePolicyList +} + +func (a imagePolicyListAdapter) len() int { + return len(a.ImagePolicyList.Items) +} + +// autov1.ImageUpdateAutomation + +type imageUpdateAutomationAdapter struct { + *autov1.ImageUpdateAutomation +} + +func (a imageUpdateAutomationAdapter) asRuntimeObject() runtime.Object { + return a.ImageUpdateAutomation +} + +// autov1.ImageUpdateAutomationList + +type imageUpdateAutomationListAdapter struct { + *autov1.ImageUpdateAutomationList +} + +func (a imageUpdateAutomationListAdapter) asRuntimeObject() runtime.Object { + return a.ImageUpdateAutomationList +} + +func (a imageUpdateAutomationListAdapter) len() int { + return len(a.ImageUpdateAutomationList.Items) +} diff --git a/cmd/flux/delete.go b/cmd/flux/delete.go index 4a9737b0..a70ca2e2 100644 --- a/cmd/flux/delete.go +++ b/cmd/flux/delete.go @@ -45,8 +45,8 @@ func init() { } type deleteCommand struct { - humanKind string // the kind being deleted, lowercase and spaced e.g., "image policy" - container objectContainer // for getting the value, and later deleting it + humanKind string // the kind being deleted, lowercase and spaced e.g., "image policy" + adapter adapter // for getting the value, and later deleting it } func (del deleteCommand) run(cmd *cobra.Command, args []string) error { @@ -68,7 +68,7 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error { Name: name, } - err = kubeClient.Get(ctx, namespacedName, del.container.AsClientObject()) + err = kubeClient.Get(ctx, namespacedName, del.adapter.asRuntimeObject()) if err != nil { return err } @@ -84,7 +84,7 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error { } logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, namespace) - err = kubeClient.Delete(ctx, del.container.AsClientObject()) + err = kubeClient.Delete(ctx, del.adapter.asRuntimeObject()) if err != nil { return err } diff --git a/cmd/flux/delete_auto_imagepolicy.go b/cmd/flux/delete_auto_imagepolicy.go index 8d6e0095..f0172835 100644 --- a/cmd/flux/delete_auto_imagepolicy.go +++ b/cmd/flux/delete_auto_imagepolicy.go @@ -31,7 +31,7 @@ var deleteImagePolicyCmd = &cobra.Command{ `, RunE: deleteCommand{ humanKind: "image policy", - container: genericContainer{&imagev1.ImagePolicy{}}, + adapter: universalAdapter{&imagev1.ImagePolicy{}}, }.run, } diff --git a/cmd/flux/delete_auto_imagerepository.go b/cmd/flux/delete_auto_imagerepository.go index 81f0d68a..20fcdb0b 100644 --- a/cmd/flux/delete_auto_imagerepository.go +++ b/cmd/flux/delete_auto_imagerepository.go @@ -31,7 +31,7 @@ var deleteImageRepositoryCmd = &cobra.Command{ `, RunE: deleteCommand{ humanKind: "image repository", - container: genericContainer{&imagev1.ImageRepository{}}, + adapter: universalAdapter{&imagev1.ImageRepository{}}, }.run, } diff --git a/cmd/flux/delete_auto_imageupdateauto.go b/cmd/flux/delete_auto_imageupdateauto.go index 2b6f8993..69caa233 100644 --- a/cmd/flux/delete_auto_imageupdateauto.go +++ b/cmd/flux/delete_auto_imageupdateauto.go @@ -31,7 +31,7 @@ var deleteImageUpdateCmd = &cobra.Command{ `, RunE: deleteCommand{ humanKind: "image update automation", - container: genericContainer{&autov1.ImageUpdateAutomation{}}, + adapter: universalAdapter{&autov1.ImageUpdateAutomation{}}, }.run, } diff --git a/cmd/flux/export.go b/cmd/flux/export.go index d80ed108..4a546369 100644 --- a/cmd/flux/export.go +++ b/cmd/flux/export.go @@ -48,21 +48,21 @@ func init() { // exportable represents a type that you can fetch from the Kubernetes // API, then tidy up for serialising. type exportable interface { - objectContainer - Export() interface{} + adapter + export() interface{} } -// exportableAt represents a type that has a list of values, each of +// exportableList represents a type that has a list of values, each of // which is exportable. -type exportableAt interface { - objectContainer - Len() int - ExportAt(i int) interface{} +type exportableList interface { + adapter + len() int + exportItem(i int) interface{} } type exportCommand struct { object exportable - list exportableAt + list exportableList } func (export exportCommand) run(cmd *cobra.Command, args []string) error { @@ -79,18 +79,18 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error { } if exportAll { - err = kubeClient.List(ctx, export.list.AsClientObject(), client.InNamespace(namespace)) + err = kubeClient.List(ctx, export.list.asRuntimeObject(), client.InNamespace(namespace)) if err != nil { return err } - if export.list.Len() == 0 { + if export.list.len() == 0 { logger.Failuref("no objects found in %s namespace", namespace) return nil } - for i := 0; i < export.list.Len(); i++ { - if err = printExport(export.list.ExportAt(i)); err != nil { + for i := 0; i < export.list.len(); i++ { + if err = printExport(export.list.exportItem(i)); err != nil { return err } } @@ -100,11 +100,11 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error { Namespace: namespace, Name: name, } - err = kubeClient.Get(ctx, namespacedName, export.object.AsClientObject()) + err = kubeClient.Get(ctx, namespacedName, export.object.asRuntimeObject()) if err != nil { return err } - return printExport(export.object.Export()) + return printExport(export.object.export()) } return nil } diff --git a/cmd/flux/export_auto_imagepolicy.go b/cmd/flux/export_auto_imagepolicy.go index 595940c5..4364a65f 100644 --- a/cmd/flux/export_auto_imagepolicy.go +++ b/cmd/flux/export_auto_imagepolicy.go @@ -19,7 +19,6 @@ package main import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" ) @@ -35,8 +34,8 @@ var exportImagePolicyCmd = &cobra.Command{ flux export auto image-policy alpine1x > alpine1x.yaml `, RunE: exportCommand{ - object: exportableImagePolicy{&imagev1.ImagePolicy{}}, - list: exportableImagePolicyList{&imagev1.ImagePolicyList{}}, + object: imagePolicyAdapter{&imagev1.ImagePolicy{}}, + list: imagePolicyListAdapter{&imagev1.ImagePolicyList{}}, }.run, } @@ -64,30 +63,10 @@ func exportImagePolicy(item *imagev1.ImagePolicy) interface{} { return export } -type exportableImagePolicy struct { - policy *imagev1.ImagePolicy +func (ex imagePolicyAdapter) export() interface{} { + return exportImagePolicy(ex.ImagePolicy) } -func (ex exportableImagePolicy) AsClientObject() runtime.Object { - return ex.policy -} - -func (ex exportableImagePolicy) Export() interface{} { - return exportImagePolicy(ex.policy) -} - -type exportableImagePolicyList struct { - list *imagev1.ImagePolicyList -} - -func (ex exportableImagePolicyList) AsClientObject() runtime.Object { - return ex.list -} - -func (ex exportableImagePolicyList) Len() int { - return len(ex.list.Items) -} - -func (ex exportableImagePolicyList) ExportAt(i int) interface{} { - return exportImagePolicy(&ex.list.Items[i]) +func (ex imagePolicyListAdapter) exportItem(i int) interface{} { + return exportImagePolicy(&ex.ImagePolicyList.Items[i]) } diff --git a/cmd/flux/export_auto_imagerepository.go b/cmd/flux/export_auto_imagerepository.go index d8a407a5..13660e81 100644 --- a/cmd/flux/export_auto_imagerepository.go +++ b/cmd/flux/export_auto_imagerepository.go @@ -19,7 +19,6 @@ package main import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" ) @@ -35,8 +34,8 @@ var exportImageRepositoryCmd = &cobra.Command{ flux export auto image-repository alpine > alpine.yaml `, RunE: exportCommand{ - object: exportableImageRepository{&imagev1.ImageRepository{}}, - list: exportableImageRepositoryList{&imagev1.ImageRepositoryList{}}, + object: imageRepositoryAdapter{&imagev1.ImageRepository{}}, + list: imageRepositoryListAdapter{&imagev1.ImageRepositoryList{}}, }.run, } @@ -62,30 +61,10 @@ func exportImageRepository(repo *imagev1.ImageRepository) interface{} { return export } -type exportableImageRepository struct { - repo *imagev1.ImageRepository +func (ex imageRepositoryAdapter) export() interface{} { + return exportImageRepository(ex.ImageRepository) } -func (ex exportableImageRepository) AsClientObject() runtime.Object { - return ex.repo -} - -func (ex exportableImageRepository) Export() interface{} { - return exportImageRepository(ex.repo) -} - -type exportableImageRepositoryList struct { - list *imagev1.ImageRepositoryList -} - -func (ex exportableImageRepositoryList) AsClientObject() runtime.Object { - return ex.list -} - -func (ex exportableImageRepositoryList) Len() int { - return len(ex.list.Items) -} - -func (ex exportableImageRepositoryList) ExportAt(i int) interface{} { - return exportImageRepository(&ex.list.Items[i]) +func (ex imageRepositoryListAdapter) exportItem(i int) interface{} { + return exportImageRepository(&ex.ImageRepositoryList.Items[i]) } diff --git a/cmd/flux/export_auto_imageupdateauto.go b/cmd/flux/export_auto_imageupdateauto.go index f7ce1d36..0e59bc3f 100644 --- a/cmd/flux/export_auto_imageupdateauto.go +++ b/cmd/flux/export_auto_imageupdateauto.go @@ -19,7 +19,6 @@ package main import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1" ) @@ -35,8 +34,8 @@ var exportImageUpdateCmd = &cobra.Command{ flux export auto image-update latest-images > latest.yaml `, RunE: exportCommand{ - object: exportableImageUpdate{&autov1.ImageUpdateAutomation{}}, - list: exportableImageUpdateList{&autov1.ImageUpdateAutomationList{}}, + object: imageUpdateAutomationAdapter{&autov1.ImageUpdateAutomation{}}, + list: imageUpdateAutomationListAdapter{&autov1.ImageUpdateAutomationList{}}, }.run, } @@ -64,30 +63,10 @@ func exportImageUpdate(item *autov1.ImageUpdateAutomation) interface{} { return export } -type exportableImageUpdate struct { - update *autov1.ImageUpdateAutomation +func (ex imageUpdateAutomationAdapter) export() interface{} { + return exportImageUpdate(ex.ImageUpdateAutomation) } -func (ex exportableImageUpdate) AsClientObject() runtime.Object { - return ex.update -} - -func (ex exportableImageUpdate) Export() interface{} { - return exportImageUpdate(ex.update) -} - -type exportableImageUpdateList struct { - list *autov1.ImageUpdateAutomationList -} - -func (ex exportableImageUpdateList) AsClientObject() runtime.Object { - return ex.list -} - -func (ex exportableImageUpdateList) Len() int { - return len(ex.list.Items) -} - -func (ex exportableImageUpdateList) ExportAt(i int) interface{} { - return exportImageUpdate(&ex.list.Items[i]) +func (ex imageUpdateAutomationListAdapter) exportItem(i int) interface{} { + return exportImageUpdate(&ex.ImageUpdateAutomationList.Items[i]) } diff --git a/cmd/flux/get.go b/cmd/flux/get.go index 26c1ac8a..631d5bde 100644 --- a/cmd/flux/get.go +++ b/cmd/flux/get.go @@ -45,10 +45,10 @@ func init() { } type summarisable interface { - objectContainer - Len() int - SummariseAt(i int, includeNamespace bool) []string - Headers(includeNamespace bool) []string + adapter + len() int + summariseItem(i int, includeNamespace bool) []string + headers(includeNamespace bool) []string } // --- these help with implementations of summarisable @@ -92,20 +92,20 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error { if !allNamespaces { listOpts = append(listOpts, client.InNamespace(namespace)) } - err = kubeClient.List(ctx, get.list.AsClientObject(), listOpts...) + err = kubeClient.List(ctx, get.list.asRuntimeObject(), listOpts...) if err != nil { return err } - if get.list.Len() == 0 { + if get.list.len() == 0 { logger.Failuref("no imagerepository objects found in %s namespace", namespace) return nil } - header := get.list.Headers(allNamespaces) + header := get.list.headers(allNamespaces) var rows [][]string - for i := 0; i < get.list.Len(); i++ { - row := get.list.SummariseAt(i, allNamespaces) + for i := 0; i < get.list.len(); i++ { + row := get.list.summariseItem(i, allNamespaces) rows = append(rows, row) } utils.PrintTable(os.Stdout, header, rows) diff --git a/cmd/flux/get_auto_imagepolicy.go b/cmd/flux/get_auto_imagepolicy.go index c2954a2d..cc459e03 100644 --- a/cmd/flux/get_auto_imagepolicy.go +++ b/cmd/flux/get_auto_imagepolicy.go @@ -18,7 +18,6 @@ package main import ( "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/runtime" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" ) @@ -34,7 +33,7 @@ var getImagePolicyCmd = &cobra.Command{ flux get auto image-policy --all-namespaces `, RunE: getCommand{ - list: &imagePolicySummary{&imagev1.ImagePolicyList{}}, + list: &imagePolicyListAdapter{&imagev1.ImagePolicyList{}}, }.run, } @@ -42,28 +41,16 @@ func init() { getAutoCmd.AddCommand(getImagePolicyCmd) } -type imagePolicySummary struct { - *imagev1.ImagePolicyList -} - -func (s imagePolicySummary) Len() int { - return len(s.Items) -} - -func (s imagePolicySummary) SummariseAt(i int, includeNamespace bool) []string { +func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool) []string { item := s.Items[i] status, msg := statusAndMessage(item.Status.Conditions) return append(nameColumns(&item, includeNamespace), status, msg, item.Status.LatestImage) } -func (s imagePolicySummary) Headers(includeNamespace bool) []string { +func (s imagePolicyListAdapter) headers(includeNamespace bool) []string { headers := []string{"Name", "Ready", "Message", "Latest image"} if includeNamespace { return append(namespaceHeader, headers...) } return headers } - -func (s imagePolicySummary) AsClientObject() runtime.Object { - return s.ImagePolicyList -} diff --git a/cmd/flux/get_auto_imagerepository.go b/cmd/flux/get_auto_imagerepository.go index 542d7b32..37a88760 100644 --- a/cmd/flux/get_auto_imagerepository.go +++ b/cmd/flux/get_auto_imagerepository.go @@ -22,7 +22,6 @@ import ( "time" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/runtime" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" ) @@ -38,7 +37,7 @@ var getImageRepositoryCmd = &cobra.Command{ flux get auto image-repository --all-namespaces `, RunE: getCommand{ - list: imageRepositorySummary{&imagev1.ImageRepositoryList{}}, + list: imageRepositoryListAdapter{&imagev1.ImageRepositoryList{}}, }.run, } @@ -46,15 +45,7 @@ func init() { getAutoCmd.AddCommand(getImageRepositoryCmd) } -type imageRepositorySummary struct { - *imagev1.ImageRepositoryList -} - -func (s imageRepositorySummary) Len() int { - return len(s.Items) -} - -func (s imageRepositorySummary) SummariseAt(i int, includeNamespace bool) []string { +func (s imageRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string { item := s.Items[i] status, msg := statusAndMessage(item.Status.Conditions) var lastScan string @@ -65,14 +56,10 @@ func (s imageRepositorySummary) SummariseAt(i int, includeNamespace bool) []stri status, msg, lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend))) } -func (s imageRepositorySummary) Headers(includeNamespace bool) []string { +func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string { headers := []string{"Name", "Ready", "Message", "Last scan", "Suspended"} if includeNamespace { return append(namespaceHeader, headers...) } return headers } - -func (s imageRepositorySummary) AsClientObject() runtime.Object { - return s.ImageRepositoryList -} diff --git a/cmd/flux/get_auto_imageupdateauto.go b/cmd/flux/get_auto_imageupdateauto.go index 8585f301..2a8e27a1 100644 --- a/cmd/flux/get_auto_imageupdateauto.go +++ b/cmd/flux/get_auto_imageupdateauto.go @@ -22,7 +22,6 @@ import ( "time" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/runtime" autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1" ) @@ -38,7 +37,7 @@ var getImageUpdateCmd = &cobra.Command{ flux get auto image-update --all-namespaces `, RunE: getCommand{ - list: &imageUpdateSummary{&autov1.ImageUpdateAutomationList{}}, + list: &imageUpdateAutomationListAdapter{&autov1.ImageUpdateAutomationList{}}, }.run, } @@ -46,15 +45,7 @@ func init() { getAutoCmd.AddCommand(getImageUpdateCmd) } -type imageUpdateSummary struct { - *autov1.ImageUpdateAutomationList -} - -func (s imageUpdateSummary) Len() int { - return len(s.Items) -} - -func (s imageUpdateSummary) SummariseAt(i int, includeNamespace bool) []string { +func (s imageUpdateAutomationListAdapter) summariseItem(i int, includeNamespace bool) []string { item := s.Items[i] status, msg := statusAndMessage(item.Status.Conditions) var lastRun string @@ -64,14 +55,10 @@ func (s imageUpdateSummary) SummariseAt(i int, includeNamespace bool) []string { return append(nameColumns(&item, includeNamespace), status, msg, lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend))) } -func (s imageUpdateSummary) Headers(includeNamespace bool) []string { +func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string { headers := []string{"Name", "Ready", "Message", "Last run", "Suspended"} if includeNamespace { return append(namespaceHeader, headers...) } return headers } - -func (s imageUpdateSummary) AsClientObject() runtime.Object { - return s.ImageUpdateAutomationList -} diff --git a/cmd/flux/object.go b/cmd/flux/object.go index 922268bb..49796b86 100644 --- a/cmd/flux/object.go +++ b/cmd/flux/object.go @@ -20,21 +20,21 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -// objectContainer is an interface for a wrapper or alias from which we -// can get a controller-runtime deserialisable value. This is used so -// that you can wrap an API type to give it other useful methods, but -// still use values of the wrapper with `client.Client`, which only -// deals with types that have been added to the schema. -type objectContainer interface { - AsClientObject() runtime.Object +// adapter is an interface for a wrapper or alias from which we can +// get a controller-runtime deserialisable value. This is used so that +// you can wrap an API type to give it other useful methods, but still +// use values of the wrapper with `client.Client`, which only deals +// with types that have been added to the schema. +type adapter interface { + asRuntimeObject() runtime.Object } -// genericContainer is an objectContainer for any runtime.Object. Use -// this if there are no other methods needed. -type genericContainer struct { +// universalAdapter is an adapter for any runtime.Object. Use this if +// there are no other methods needed. +type universalAdapter struct { obj runtime.Object } -func (c genericContainer) AsClientObject() runtime.Object { +func (c universalAdapter) asRuntimeObject() runtime.Object { return c.obj }