Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli: add update command #1178

Merged
merged 4 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type App interface {
Status(extended bool) error
Version() error
Runtime() (string, error)
Update() error
Kubernetes() (environment.Container, error)
}

Expand Down Expand Up @@ -454,6 +455,25 @@ func (c colimaApp) Active() bool {
return c.guest.Running(context.Background())
}

func (c *colimaApp) Update() error {
ctx := context.Background()
if !c.guest.Running(ctx) {
return fmt.Errorf("%s is not running", config.CurrentProfile().DisplayName)
}

runtime, err := c.currentRuntime(ctx)
if err != nil {
return err
}

container, err := c.containerEnvironment(runtime)
if err != nil {
return err
}

return container.Update(ctx)
}

func generateSSHConfig(modifySSHConfig bool) error {
instances, err := limautil.Instances()
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ var rootCmd = &cobra.Command{
switch cmd.Name() {

// special case handling for commands directly interacting with the VM
// start, stop, restart, delete, status, version, ssh-config
// start, stop, restart, delete, status, version, update, ssh-config
case "start",
"stop",
"restart",
"delete",
"status",
"version",
"update",
"ssh-config":

// if an arg is passed, assume it to be the profile (provided --profile is unset)
Expand Down
22 changes: 22 additions & 0 deletions cmd/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)

// statusCmd represents the status command
var updateCmd = &cobra.Command{
Use: "update [profile]",
Aliases: []string{"u", "up"},
Short: "update the container runtime",
Long: `Update the current container runtime.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Update()
},
}

func init() {
root.Cmd().AddCommand(updateCmd)
}
2 changes: 2 additions & 0 deletions environment/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type Container interface {
Stop(ctx context.Context) error
// Teardown tears down/uninstall the container runtime.
Teardown(ctx context.Context) error
// Update the container runtime.
Update(ctx context.Context) error
// Version returns the container runtime version.
Version(ctx context.Context) string
// Running returns if the container runtime is currently running.
Expand Down
5 changes: 5 additions & 0 deletions environment/container/containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package containerd
import (
"context"
_ "embed"
"fmt"
"path/filepath"
"time"

Expand Down Expand Up @@ -101,3 +102,7 @@ func (c containerdRuntime) Version(ctx context.Context) string {
version, _ := c.guest.RunOutput("sudo", "nerdctl", "version", "--format", `client: {{.Client.Version}}{{printf "\n"}}server: {{(index .Server.Components 0).Version}}`)
return version
}

func (c *containerdRuntime) Update(ctx context.Context) error {
return fmt.Errorf("update not supported for the %s runtime", Name)
}
11 changes: 11 additions & 0 deletions environment/container/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/util/debutil"
)

// Name is container runtime name.
Expand Down Expand Up @@ -133,3 +134,13 @@ func (d dockerRuntime) Version(ctx context.Context) string {
version, _ := d.host.RunOutput("docker", "version", "--format", `client: v{{.Client.Version}}{{printf "\n"}}server: v{{.Server.Version}}`)
return version
}

func (d *dockerRuntime) Update(ctx context.Context) error {
packages := []string{
"docker-ce",
"docker-ce-cli",
"containerd.io",
}

return debutil.UpdateRuntime(ctx, d.guest, d, Name, packages...)
}
2 changes: 1 addition & 1 deletion environment/container/incus/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ config:
core.https_address: '[::]:8443'
networks:
- config:
ipv4.address: 10.0.0.1/8
ipv4.address: 192.100.0.1/24
ipv4.nat: "true"
ipv6.address: auto
description: ""
Expand Down
13 changes: 13 additions & 0 deletions environment/container/incus/incus.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/debutil"
)

const incusBridgeInterface = "incusbr0"
Expand Down Expand Up @@ -278,3 +279,15 @@ type networkInfo struct {
Managed bool `json:"managed"`
Type string `json:"type"`
}

func (c *incusRuntime) Update(ctx context.Context) error {
packages := []string{
"incus",
"incus-base",
"incus-client",
"incus-extra",
"incus-ui-canonical",
}

return debutil.UpdateRuntime(ctx, c.guest, c, Name, packages...)
}
5 changes: 5 additions & 0 deletions environment/container/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,8 @@ func (c kubernetesRuntime) Version(context.Context) string {
version, _ := c.host.RunOutput("kubectl", "--context", config.CurrentProfile().ID, "version", "--short")
return version
}

func (c *kubernetesRuntime) Update(ctx context.Context) error {
// update not supported
return nil
}
84 changes: 84 additions & 0 deletions util/debutil/debutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package debutil

import (
"context"
"fmt"
"strings"

"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/environment"
)

// packages is list of deb package names.
type packages []string

// Upgradable returns the shell command to check if the packages are upgradable with apt.
// The returned command should be passed to 'sh -c' or equivalent.
func (p packages) Upgradable() string {
cmd := "sudo apt list --upgradable | grep"
for _, v := range p {
cmd += fmt.Sprintf(" -e '^%s/'", v)
}
return cmd
}

// Install returns the shell command to install the packages with apt.
// The returned command should be passed to 'sh -c' or equivalent.
func (p packages) Install() string {
return "sudo apt-get install -y --allow-change-held-packages " + strings.Join(p, " ")
}

func UpdateRuntime(
ctx context.Context,
guest environment.GuestActions,
chain cli.CommandChain,
runtime string,
packageNames ...string,
) error {
a := chain.Init(ctx)
log := a.Logger()

packages := packages(packageNames)

updatesAvailable := false

a.Stage("refreshing package manager")
a.Add(func() error {
return guest.RunQuiet(
"sh",
"-c",
"sudo apt-get update -y",
)
})

a.Stage("checking for updates")
a.Add(func() error {
err := guest.RunQuiet(
"sh",
"-c",
packages.Upgradable(),
)
updatesAvailable = err == nil
return nil
})

a.Add(func() (err error) {
if !updatesAvailable {
log.Warnf("no updates available for %s runtime", runtime)
return
}

log.Println("updating packages ...")
err = guest.RunQuiet(
"sh",
"-c",
packages.Install(),
)
if err == nil {
log.Println("done")
}
return
})

return a.Exec()
}
Loading