Skip to content

Commit

Permalink
cli: ux improvements (#207)
Browse files Browse the repository at this point in the history
* cli: accept profile name as arg for some commands

* cli: remove obsolete --port-interface flag

* vm: delegate port allocation to Lima

* cli: add ssh-config

* ssh-config: remove 'lima-' prefix from hostname
  • Loading branch information
abiosoft authored Mar 7, 2022
1 parent 5085352 commit 316ba9c
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 57 deletions.
8 changes: 0 additions & 8 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package app

import (
"fmt"
"strconv"

"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment"
Expand Down Expand Up @@ -75,9 +74,6 @@ func (c colimaApp) Start(conf config.Config) error {
if err := c.setRuntime(conf.Runtime); err != nil {
return fmt.Errorf("error setting current runtime: %w", err)
}
if err := c.setSSHPort(conf.VM.SSHPort); err != nil {
return fmt.Errorf("error setting SSH port: %w", err)
}
// persist kubernetes version for future reference.
if err := c.setKubernetesVersion(conf.Kubernetes.Version); err != nil {
return fmt.Errorf("error setting kubernetes version: %w", err)
Expand Down Expand Up @@ -252,10 +248,6 @@ func (c colimaApp) setKubernetesVersion(version string) error {
return c.guest.Set(environment.KubernetesVersionKey, version)
}

func (c colimaApp) setSSHPort(sshPort int) error {
return c.guest.Set(environment.SSHPortKey, strconv.Itoa(sshPort))
}

func (c colimaApp) currentContainerEnvironments() ([]environment.Container, error) {
var containers []environment.Container

Expand Down
4 changes: 2 additions & 2 deletions cmd/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ var deleteCmdArgs struct {

// deleteCmd represents the delete command
var deleteCmd = &cobra.Command{
Use: "delete",
Use: "delete [profile]",
Short: "delete and teardown Colima",
Long: `Delete and teardown Colima and all settings.
Use with caution. This deletes everything and a startup afterwards is like the
initial startup of Colima.
If you simply want to reset the Kubernetes cluster, run 'colima kubernetes reset'.`,
Args: cobra.NoArgs,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if !deleteCmdArgs.force {
y := cli.Prompt("are you sure you want to delete " + config.Profile().DisplayName + " and all settings")
Expand Down
11 changes: 11 additions & 0 deletions cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ var rootCmd = &cobra.Command{
Short: "container runtimes on macOS with minimal setup",
Long: `Colima provides container runtimes on macOS with minimal setup.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {

switch cmd.Name() {
// special case handling for commands directly interacting with the VM
// start, stop, delete, status, version, ssh-config
case "start", "stop", "delete", "status", "version", "ssh-config":
// if an arg is passed, assume it to be the profile (provided --profile is unset)
// i.e. colima start docker == colima start --profile=docker
if len(args) > 0 && !cmd.Flag("profile").Changed {
rootCmdArgs.Profile = args[0]
}
}
if rootCmdArgs.Profile != "" {
config.SetProfile(rootCmdArgs.Profile)
}
Expand Down
29 changes: 29 additions & 0 deletions cmd/ssh-config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmd

import (
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/vm/lima"
"github.com/spf13/cobra"
)

// statusCmd represents the status command
var sshConfigCmd = &cobra.Command{
Use: "ssh-config [profile]",
Short: "show SSH connection config",
Long: `Show configuration of the SSH connection to the VM.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return lima.ShowSSH(config.Profile().ID, sshConfigCmdArgs.format)
},
}

var sshConfigCmdArgs struct {
format string
}

func init() {
root.Cmd().AddCommand(sshConfigCmd)

sshConfigCmd.Flags().StringVarP(&sshConfigCmdArgs.format, "format", "f", "config", "format (config, cmd)")
}
28 changes: 2 additions & 26 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
"fmt"
"net"
"runtime"
"strings"

Expand All @@ -16,7 +15,7 @@ import (

// startCmd represents the start command
var startCmd = &cobra.Command{
Use: "start",
Use: "start [profile]",
Short: "start Colima",
Long: `Start Colima with the specified container runtime (and kubernetes if --with-kubernetes is passed).
The --runtime, --disk and --arch flags are only used on initial start and ignored on subsequent starts.
Expand All @@ -28,14 +27,11 @@ The --runtime, --disk and --arch flags are only used on initial start and ignore
" colima start --cpu 4 --memory 8 --disk 100\n" +
" colima start --arch aarch64\n" +
" colima start --dns 1.1.1.1 --dns 8.8.8.8",
Args: cobra.NoArgs,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Start(startCmdArgs.Config)
},
PreRunE: func(cmd *cobra.Command, args []string) error {
// set port
startCmdArgs.VM.SSHPort = randomAvailablePort()

current, err := config.Load()
if err != nil {
// not fatal, will proceed with defaults
Expand Down Expand Up @@ -69,9 +65,6 @@ The --runtime, --disk and --arch flags are only used on initial start and ignore
if !cmd.Flag("mount").Changed {
startCmdArgs.VM.Mounts = current.VM.Mounts
}
if !cmd.Flag("port-interface").Changed {
startCmdArgs.PortInterface = current.PortInterface
}
if !cmd.Flag("ssh-agent").Changed {
startCmdArgs.VM.ForwardAgent = current.VM.ForwardAgent
}
Expand Down Expand Up @@ -100,23 +93,9 @@ var startCmdArgs struct {
config.Config
}

func randomAvailablePort() int {
listener, err := net.Listen("tcp", ":0")
if err != nil {
log.Fatal(fmt.Errorf("error picking an available port: %w", err))
}

if err := listener.Close(); err != nil {
log.Fatal(fmt.Errorf("error closing temporary port listener: %w", err))
}

return listener.Addr().(*net.TCPAddr).Port
}

func init() {
runtimes := strings.Join(environment.ContainerRuntimes(), ", ")
defaultArch := string(environment.Arch(runtime.GOARCH).Value())
defaultPortInterface := net.ParseIP("0.0.0.0")

root.Cmd().AddCommand(startCmd)
startCmd.Flags().StringVarP(&startCmdArgs.Runtime, "runtime", "r", docker.Name, "container runtime ("+runtimes+")")
Expand All @@ -128,9 +107,6 @@ func init() {
// mounts
startCmd.Flags().StringSliceVarP(&startCmdArgs.VM.Mounts, "mount", "v", nil, "directories to mount, suffix ':w' for writable")

// port forwarding
startCmd.Flags().IPVarP(&startCmdArgs.PortInterface, "port-interface", "i", defaultPortInterface, "interface to use for forwarded ports")

// ssh agent
startCmd.Flags().BoolVarP(&startCmdArgs.VM.ForwardAgent, "ssh-agent", "s", false, "forward SSH agent to the VM")

Expand Down
4 changes: 2 additions & 2 deletions cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (

// statusCmd represents the status command
var statusCmd = &cobra.Command{
Use: "status",
Use: "status [profile]",
Short: "show the status of Colima",
Long: `Show the status of Colima`,
Args: cobra.NoArgs,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Status()
},
Expand Down
4 changes: 2 additions & 2 deletions cmd/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (

// stopCmd represents the stop command
var stopCmd = &cobra.Command{
Use: "stop",
Use: "stop [profile]",
Short: "stop Colima",
Long: `Stop stops Colima to free up resources.
The state of the VM is persisted at stop. A start afterwards
should return it back to its previous state.`,
Args: cobra.NoArgs,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Stop()
},
Expand Down
4 changes: 2 additions & 2 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (

// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version",
Use: "version [profile]",
Short: "print the version of Colima",
Long: `Print the version of Colima`,
Args: cobra.NoArgs,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
version := config.AppVersion()
fmt.Println(config.AppName, "version", version.Version)
Expand Down
5 changes: 0 additions & 5 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,6 @@ type Config struct {

// Kubernetes sets if kubernetes should be enabled.
Kubernetes Kubernetes `yaml:"kubernetes"`

// Network address to forward VM ports to.
PortInterface net.IP `yaml:"port_interface"`
}

// Kubernetes is kubernetes configuration
Expand All @@ -174,8 +171,6 @@ type VM struct {
Memory int `yaml:"memory"`
Arch string `yaml:"arch"`

// auto generated
SSHPort int `yaml:"-"`
ForwardAgent bool `yaml:"forward_agent"`

// volume mounts
Expand Down
2 changes: 0 additions & 2 deletions environment/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ const (
ContainerRuntimeKey = "runtime"
// KubernetesVersionKey is the settings key for kubernetes version.
KubernetesVersionKey = "kubernetes_version"
// SSHPortKey is the settings for the VM SSH port.
SSHPortKey = "ssh_port"

// BinfmtTarFile is the path in the VM to the binfmt oci image tar.
// TODO: decide if this should reside somewhere else.
Expand Down
32 changes: 28 additions & 4 deletions environment/vm/lima/lima.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,37 @@ func Instances() ([]InstanceInfo, error) {
}

// rename to local friendly names
if i.Name == "colima" {
i.Name = "default"
}
i.Name = strings.TrimPrefix(i.Name, "colima-")
i.Name = toUserFriendlyName(i.Name)

instances = append(instances, i)
}

return instances, nil
}

// ShowSSH runs the show-ssh command in Lima.
func ShowSSH(name, format string) error {
var buf bytes.Buffer
cmd := cli.Command("limactl", "show-ssh", "--format", format, name)
cmd.Stdout = &buf
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
return fmt.Errorf("error retrieving ssh config: %w", err)
}

// TODO: this is a lazy approach, edge cases may not be covered
from := "lima-" + name
to := name
out := strings.ReplaceAll(buf.String(), from, to)

fmt.Println(out)
return nil
}

func toUserFriendlyName(name string) string {
if name == "colima" {
name = "default"
}
return strings.TrimPrefix(name, "colima-")
}
8 changes: 4 additions & 4 deletions environment/vm/lima/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func newConf(conf config.Config) (l Config, err error) {
l.Memory = fmt.Sprintf("%dGiB", conf.VM.Memory)
l.Disk = fmt.Sprintf("%dGiB", conf.VM.Disk)

l.SSH = SSH{LocalPort: conf.VM.SSHPort, LoadDotSSHPubKeys: false, ForwardAgent: conf.VM.ForwardAgent}
l.SSH = SSH{LocalPort: 0, LoadDotSSHPubKeys: false, ForwardAgent: conf.VM.ForwardAgent}
l.Containerd = Containerd{System: false, User: false}
l.Firmware.LegacyBIOS = false

Expand Down Expand Up @@ -121,7 +121,7 @@ type Config struct {
Memory string `yaml:"memory,omitempty"`
Disk string `yaml:"disk,omitempty"`
Mounts []Mount `yaml:"mounts,omitempty"`
SSH SSH `yaml:"ssh,omitempty"`
SSH SSH `yaml:"ssh"`
Containerd Containerd `yaml:"containerd"`
Env map[string]string `yaml:"env,omitempty"`
DNS []net.IP `yaml:"-"` // will be handled manually by colima
Expand All @@ -142,11 +142,11 @@ type Mount struct {
}

type SSH struct {
LocalPort int `yaml:"localPort,omitempty"` // REQUIRED
LocalPort int `yaml:"localPort"`
// LoadDotSSHPubKeys loads ~/.ssh/*.pub in addition to $LIMA_HOME/_config/user.pub .
// Default: true
LoadDotSSHPubKeys bool `yaml:"loadDotSSHPubKeys"`
ForwardAgent bool `yaml:"forwardAgent,omitempty"` // default: false
ForwardAgent bool `yaml:"forwardAgent"` // default: false
}

type Containerd struct {
Expand Down

0 comments on commit 316ba9c

Please sign in to comment.