Factor out export command control flow

The export command works the same way for most (all?) types. I have
made it generic and moved it into export.go, then ported
{export,create}_auto_image{repository,policy}.go to use it.

Signed-off-by: Michael Bridgen <michael@weave.works>
pull/538/head
Michael Bridgen 4 years ago
parent 52145c045d
commit 4f52b77563

@ -98,7 +98,7 @@ func createAutoImagePolicyRun(cmd *cobra.Command, args []string) error {
}
if export {
return exportImagePolicy(policy) // defined with export command
return printExport(exportImagePolicy(&policy))
}
// I don't need these until attempting to upsert the object, but

@ -103,7 +103,7 @@ func createAutoImageRepositoryRun(cmd *cobra.Command, args []string) error {
}
if export {
return exportImageRepo(repo) // defined with export command
return printExport(exportImageRepository(&repo))
}
// I don't need these until attempting to upsert the object, but

@ -18,8 +18,15 @@ package main
import (
"bytes"
"context"
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
)
var exportCmd = &cobra.Command{
@ -38,6 +45,80 @@ func init() {
rootCmd.AddCommand(exportCmd)
}
// exportable represents a type that you can fetch from the Kubernetes
// API, then tidy up for serialising.
type exportable interface {
objectContainer
Export() interface{}
}
// exportableAt 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 exportCommand struct {
object exportable
list exportableAt
}
func (export exportCommand) run(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
err = kubeClient.List(ctx, export.list.AsClientObject(), client.InNamespace(namespace))
if err != nil {
return err
}
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 {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, export.object.AsClientObject())
if err != nil {
return err
}
return printExport(export.object.Export())
}
return nil
}
func printExport(export interface{}) error {
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}
func resourceToString(data []byte) string {
data = bytes.Replace(data, []byte(" creationTimestamp: null\n"), []byte(""), 1)
data = bytes.Replace(data, []byte("status: {}\n"), []byte(""), 1)

@ -17,16 +17,10 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"k8s.io/apimachinery/pkg/runtime"
"github.com/fluxcd/flux2/internal/utils"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
@ -40,60 +34,19 @@ var exportImagePolicyCmd = &cobra.Command{
# Export a specific policy
flux export auto image-policy alpine1x > alpine1x.yaml
`,
RunE: exportImagePolicyRun,
RunE: exportCommand{
object: exportableImagePolicy{&imagev1.ImagePolicy{}},
list: exportableImagePolicyList{&imagev1.ImagePolicyList{}},
}.run,
}
func init() {
exportAutoCmd.AddCommand(exportImagePolicyCmd)
}
func exportImagePolicyRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list imagev1.ImagePolicyList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no imagepolicy objects found in %s namespace", namespace)
return nil
}
for _, policy := range list.Items {
if err := exportImagePolicy(policy); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var policy imagev1.ImagePolicy
err = kubeClient.Get(ctx, namespacedName, &policy)
if err != nil {
return err
}
return exportImagePolicy(policy)
}
return nil
}
func exportImagePolicy(policy imagev1.ImagePolicy) error {
// Export returns a ImagePolicy value which has extraneous information
// stripped out.
func exportImagePolicy(item *imagev1.ImagePolicy) interface{} {
gvk := imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)
export := imagev1.ImagePolicy{
TypeMeta: metav1.TypeMeta{
@ -101,20 +54,40 @@ func exportImagePolicy(policy imagev1.ImagePolicy) error {
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: policy.Name,
Namespace: policy.Namespace,
Labels: policy.Labels,
Annotations: policy.Annotations,
Name: item.Name,
Namespace: item.Namespace,
Labels: item.Labels,
Annotations: item.Annotations,
},
Spec: policy.Spec,
Spec: item.Spec,
}
return export
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
type exportableImagePolicy struct {
policy *imagev1.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)
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
func (ex exportableImagePolicyList) ExportAt(i int) interface{} {
return exportImagePolicy(&ex.list.Items[i])
}

@ -17,16 +17,10 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"k8s.io/apimachinery/pkg/runtime"
"github.com/fluxcd/flux2/internal/utils"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
@ -40,60 +34,17 @@ var exportImageRepositoryCmd = &cobra.Command{
# Export a Provider
flux export auto image-repository alpine > alpine.yaml
`,
RunE: exportImageRepositoryCmdRun,
RunE: exportCommand{
object: exportableImageRepository{&imagev1.ImageRepository{}},
list: exportableImageRepositoryList{&imagev1.ImageRepositoryList{}},
}.run,
}
func init() {
exportAutoCmd.AddCommand(exportImageRepositoryCmd)
}
func exportImageRepositoryCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list imagev1.ImageRepositoryList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no imagerepository objects found in %s namespace", namespace)
return nil
}
for _, imageRepo := range list.Items {
if err := exportImageRepo(imageRepo); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var imageRepo imagev1.ImageRepository
err = kubeClient.Get(ctx, namespacedName, &imageRepo)
if err != nil {
return err
}
return exportImageRepo(imageRepo)
}
return nil
}
func exportImageRepo(repo imagev1.ImageRepository) error {
func exportImageRepository(repo *imagev1.ImageRepository) interface{} {
gvk := imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)
export := imagev1.ImageRepository{
TypeMeta: metav1.TypeMeta{
@ -108,13 +59,33 @@ func exportImageRepo(repo imagev1.ImageRepository) error {
},
Spec: repo.Spec,
}
return export
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
type exportableImageRepository struct {
repo *imagev1.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)
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
func (ex exportableImageRepositoryList) ExportAt(i int) interface{} {
return exportImageRepository(&ex.list.Items[i])
}

Loading…
Cancel
Save