Skip to content

Commit

Permalink
Refactor for cli and pkg/action decoupling and deduplication (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
joelanford committed Nov 11, 2020
1 parent fb6f935 commit b4e7a70
Show file tree
Hide file tree
Showing 14 changed files with 244 additions and 277 deletions.
18 changes: 16 additions & 2 deletions internal/cmd/catalog_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ package cmd
import (
"context"
"io/ioutil"
"time"

"github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
"github.com/operator-framework/kubectl-operator/internal/pkg/action"
)

func newCatalogAddCmd(cfg *action.Configuration) *cobra.Command {
var timeout time.Duration
a := action.NewCatalogAdd(cfg)
a.Logf = log.Printf

Expand All @@ -28,7 +31,7 @@ func newCatalogAddCmd(cfg *action.Configuration) *cobra.Command {
}
},
Run: func(cmd *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(cmd.Context(), a.AddTimeout)
ctx, cancel := context.WithTimeout(cmd.Context(), timeout)
defer cancel()

a.CatalogSourceName = args[0]
Expand All @@ -41,7 +44,18 @@ func newCatalogAddCmd(cfg *action.Configuration) *cobra.Command {
log.Printf("created catalogsource %q\n", cs.Name)
},
}
a.BindFlags(cmd.Flags())
bindCatalogAddFlags(cmd.Flags(), a)
cmd.Flags().DurationVarP(&timeout, "timeout", "t", time.Minute, "the amount of time to wait before cancelling the catalog addition")

return cmd
}

func bindCatalogAddFlags(fs *pflag.FlagSet, a *action.CatalogAdd) {
fs.StringVarP(&a.DisplayName, "display-name", "d", "", "display name of the index")
fs.StringVarP(&a.Publisher, "publisher", "p", "", "publisher of the index")
fs.DurationVar(&a.CleanupTimeout, "cleanup-timeout", time.Minute, "the amount to time to wait before cancelling cleanup")

fs.StringArrayVarP(&a.InjectBundles, "inject-bundles", "b", nil, "inject extra bundles into the index at runtime")
fs.StringVarP(&a.InjectBundleMode, "inject-bundle-mode", "m", "", "mode to use to inject bundles")
_ = fs.MarkHidden("inject-bundle-mode")
}
59 changes: 13 additions & 46 deletions internal/cmd/operator_describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import (

"github.com/spf13/cobra"

operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"

"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
"github.com/operator-framework/kubectl-operator/internal/pkg/action"
"github.com/operator-framework/kubectl-operator/internal/pkg/operator"
)

var (
Expand Down Expand Up @@ -43,22 +42,17 @@ func newOperatorDescribeCmd(cfg *action.Configuration) *cobra.Command {
// Find the package manifest and package channel for the operator
pms, err := l.Run(cmd.Context())
if err != nil {
log.Fatalf("failed to find operator: %v", err)
log.Fatal(err)
}

// we only expect one item because describe always searches
// for a specific operator by name
pm := &pms[0]

// If the user asked for a channel, look for that
if channel == "" {
channel = pm.Status.DefaultChannel
}
pm := pms[0]

pc, err := getPackageChannel(channel, pm)
pc, err := pm.GetChannel(channel)
if err != nil {
// the requested channel doesn't exist
log.Fatalf("failed to find channel for operator: %v", err)
log.Fatal(err)
}

// prepare what we want to print to the console
Expand All @@ -78,10 +72,10 @@ func newOperatorDescribeCmd(cfg *action.Configuration) *cobra.Command {
catHdr+fmt.Sprintf("%s\n\n", pm.Status.CatalogSourceDisplayName),
// available channels
chHdr+fmt.Sprintf("%s\n\n",
strings.Join(getAvailableChannelsWithMarkers(channel, pm), "\n")),
strings.Join(getAvailableChannelsWithMarkers(*pc, pm), "\n")),
// install modes
imHdr+fmt.Sprintf("%s\n\n",
strings.Join(getSupportedInstallModes(pc), "\n")),
strings.Join(pc.GetSupportedInstallModes().List(), "\n")),
// description
sdHdr+fmt.Sprintf("%s\n",
pc.CurrentCSVDesc.Annotations[descAnnot]),
Expand All @@ -102,8 +96,9 @@ func newOperatorDescribeCmd(cfg *action.Configuration) *cobra.Command {
}

// add flags to the flagset for this command.
cmd.Flags().StringVarP(&channel, "channel", "c", "", "channel")
cmd.Flags().BoolVarP(&longDescription, "with-long-description", "L", false, "long description")
bindOperatorListAvailableFlags(cmd.Flags(), l)
cmd.Flags().StringVarP(&channel, "channel", "C", "", "package channel to describe")
cmd.Flags().BoolVarP(&longDescription, "with-long-description", "L", false, "include long description")

return cmd
}
Expand All @@ -114,45 +109,17 @@ func asHeader(s string) string {
return fmt.Sprintf("== %s ==\n", s)
}

