1
0
mirror of synced 2026-02-06 19:05:55 +00:00

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 <michael@weave.works>
This commit is contained in:
Michael Bridgen
2020-12-04 18:06:27 +00:00
parent 037a5b71fd
commit 512761080e
5 changed files with 226 additions and 68 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
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
}
if len(list.Items) == 0 {
logger.Failuref("no imagerepository objects found in %s namespace", namespace)
return nil
}
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
type imageRepositorySummary struct {
*imagev1.ImageRepositoryList
}
func (s imageRepositorySummary) Len() int {
return len(s.Items)
}
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)))
}
func (s imageRepositorySummary) Headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Last scan", "Suspended"}
if includeNamespace {
return append(namespaceHeader, headers...)
}
return headers
}
func (s imageRepositorySummary) AsObject() runtime.Object {
return s.ImageRepositoryList
}