-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #47 from foomo/digitialocean/doctl
feat: add digitalocean/doctl
- Loading branch information
Showing
22 changed files
with
703 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# POSH doctl provider | ||
|
||
## Usage | ||
|
||
### Plugin | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"github.com/foomo/posh/provider/foomo/gotsrpc" | ||
"github.com/foomo/posh/pkg/command" | ||
"github.com/foomo/posh/pkg/log" | ||
"github.com/foomo/posh/pkg/plugin" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
type Plugin struct { | ||
l log.Logger | ||
cache cache.Cache | ||
doctl *doctl.Doctl | ||
commands command.Commands | ||
} | ||
|
||
func New(l log.Logger) (plugin.Plugin, error) { | ||
var err error | ||
inst := &Plugin{ | ||
l: l, | ||
cache: &cache.MemoryCache{}, | ||
commands: command.Commands{}, | ||
} | ||
|
||
// ... | ||
|
||
inst.doctl, err = doctl.New(l, inst.cache) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to create doctl") | ||
} | ||
|
||
// ... | ||
|
||
return inst, nil | ||
} | ||
``` | ||
|
||
### Config | ||
|
||
```yaml | ||
## doctl | ||
doctl: | ||
configPath: .posh/config/doctl.yaml | ||
clusters: | ||
prod: | ||
name: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX | ||
``` | ||
### Ownbrew | ||
To install binary locally, add: | ||
```yaml | ||
ownbrew: | ||
packages: | ||
## https://github.com/digitalocean/doctl/releases | ||
- name: doctl | ||
tap: foomo/tap/digitalocean/doctl | ||
version: 1.100.0 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package doctl | ||
|
||
type Cluster struct { | ||
Name string `json:"name" yaml:"name"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package doctl | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/foomo/posh-providers/kubernets/kubectl" | ||
"github.com/foomo/posh/pkg/cache" | ||
"github.com/foomo/posh/pkg/command/tree" | ||
"github.com/foomo/posh/pkg/log" | ||
"github.com/foomo/posh/pkg/prompt/goprompt" | ||
"github.com/foomo/posh/pkg/readline" | ||
"github.com/foomo/posh/pkg/shell" | ||
"github.com/foomo/posh/pkg/util/suggests" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type ( | ||
Command struct { | ||
l log.Logger | ||
name string | ||
doctl *Doctl | ||
cache cache.Cache | ||
kubectl *kubectl.Kubectl | ||
commandTree tree.Root | ||
clusterNameFn ClusterNameFn | ||
} | ||
ClusterNameFn func(name string, cluster Cluster) string | ||
CommandOption func(*Command) | ||
) | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// ~ Options | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
func CommandWithName(v string) CommandOption { | ||
return func(o *Command) { | ||
o.name = v | ||
} | ||
} | ||
|
||
func CommandWithClusterNameFn(v ClusterNameFn) CommandOption { | ||
return func(o *Command) { | ||
o.clusterNameFn = v | ||
} | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// ~ Constructor | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
func NewCommand(l log.Logger, cache cache.Cache, doctl *Doctl, kubectl *kubectl.Kubectl, opts ...CommandOption) *Command { | ||
inst := &Command{ | ||
l: l.Named("doctl"), | ||
name: "doctl", | ||
cache: cache, | ||
doctl: doctl, | ||
kubectl: kubectl, | ||
clusterNameFn: func(name string, cluster Cluster) string { | ||
return name | ||
}, | ||
} | ||
for _, opt := range opts { | ||
if opt != nil { | ||
opt(inst) | ||
} | ||
} | ||
|
||
inst.commandTree = tree.New(&tree.Node{ | ||
Name: inst.name, | ||
Description: "Manage digital ocean resources", | ||
Nodes: tree.Nodes{ | ||
{ | ||
Name: "auth", | ||
Execute: inst.auth, | ||
}, | ||
{ | ||
Name: "kubeconfig", | ||
Description: "Retrieve credentials to access remote cluster.", | ||
Args: tree.Args{ | ||
{ | ||
Name: "cluster", | ||
Description: "Name of the cluster.", | ||
Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest { | ||
return suggests.List(inst.doctl.cfg.ClusterNames()) | ||
}, | ||
}, | ||
}, | ||
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { | ||
fs.Internal().String("profile", "", "Store credentials in given profile.") | ||
return fs.Internal().SetValues("profile", "digitalocean") | ||
}, | ||
Execute: inst.kubeconfig, | ||
}, | ||
}, | ||
}) | ||
|
||
return inst | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// ~ Public methods | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
func (c *Command) Name() string { | ||
return c.commandTree.Node().Name | ||
} | ||
|
||
func (c *Command) Description() string { | ||
return c.commandTree.Node().Description | ||
} | ||
|
||
func (c *Command) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest { | ||
return c.commandTree.Complete(ctx, r) | ||
} | ||
|
||
func (c *Command) Execute(ctx context.Context, r *readline.Readline) error { | ||
return c.commandTree.Execute(ctx, r) | ||
} | ||
|
||
func (c *Command) Help(ctx context.Context, r *readline.Readline) string { | ||
return c.commandTree.Help(ctx, r) | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// ~ Private methods | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
func (c *Command) kubeconfig(ctx context.Context, r *readline.Readline) error { | ||
var args []string | ||
ifs := r.FlagSets().Internal() | ||
clusterName := r.Args().At(1) | ||
|
||
cluster, err := c.doctl.cfg.Cluster(clusterName) | ||
if err != nil { | ||
return errors.Errorf("failed to retrieve cluster for: %q", clusterName) | ||
} | ||
|
||
kubectlCluster := c.kubectl.Cluster(c.clusterNameFn(clusterName, cluster)) | ||
if kubectlCluster == nil { | ||
return errors.Errorf("failed to retrieve kubectl cluster for: %q", cluster.Name) | ||
} | ||
|
||
profile, err := ifs.GetString("profile") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return shell.New(ctx, c.l, "doctl", "kubernetes", "cluster", "kubeconfig", "save", cluster.Name). | ||
Args(args...). | ||
Args(r.AdditionalArgs()...). | ||
Env(kubectlCluster.Env(profile)). | ||
Run() | ||
} | ||
|
||
func (c *Command) auth(ctx context.Context, r *readline.Readline) error { | ||
return shell.New(ctx, c.l, "doctl", "auth", "init"). | ||
Args(r.Flags()...). | ||
Args(r.AdditionalArgs()...). | ||
Args(r.AdditionalFlags()...). | ||
Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package doctl | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"github.com/samber/lo" | ||
) | ||
|
||
type Config struct { | ||
ConfigPath string `json:"configPath" yaml:"configPath"` | ||
Clusters map[string]Cluster `json:"clusters" yaml:"clusters"` | ||
} | ||
|
||
func (c Config) Cluster(name string) (Cluster, error) { | ||
value, ok := c.Clusters[name] | ||
if !ok { | ||
return Cluster{}, errors.Errorf("given cluster not found: %s", name) | ||
} | ||
return value, nil | ||
} | ||
|
||
func (c Config) ClusterNames() []string { | ||
return lo.Keys(c.Clusters) | ||
} |
Oops, something went wrong.