From 512761080eda9797169269274bfdedc661cbb0cf Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Fri, 4 Dec 2020 18:06:27 +0000 Subject: [PATCH] Add get auto image-policy and refactor This factors the get command implementation so that the control flow is generic and relies on a handful of methods, then uses that to add `get auto image-policy` and to rewrite `get auto image-repository`. Signed-off-by: Michael Bridgen --- cmd/flux/get.go | 79 +++++++++++++++++++++++ cmd/flux/get_auto_imagepolicy.go | 69 ++++++++++++++++++++ cmd/flux/get_auto_imagerepository.go | 89 ++++++++------------------ docs/cmd/flux_get_auto.md | 1 + docs/cmd/flux_get_auto_image-policy.md | 44 +++++++++++++ 5 files changed, 220 insertions(+), 62 deletions(-) create mode 100644 cmd/flux/get_auto_imagepolicy.go create mode 100644 docs/cmd/flux_get_auto_image-policy.md diff --git a/cmd/flux/get.go b/cmd/flux/get.go index 059a32e7..a65cd957 100644 --- a/cmd/flux/get.go +++ b/cmd/flux/get.go @@ -17,7 +17,18 @@ limitations under the License. package main import ( + "context" + "os" + "github.com/spf13/cobra" + apimeta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/fluxcd/pkg/apis/meta" + + "github.com/fluxcd/flux2/internal/utils" ) var getCmd = &cobra.Command{ @@ -33,3 +44,71 @@ func init() { "list the requested object(s) across all namespaces") rootCmd.AddCommand(getCmd) } + +type summarisable interface { + AsObject() runtime.Object + Len() int + SummariseAt(i int, includeNamespace bool) []string + Headers(includeNamespace bool) []string +} + +// --- these help with implementations of summarisable + +func statusAndMessage(conditions []metav1.Condition) (string, string) { + if c := apimeta.FindStatusCondition(conditions, meta.ReadyCondition); c != nil { + return string(c.Status), c.Message + } + return string(metav1.ConditionFalse), "waiting to be reconciled" +} + +type named interface { + GetName() string + GetNamespace() string +} + +func nameColumns(item named, includeNamespace bool) []string { + if includeNamespace { + return []string{item.GetNamespace(), item.GetName()} + } + return []string{item.GetName()} +} + +var namespaceHeader = []string{"Namespace"} + +type getCommand struct { + headers []string + list summarisable +} + +func (get getCommand) run(cmd *cobra.Command, args []string) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) + if err != nil { + return err + } + + var listOpts []client.ListOption + if !allNamespaces { + listOpts = append(listOpts, client.InNamespace(namespace)) + } + err = kubeClient.List(ctx, get.list.AsObject(), listOpts...) + if err != nil { + return err + } + + if get.list.Len() == 0 { + logger.Failuref("no imagerepository objects found in %s namespace", namespace) + return nil + } + + header := get.list.Headers(allNamespaces) + var rows [][]string + for i := 0; i < get.list.Len(); i++ { + row := get.list.SummariseAt(i, allNamespaces) + rows = append(rows, row) + } + utils.PrintTable(os.Stdout, header, rows) + return nil +} diff --git a/cmd/flux/get_auto_imagepolicy.go b/cmd/flux/get_auto_imagepolicy.go new file mode 100644 index 00000000..48b9abdd --- /dev/null +++ b/cmd/flux/get_auto_imagepolicy.go @@ -0,0 +1,69 @@ +/* +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 ( + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/runtime" + + imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" +) + +var getImagePolicyCmd = &cobra.Command{ + Use: "image-policy", + Short: "Get ImagePolicy statuses", + Long: "The get auto image-policy command prints the status of ImagePolicy objects.", + Example: ` # List all image policies and their status + flux get auto image-policy + + # List image policies from all namespaces + flux get auto image-policy --all-namespaces +`, + RunE: getCommand{ + list: &imagePolicySummary{&imagev1.ImagePolicyList{}}, + }.run, +} + +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 { + 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 { + headers := []string{"Name", "Ready", "Message", "Latest image"} + if includeNamespace { + return append(namespaceHeader, headers...) + } + return headers +} + +func (s imagePolicySummary) AsObject() runtime.Object { + return s.ImagePolicyList +} diff --git a/cmd/flux/get_auto_imagerepository.go b/cmd/flux/get_auto_imagerepository.go index 5e781628..d093dd8b 100644 --- a/cmd/flux/get_auto_imagerepository.go +++ b/cmd/flux/get_auto_imagerepository.go @@ -17,19 +17,12 @@ limitations under the License. package main import ( - "context" - "os" "strconv" "strings" "time" - "github.com/fluxcd/flux2/internal/utils" - "github.com/fluxcd/pkg/apis/meta" - "github.com/spf13/cobra" - apimeta "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" + "k8s.io/apimachinery/pkg/runtime" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" ) @@ -44,70 +37,42 @@ var getImageRepositoryCmd = &cobra.Command{ # List image repositories from all namespaces flux get auto image-repository --all-namespaces `, - RunE: getImageRepositoryRun, + RunE: getCommand{ + list: imageRepositorySummary{&imagev1.ImageRepositoryList{}}, + }.run, } func init() { getAutoCmd.AddCommand(getImageRepositoryCmd) } -func getImageRepositoryRun(cmd *cobra.Command, args []string) error { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() +type imageRepositorySummary struct { + *imagev1.ImageRepositoryList +} - kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) - if err != nil { - return err - } +func (s imageRepositorySummary) Len() int { + return len(s.Items) +} - var listOpts []client.ListOption - if !allNamespaces { - listOpts = append(listOpts, client.InNamespace(namespace)) - } - var list imagev1.ImageRepositoryList - err = kubeClient.List(ctx, &list, listOpts...) - if err != nil { - return err +func (s imageRepositorySummary) SummariseAt(i int, includeNamespace bool) []string { + item := s.Items[i] + status, msg := statusAndMessage(item.Status.Conditions) + var lastScan string + if item.Status.LastScanResult != nil { + lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339) } + return append(nameColumns(&item, includeNamespace), + status, msg, lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend))) +} - if len(list.Items) == 0 { - logger.Failuref("no imagerepository objects found in %s namespace", namespace) - return nil +func (s imageRepositorySummary) Headers(includeNamespace bool) []string { + headers := []string{"Name", "Ready", "Message", "Last scan", "Suspended"} + if includeNamespace { + return append(namespaceHeader, headers...) } + return headers +} - header := []string{"Name", "Ready", "Message", "Last scan", "Suspended"} - if allNamespaces { - header = append([]string{"Namespace"}, header...) - } - var rows [][]string - for _, repo := range list.Items { - var row []string - var lastScan string - if repo.Status.LastScanResult != nil { - lastScan = repo.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339) - } - if c := apimeta.FindStatusCondition(repo.Status.Conditions, meta.ReadyCondition); c != nil { - row = []string{ - repo.GetName(), - string(c.Status), - c.Message, - lastScan, - strings.Title(strconv.FormatBool(repo.Spec.Suspend)), - } - } else { - row = []string{ - repo.GetName(), - string(metav1.ConditionFalse), - "waiting to be reconciled", - lastScan, - strings.Title(strconv.FormatBool(repo.Spec.Suspend)), - } - } - if allNamespaces { - row = append([]string{repo.Namespace}, row...) - } - rows = append(rows, row) - } - utils.PrintTable(os.Stdout, header, rows) - return nil +func (s imageRepositorySummary) AsObject() runtime.Object { + return s.ImageRepositoryList } diff --git a/docs/cmd/flux_get_auto.md b/docs/cmd/flux_get_auto.md index be574ff3..1a3b0718 100644 --- a/docs/cmd/flux_get_auto.md +++ b/docs/cmd/flux_get_auto.md @@ -26,5 +26,6 @@ The get auto sub-commands print the statuses of the automation objects. ### SEE ALSO * [flux get](flux_get.md) - Get sources and resources +* [flux get auto image-policy](flux_get_auto_image-policy.md) - Get ImagePolicy statuses * [flux get auto image-repository](flux_get_auto_image-repository.md) - Get ImageRepository statuses diff --git a/docs/cmd/flux_get_auto_image-policy.md b/docs/cmd/flux_get_auto_image-policy.md new file mode 100644 index 00000000..b802787c --- /dev/null +++ b/docs/cmd/flux_get_auto_image-policy.md @@ -0,0 +1,44 @@ +## flux get auto image-policy + +Get ImagePolicy statuses + +### Synopsis + +The get auto image-policy command prints the status of ImagePolicy objects. + +``` +flux get auto image-policy [flags] +``` + +### Examples + +``` + # List all image policies and their status + flux get auto image-policy + + # List image policies from all namespaces + flux get auto image-policy --all-namespaces + +``` + +### Options + +``` + -h, --help help for image-policy +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --context string kubernetes context to use + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux get auto](flux_get_auto.md) - Get automation statuses +