// getPackageChannel returns the package channel specified, or the default if none was specified.
func getPackageChannel(channel string, pm *operatorsv1.PackageManifest) (*operatorsv1.PackageChannel, error) {
var packageChannel *operatorsv1.PackageChannel
for _, ch := range pm.Status.Channels {
ch := ch
if ch.Name == channel {
packageChannel = &ch
}
}
if packageChannel == nil {
return nil, fmt.Errorf("channel %q does not exist for package %q", channel, pm.GetName())
}
return packageChannel, nil
}

// GetSupportedInstallModes returns a string slice representation of install mode
// objects the operator supports.
func getSupportedInstallModes(pc *operatorsv1.PackageChannel) []string {
supportedInstallModes := make([]string, 1)
for _, imode := range pc.CurrentCSVDesc.InstallModes {
if imode.Supported {
supportedInstallModes = append(supportedInstallModes, string(imode.Type))
}
}

return supportedInstallModes
}

// getAvailableChannelsWithMarkers parses all available package channels for a package manifest
// and returns those channel names with indicators for pretty-printing whether they are shown
// or the default channel
func getAvailableChannelsWithMarkers(channel string, pm *operatorsv1.PackageManifest) []string {
func getAvailableChannelsWithMarkers(channel operator.PackageChannel, pm operator.PackageManifest) []string {
channels := make([]string, len(pm.Status.Channels))
for i, ch := range pm.Status.Channels {
n := ch.Name
if ch.IsDefaultChannel(*pm) {
if ch.IsDefaultChannel(pm.PackageManifest) {
n += " (default)"
}
if channel == ch.Name {
if channel.Name == ch.Name {
n += " (shown)"
}
channels[i] = n
Expand Down
26 changes: 24 additions & 2 deletions internal/cmd/operator_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ package cmd

import (
"context"
"fmt"
"time"

"github.com/operator-framework/api/pkg/operators/v1alpha1"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
"github.com/operator-framework/kubectl-operator/internal/pkg/action"
)

func newOperatorInstallCmd(cfg *action.Configuration) *cobra.Command {
var timeout time.Duration
i := action.NewOperatorInstall(cfg)
i.Logf = log.Printf

Expand All @@ -19,7 +24,7 @@ func newOperatorInstallCmd(cfg *action.Configuration) *cobra.Command {
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
i.Package = args[0]
ctx, cancel := context.WithTimeout(cmd.Context(), i.InstallTimeout)
ctx, cancel := context.WithTimeout(cmd.Context(), timeout)
defer cancel()
csv, err := i.Run(ctx)
if err != nil {
Expand All @@ -28,6 +33,23 @@ func newOperatorInstallCmd(cfg *action.Configuration) *cobra.Command {
log.Printf("operator %q installed; installed csv is %q", i.Package, csv.Name)
},
}
i.BindFlags(cmd.Flags())
bindOperatorInstallFlags(cmd.Flags(), i)
cmd.Flags().DurationVarP(&timeout, "timeout", "t", time.Minute, "the amount of time to wait before cancelling the install")

return cmd
}

func bindOperatorInstallFlags(fs *pflag.FlagSet, i *action.OperatorInstall) {
fs.StringVarP(&i.Channel, "channel", "c", "", "subscription channel")
fs.VarP(&i.Approval, "approval", "a", fmt.Sprintf("approval (%s or %s)", v1alpha1.ApprovalManual, v1alpha1.ApprovalAutomatic))
fs.StringVarP(&i.Version, "version", "v", "", "install specific version for operator (default latest)")
fs.StringSliceVarP(&i.WatchNamespaces, "watch", "w", []string{}, "namespaces to watch")
fs.DurationVar(&i.CleanupTimeout, "cleanup-timeout", time.Minute, "the amount to time to wait before cancelling cleanup")
fs.BoolVarP(&i.CreateOperatorGroup, "create-operator-group", "C", false, "create operator group if necessary")

fs.VarP(&i.InstallMode, "install-mode", "i", "install mode")
err := fs.MarkHidden("install-mode")
if err != nil {
panic(`requested flag "install-mode" missing`)
}
}
7 changes: 6 additions & 1 deletion internal/cmd/operator_list_available.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/duration"

Expand Down Expand Up @@ -56,6 +57,10 @@ func newOperatorListAvailableCmd(cfg *action.Configuration) *cobra.Command {
_ = tw.Flush()
},
}
l.BindFlags(cmd.Flags())
bindOperatorListAvailableFlags(cmd.Flags(), l)
return cmd
}

func bindOperatorListAvailableFlags(fs *pflag.FlagSet, l *action.OperatorListAvailable) {
fs.VarP(&l.Catalog, "catalog", "c", "catalog to query (default: search all cluster catalogs)")
}
10 changes: 9 additions & 1 deletion internal/cmd/operator_uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
"github.com/operator-framework/kubectl-operator/internal/pkg/action"
Expand All @@ -23,6 +24,13 @@ func newOperatorUninstallCmd(cfg *action.Configuration) *cobra.Command {
log.Printf("operator %q uninstalled", u.Package)
},
}
u.BindFlags(cmd.Flags())
bindOperatorUninstallFlags(cmd.Flags(), u)
return cmd
}

func bindOperatorUninstallFlags(fs *pflag.FlagSet, u *action.OperatorUninstall) {
fs.BoolVarP(&u.DeleteAll, "delete-all", "X", false, "enable all delete flags")
fs.BoolVar(&u.DeleteCRDs, "delete-crds", false, "delete all owned CRDs and all CRs")
fs.BoolVar(&u.DeleteOperatorGroups, "delete-operator-groups", false, "delete operator groups if no other operators remain")
fs.StringSliceVar(&u.DeleteOperatorGroupNames, "delete-operator-group-names", nil, "specific operator group names to delete (only effective with --delete-operator-groups)")
}
12 changes: 10 additions & 2 deletions internal/cmd/operator_upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,25 @@ package cmd

import (
"context"
"time"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
"github.com/operator-framework/kubectl-operator/internal/pkg/action"
)

func newOperatorUpgradeCmd(cfg *action.Configuration) *cobra.Command {
var timeout time.Duration
u := action.NewOperatorUpgrade(cfg)
cmd := &cobra.Command{
Use: "upgrade <operator>",
Short: "Upgrade an operator",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
u.Package = args[0]
ctx, cancel := context.WithTimeout(cmd.Context(), u.UpgradeTimeout)
ctx, cancel := context.WithTimeout(cmd.Context(), timeout)
defer cancel()
csv, err := u.Run(ctx)
if err != nil {
Expand All @@ -26,6 +29,11 @@ func newOperatorUpgradeCmd(cfg *action.Configuration) *cobra.Command {
log.Printf("operator %q upgraded; installed csv is %q", u.Package, csv.Name)
},
}
u.BindFlags(cmd.Flags())
bindOperatorUpgradeFlags(cmd.Flags(), u)
cmd.Flags().DurationVarP(&timeout, "timeout", "t", time.Minute, "the amount of time to wait before cancelling the upgrade")
return cmd
}

func bindOperatorUpgradeFlags(fs *pflag.FlagSet, u *action.OperatorUpgrade) {
fs.StringVarP(&u.Channel, "channel", "c", "", "subscription channel")
}
25 changes: 6 additions & 19 deletions internal/pkg/action/catalog_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/operator-framework/api/pkg/operators/v1alpha1"
"github.com/operator-framework/operator-registry/pkg/image"
"github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
"github.com/spf13/pflag"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -27,7 +26,7 @@ import (
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

"github.com/operator-framework/kubectl-operator/internal/pkg/catalog"
"github.com/operator-framework/kubectl-operator/internal/pkg/catalogsource"
)

const (
Expand All @@ -47,7 +46,6 @@ type CatalogAdd struct {
InjectBundleMode string
DisplayName string
Publisher string
AddTimeout time.Duration
CleanupTimeout time.Duration

Logf func(string, ...interface{})
Expand All @@ -63,17 +61,6 @@ func NewCatalogAdd(cfg *Configuration) *CatalogAdd {
}
}

func (a *CatalogAdd) BindFlags(fs *pflag.FlagSet) {
fs.StringVarP(&a.DisplayName, "display-name", "d", "", "display name of the index")
fs.StringVarP(&a.Publisher, "publisher", "p", "", "publisher of the index")
fs.DurationVarP(&a.AddTimeout, "timeout", "t", time.Minute, "the amount of time to wait before cancelling the catalog addition")
fs.DurationVar(&a.CleanupTimeout, "cleanup-timeout", time.Minute, "the amount to time to wait before cancelling cleanup")

fs.StringArrayVarP(&a.InjectBundles, "inject-bundles", "b", nil, "inject extra bundles into the index at runtime")
fs.StringVarP(&a.InjectBundleMode, "inject-bundle-mode", "m", "", "mode to use to inject bundles")
_ = fs.MarkHidden("inject-bundle-mode")
}

func (a *CatalogAdd) Run(ctx context.Context) (*v1alpha1.CatalogSource, error) {
var err error
a.registry, err = containerdregistry.NewRegistry(a.RegistryOptions...)
Expand All @@ -99,16 +86,16 @@ func (a *CatalogAdd) Run(ctx context.Context) (*v1alpha1.CatalogSource, error) {

a.setDefaults(labels)

opts := []catalog.Option{
catalog.DisplayName(a.DisplayName),
catalog.Publisher(a.Publisher),
opts := []catalogsource.Option{
catalogsource.DisplayName(a.DisplayName),
catalogsource.Publisher(a.Publisher),
}

if len(a.InjectBundles) == 0 {
opts = append(opts, catalog.Image(a.IndexImage))
opts = append(opts, catalogsource.Image(a.IndexImage))
}

cs := catalog.Build(csKey, opts...)
cs := catalogsource.Build(csKey, opts...)
if err := a.config.Client.Create(ctx, cs); err != nil {
return nil, fmt.Errorf("create catalogsource: %v", err)
}
Expand Down

0 comments on commit b4e7a70

Please sign in to comment.