Skip to content

Commit

Permalink
Merge pull request #420 from tnthornton/spaces-1.2-up-connect
Browse files Browse the repository at this point in the history
space subcommands should respect 'groups'
  • Loading branch information
tnthornton committed Feb 1, 2024
2 parents b7e7360 + 13faf83 commit c2480b1
Show file tree
Hide file tree
Showing 18 changed files with 360 additions and 167 deletions.
15 changes: 10 additions & 5 deletions cmd/up/controlplane/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ import (

"github.com/alecthomas/kong"
"github.com/pterm/pterm"

"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"

"github.com/upbound/up-sdk-go/service/configurations"
cp "github.com/upbound/up-sdk-go/service/controlplanes"

"github.com/upbound/up/internal/controlplane"
"github.com/upbound/up/internal/controlplane/cloud"
"github.com/upbound/up/internal/controlplane/space"
Expand All @@ -47,18 +46,22 @@ const (
)

type ctpConnector interface {
GetKubeConfig(ctx context.Context, name string) (*api.Config, error)
GetKubeConfig(ctx context.Context, ctp types.NamespacedName) (*api.Config, error)
}

// AfterApply sets default values in command after assignment and validation.
func (c *connectCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) error {
c.stdin = os.Stdin

if upCtx.Profile.IsSpace() {
kubeconfig, err := upCtx.Profile.GetKubeClientConfig()
kubeconfig, ns, err := upCtx.Profile.GetKubeClientConfig()
if err != nil {
return err
}
if c.Group == "" {
c.Group = ns
}

client, err := dynamic.NewForConfig(kubeconfig)
if err != nil {
return err
Expand Down Expand Up @@ -104,6 +107,8 @@ type connectCmd struct {
Name string `arg:"" required:"" help:"Name of control plane." predictor:"ctps"`
Token string `help:"API token used to authenticate. Required for Upbound Cloud; ignored otherwise."`

Group string `short:"g" help:"The control plane group that the control plane is contained in. By default, this is the group specified in the current profile."`

stdin io.Reader
client ctpConnector
}
Expand All @@ -129,7 +134,7 @@ func (c *connectCmd) Run(ctx context.Context, printer upterm.ObjectPrinter, p pt
return nil
}

cfg, err := c.client.GetKubeConfig(ctx, c.Name)
cfg, err := c.client.GetKubeConfig(ctx, types.NamespacedName{Namespace: c.Group, Name: c.Name})
if controlplane.IsNotFound(err) {
p.Printfln("Control plane %s not found", c.Name)
return nil
Expand Down
3 changes: 2 additions & 1 deletion cmd/up/controlplane/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import (
"errors"
"testing"

"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/google/go-cmp/cmp"
"k8s.io/client-go/tools/clientcmd/api"

"github.com/crossplane/crossplane-runtime/pkg/test"
)

func TestUpdateKubeConfig(t *testing.T) {
Expand Down
39 changes: 24 additions & 15 deletions cmd/up/controlplane/controlplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ package controlplane

import (
"context"
"time"

"github.com/alecthomas/kong"
"github.com/posener/complete"
"k8s.io/apimachinery/pkg/util/duration"

cp "github.com/upbound/up-sdk-go/service/controlplanes"
"github.com/upbound/up/cmd/up/controlplane/connector"
Expand All @@ -32,8 +34,8 @@ import (
)

var (
cloudfieldNames = []string{"NAME", "ID", "STATUS", "CONFIGURATION", "CONFIGURATION STATUS"}
spacefieldNames = []string{"NAME", "ID", "STATUS", "MESSAGE", "CONNECTION NAME", "CONNECTION NAMESPACE"}
cloudfieldNames = []string{"NAME", "CONFIGURATION", "UPDATED", "SYNCED", "READY", "MESSAGE", "AGE"}
spacefieldNames = []string{"GROUP", "NAME", "CROSSPLANE", "SYNCED", "READY", "MESSAGE", "AGE"}
)

// BeforeReset is the first hook to run.
Expand Down Expand Up @@ -116,40 +118,47 @@ between different Upbound profiles or to connect to a local Space.`
}

func extractCloudFields(obj any) []string {
id, readyStatus := "unknown", "unknown"

resp, ok := obj.(*controlplane.Response)
if !ok {
return []string{"", id, readyStatus}
return []string{"unknown", "unknown", "", "", "", "", ""}
}

return []string{
resp.Name,
resp.ID,
resp.Status,
resp.Cfg,
resp.CfgStatus,
resp.Updated,
resp.Synced,
resp.Ready,
resp.Message,
formatAge(resp.Age),
}
}

func extractSpaceFields(obj any) []string {
id, readyStatus := "unknown", "unknown"

resp, ok := obj.(*controlplane.Response)
if !ok {
return []string{"", id, readyStatus}
return []string{"unknown", "unknown", "", "", "", "", ""}
}

return []string{
resp.Group,
resp.Name,
resp.ID,
resp.Status,
resp.CrossplaneVersion,
resp.Synced,
resp.Ready,
resp.Message,
resp.ConnName,
resp.ConnNamespace,
formatAge(resp.Age),
}
}

func formatAge(age *time.Duration) string {
if age == nil {
return ""
}

return duration.HumanDuration(*age)
}

func tabularPrint(obj any, printer upterm.ObjectPrinter, upCtx *upbound.Context) error {
if upCtx.Profile.IsSpace() {
return printer.Print(obj, spacefieldNames, extractSpaceFields)
Expand Down
19 changes: 11 additions & 8 deletions cmd/up/controlplane/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ import (

"github.com/alecthomas/kong"
"github.com/pterm/pterm"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"

"github.com/upbound/up-sdk-go/service/configurations"
cp "github.com/upbound/up-sdk-go/service/controlplanes"

"github.com/upbound/up/internal/controlplane"
"github.com/upbound/up/internal/controlplane/cloud"
"github.com/upbound/up/internal/controlplane/space"
"github.com/upbound/up/internal/upbound"
)

type ctpCreator interface {
Create(ctx context.Context, name string, opts controlplane.Options) (*controlplane.Response, error)
Create(ctx context.Context, ctp types.NamespacedName, opts controlplane.Options) (*controlplane.Response, error)
}

// createCmd creates a control plane on Upbound.
Expand All @@ -41,20 +41,23 @@ type createCmd struct {
ConfigurationName *string `help:"The optional name of the Configuration."`
Description string `short:"d" help:"Description for control plane."`

SecretName string `help:"The name of the control plane's secret. Defaults to 'kubeconfig-{control plane name}'. Only applicable for Space control planes."`
SecretNamespace string `default:"default" help:"The name of namespace for the control plane's secret. Only applicable for Space control planes."`
SecretName string `help:"The name of the control plane's secret. Defaults to 'kubeconfig-{control plane name}'. Only applicable for Space control planes."`
Group string `short:"g" help:"The control plane group that the control plane is contained in. This defaults to the group specified in the current profile."`

client ctpCreator
}

// AfterApply sets default values in command after assignment and validation.
func (c *createCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) error {

if upCtx.Profile.IsSpace() {
kubeconfig, err := upCtx.Profile.GetKubeClientConfig()
kubeconfig, ns, err := upCtx.Profile.GetKubeClientConfig()
if err != nil {
return err
}
if c.Group == "" {
c.Group = ns
}

client, err := dynamic.NewForConfig(kubeconfig)
if err != nil {
return err
Expand All @@ -79,10 +82,10 @@ func (c *createCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) er
func (c *createCmd) Run(ctx context.Context, p pterm.TextPrinter, upCtx *upbound.Context) error {
_, err := c.client.Create(
ctx,
c.Name,
types.NamespacedName{Name: c.Name, Namespace: c.Group},
controlplane.Options{
SecretName: c.SecretName,
SecretNamespace: c.SecretNamespace,
SecretNamespace: c.Group,
ConfigurationName: c.ConfigurationName,
},
)
Expand Down
16 changes: 10 additions & 6 deletions cmd/up/controlplane/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,40 @@ import (

"github.com/alecthomas/kong"
"github.com/pterm/pterm"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"

"github.com/upbound/up-sdk-go/service/configurations"
cp "github.com/upbound/up-sdk-go/service/controlplanes"

"github.com/upbound/up/internal/controlplane"
"github.com/upbound/up/internal/controlplane/cloud"
"github.com/upbound/up/internal/controlplane/space"
"github.com/upbound/up/internal/upbound"
)

type ctpDeleter interface {
Delete(ctx context.Context, name string) error
Delete(ctx context.Context, ctp types.NamespacedName) error
}

// deleteCmd deletes a control plane on Upbound.
type deleteCmd struct {
Name string `arg:"" help:"Name of control plane." predictor:"ctps"`
Name string `arg:"" help:"Name of control plane." predictor:"ctps"`
Group string `short:"g" help:"The control plane group that the control plane is contained in. This defaults to the group specified in the current profile."`

client ctpDeleter
}

// AfterApply sets default values in command after assignment and validation.
func (c *deleteCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) error {

if upCtx.Profile.IsSpace() {
kubeconfig, err := upCtx.Profile.GetKubeClientConfig()
kubeconfig, ns, err := upCtx.Profile.GetKubeClientConfig()
if err != nil {
return err
}
if c.Group == "" {
c.Group = ns
}

client, err := dynamic.NewForConfig(kubeconfig)
if err != nil {
return err
Expand All @@ -69,7 +73,7 @@ func (c *deleteCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) er

// Run executes the delete command.
func (c *deleteCmd) Run(ctx context.Context, p pterm.TextPrinter, upCtx *upbound.Context) error {
if err := c.client.Delete(ctx, c.Name); err != nil {
if err := c.client.Delete(ctx, types.NamespacedName{Name: c.Name, Namespace: c.Group}); err != nil {
if controlplane.IsNotFound(err) {
p.Printfln("Control plane %s not found", c.Name)
return nil
Expand Down
16 changes: 10 additions & 6 deletions cmd/up/controlplane/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import (

"github.com/alecthomas/kong"
"github.com/pterm/pterm"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"

"github.com/upbound/up-sdk-go/service/configurations"
cp "github.com/upbound/up-sdk-go/service/controlplanes"

"github.com/upbound/up/internal/controlplane"
"github.com/upbound/up/internal/controlplane/cloud"
"github.com/upbound/up/internal/controlplane/space"
Expand All @@ -32,17 +32,20 @@ import (
)

type ctpGetter interface {
Get(ctx context.Context, name string) (*controlplane.Response, error)
Get(ctx context.Context, name types.NamespacedName) (*controlplane.Response, error)
}

// AfterApply sets default values in command after assignment and validation.
func (c *getCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) error {

if upCtx.Profile.IsSpace() {
kubeconfig, err := upCtx.Profile.GetKubeClientConfig()
kubeconfig, ns, err := upCtx.Profile.GetKubeClientConfig()
if err != nil {
return err
}
if c.Group == "" {
c.Group = ns
}

client, err := dynamic.NewForConfig(kubeconfig)
if err != nil {
return err
Expand All @@ -65,14 +68,15 @@ func (c *getCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) error

// getCmd gets a single control plane in an account on Upbound.
type getCmd struct {
Name string `arg:"" required:"" help:"Name of control plane." predictor:"ctps"`
Name string `arg:"" required:"" help:"Name of control plane." predictor:"ctps"`
Group string `short:"g" help:"The control plane group that the control plane is contained in. This defaults to the group specified in the current profile."`

client ctpGetter
}

// Run executes the get command.
func (c *getCmd) Run(ctx context.Context, printer upterm.ObjectPrinter, p pterm.TextPrinter, upCtx *upbound.Context) error {
ctp, err := c.client.Get(ctx, c.Name)
ctp, err := c.client.Get(ctx, types.NamespacedName{Name: c.Name, Namespace: c.Group})
if controlplane.IsNotFound(err) {
p.Printfln("Control plane %s not found", c.Name)
return nil
Expand Down
26 changes: 21 additions & 5 deletions cmd/up/controlplane/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (

"github.com/upbound/up-sdk-go/service/configurations"
cp "github.com/upbound/up-sdk-go/service/controlplanes"

"github.com/upbound/up/internal/controlplane"
"github.com/upbound/up/internal/controlplane/cloud"
"github.com/upbound/up/internal/controlplane/space"
Expand All @@ -32,22 +31,28 @@ import (
)

type ctpLister interface {
List(ctx context.Context) ([]*controlplane.Response, error)
List(ctx context.Context, namespace string) ([]*controlplane.Response, error)
}

// listCmd list control planes in an account on Upbound.
type listCmd struct {
Group string `short:"g" help:"The control plane group that the control plane is contained in. This defaults to the group specified in the current profile."`
AllGroups bool `short:"A" default:"false" help:"List control planes across all groups."`

client ctpLister
}

// AfterApply sets default values in command after assignment and validation.
func (c *listCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) error {

if upCtx.Profile.IsSpace() {
kubeconfig, err := upCtx.Profile.GetKubeClientConfig()
kubeconfig, ns, err := upCtx.Profile.GetKubeClientConfig()
if err != nil {
return err
}
if c.Group == "" {
c.Group = ns
}

client, err := dynamic.NewForConfig(kubeconfig)
if err != nil {
return err
Expand All @@ -70,7 +75,11 @@ func (c *listCmd) AfterApply(kongCtx *kong.Context, upCtx *upbound.Context) erro

// Run executes the list command.
func (c *listCmd) Run(ctx context.Context, printer upterm.ObjectPrinter, p pterm.TextPrinter, upCtx *upbound.Context) error {
l, err := c.client.List(ctx)
l, err := c.client.List(ctx, c.deriveGroup())
if controlplane.IsNotFound(err) {
p.Printfln("No Control planes found in %s group", c.deriveGroup())
return nil
}
if err != nil {
return err
}
Expand All @@ -82,3 +91,10 @@ func (c *listCmd) Run(ctx context.Context, printer upterm.ObjectPrinter, p pterm

return tabularPrint(l, printer, upCtx)
}

func (c *listCmd) deriveGroup() string {
if c.AllGroups {
return ""
}
return c.Group
}

0 comments on commit c2480b1

Please sign in to comment.