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 { 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 // 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 { 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 // I don't need these until attempting to upsert the object, but

@ -18,8 +18,15 @@ package main
import ( import (
"bytes" "bytes"
"context"
"fmt"
"github.com/spf13/cobra" "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{ var exportCmd = &cobra.Command{
@ -38,6 +45,80 @@ func init() {
rootCmd.AddCommand(exportCmd) 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 { func resourceToString(data []byte) string {
data = bytes.Replace(data, []byte(" creationTimestamp: null\n"), []byte(""), 1) data = bytes.Replace(data, []byte(" creationTimestamp: null\n"), []byte(""), 1)
data = bytes.Replace(data, []byte("status: {}\n"), []byte(""), 1) data = bytes.Replace(data, []byte("status: {}\n"), []byte(""), 1)

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

@ -17,16 +17,10 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
) )
@ -40,60 +34,17 @@ var exportImageRepositoryCmd = &cobra.Command{
# Export a Provider # Export a Provider
flux export auto image-repository alpine > alpine.yaml flux export auto image-repository alpine > alpine.yaml
`, `,
RunE: exportImageRepositoryCmdRun, RunE: exportCommand{
object: exportableImageRepository{&imagev1.ImageRepository{}},
list: exportableImageRepositoryList{&imagev1.ImageRepositoryList{}},
}.run,
} }
func init() { func init() {
exportAutoCmd.AddCommand(exportImageRepositoryCmd) exportAutoCmd.AddCommand(exportImageRepositoryCmd)
} }
func exportImageRepositoryCmdRun(cmd *cobra.Command, args []string) error { func exportImageRepository(repo *imagev1.ImageRepository) interface{} {
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 {
gvk := imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind) gvk := imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)
export := imagev1.ImageRepository{ export := imagev1.ImageRepository{
TypeMeta: metav1.TypeMeta{ TypeMeta: metav1.TypeMeta{
@ -108,13 +59,33 @@ func exportImageRepo(repo imagev1.ImageRepository) error {
}, },
Spec: repo.Spec, Spec: repo.Spec,
} }
return export
}
data, err := yaml.Marshal(export) type exportableImageRepository struct {
if err != nil { repo *imagev1.ImageRepository
return err }
}
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("---") func (ex exportableImageRepositoryList) ExportAt(i int) interface{} {
fmt.Println(resourceToString(data)) return exportImageRepository(&ex.list.Items[i])
return nil
} }

Loading…
Cancel
Save