Skip to content

Commit

Permalink
kubernetes: cache downloaded dependencies
Browse files Browse the repository at this point in the history
Signed-off-by: Abiola Ibrahim <[email protected]>
  • Loading branch information
abiosoft committed Sep 26, 2021
1 parent 480f457 commit c792a9d
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 26 deletions.
7 changes: 5 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package config

import (
"fmt"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/yamlutil"
"gopkg.in/yaml.v3"
"log"
"net"
Expand Down Expand Up @@ -32,6 +32,9 @@ func SSHPort() int { return sshPort }
// Dir returns the configuration directory.
func Dir() string { return configDir }

// CacheDir returns the cache directory.
func CacheDir() string { return cacheDir }

// LogFile returns the path the command log output.
func LogFile() string {
return filepath.Join(cacheDir, "out.log")
Expand Down Expand Up @@ -71,7 +74,7 @@ func configFile() string {

// Save saves the config.
func Save(c Config) error {
return util.WriteYAML(c, configFile())
return yamlutil.WriteYAML(c, configFile())
}

// Load loads the config.
Expand Down
9 changes: 5 additions & 4 deletions environment/container/kubernetes/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import (
"fmt"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/util/downloader"
"os"
"path/filepath"
"runtime"
)

func installContainerdDeps(guest environment.GuestActions, r *cli.ActiveCommandChain) {
func installContainerdDeps(host environment.HostActions, guest environment.GuestActions, r *cli.ActiveCommandChain) {
// install crictl
installCrictl(guest, r)
installCrictl(host, guest, r)

// minikube with containerd still needs docker :( https://github.com/kubernetes/minikube/issues/10908
// the good news is we can spoof it.
Expand Down Expand Up @@ -47,7 +48,7 @@ func installContainerdDeps(guest environment.GuestActions, r *cli.ActiveCommandC
})
}

func installCrictl(guest environment.GuestActions, r *cli.ActiveCommandChain) {
func installCrictl(host environment.Host, guest environment.GuestActions, r *cli.ActiveCommandChain) {
// TODO figure a way to keep up to date.
version := "v1.22.0"
downloadPath := "/tmp/crictl.tar.gz"
Expand All @@ -63,7 +64,7 @@ func installCrictl(guest environment.GuestActions, r *cli.ActiveCommandChain) {
})

r.Add(func() error {
return guest.RunInteractive("curl", "-L", "-#", "-o", downloadPath, url)
return downloader.Download(host, guest, url, downloadPath)
})
r.Add(func() error {
return guest.Run("sudo", "tar", "xvfz", downloadPath, "-C", "/usr/local/bin")
Expand Down
4 changes: 2 additions & 2 deletions environment/container/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ func (c *kubernetesRuntime) Provision() error {

case containerd.Name:
r.Stage("installing " + containerRuntime + " dependencies")
installContainerdDeps(c.guest, r)
installContainerdDeps(c.host, c.guest, r)

case docker.Name:
// no known dependencies for now
}

// minikube
r.Stage("installing minikube")
installMinikube(c.guest, r, c.kubernetesVersion())
installMinikube(c.host, c.guest, r, c.kubernetesVersion())

// adding to chain to ensure it executes after successful provision
r.Add(func() error {
Expand Down
11 changes: 6 additions & 5 deletions environment/container/kubernetes/minikube.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@ package kubernetes
import (
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/util/downloader"
"runtime"
)

func installMinikube(guest environment.GuestActions, r *cli.ActiveCommandChain, kubeVersion string) {
installMinikubeCache(guest, r, kubeVersion)
func installMinikube(host environment.HostActions, guest environment.GuestActions, r *cli.ActiveCommandChain, kubeVersion string) {
installMinikubeCache(host, guest, r, kubeVersion)

// install minikube last to ensure it is the last step
downloadPath := "/tmp/minikube"
url := "https://storage.googleapis.com/minikube/releases/latest/minikube-linux-" + runtime.GOARCH
r.Add(func() error {
return guest.RunInteractive("curl", "-L", "-#", "-o", downloadPath, url)
return downloader.Download(host, guest, url, downloadPath)
})
r.Add(func() error {
return guest.Run("sudo", "install", downloadPath, "/usr/local/bin/minikube")
})
}

func installMinikubeCache(guest environment.GuestActions, r *cli.ActiveCommandChain, kubeVersion string) {
func installMinikubeCache(host environment.HostActions, guest environment.GuestActions, r *cli.ActiveCommandChain, kubeVersion string) {
downloadPath := "/tmp/minikube-cache.tar.gz"
url := "https://dl.k8s.io/" + kubeVersion + "/kubernetes-node-linux-" + runtime.GOARCH + ".tar.gz"
r.Add(func() error {
return guest.RunInteractive("curl", "-L", "-#", "-o", downloadPath, url)
return downloader.Download(host, guest, url, downloadPath)
})
r.Add(func() error {
return guest.Run("tar", "xvfz", downloadPath, "-C", "/tmp")
Expand Down
5 changes: 3 additions & 2 deletions environment/vm/lima/lima.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/yamlutil"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -65,7 +66,7 @@ func (l *limaVM) Start(conf config.Config) error {

r.Add(func() error {
limaConf := newConf(conf)
return util.WriteYAML(limaConf, configFile)
return yamlutil.WriteYAML(limaConf, configFile)
})
r.Add(func() error {
return l.host.Run(limactl, "start", "--tty=false", configFile)
Expand Down Expand Up @@ -97,7 +98,7 @@ func (l limaVM) resume(conf config.Config) error {

r.Add(func() error {
limaConf := newConf(conf)
return util.WriteYAML(limaConf, configFile)
return yamlutil.WriteYAML(limaConf, configFile)
})

r.Stage("starting")
Expand Down
68 changes: 68 additions & 0 deletions util/downloader/download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package downloader

import (
"crypto/sha256"
"fmt"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment"
"os"
"path/filepath"
)

// Download downloads file at url and saves it in the destination.
//
// In the implementation, the file is downloaded (and cached) on the host, but copied to the desired
// destination for the guest.
// fileName must be a directory on the guest that does not require root access.
func Download(host environment.HostActions, guest environment.GuestActions, url, fileName string) error {
d := downloader{
host: host,
guest: guest,
}

if !d.hasCache(url) {
if err := d.downloadFile(url); err != nil {
return fmt.Errorf("error downloading '%s': %w", url, err)
}
}

return guest.Run("cp", d.cacheFileName(url), fileName)
}

type downloader struct {
host environment.HostActions
guest environment.GuestActions
}

func (d downloader) cacheFileName(url string) string {
return filepath.Join(config.CacheDir(), "caches", sha256Hash(url))
}

func (d downloader) cacheDownloadingFileName(url string) string {
return d.cacheFileName(url) + ".downloading"
}

func (d downloader) downloadFile(url string) (err error) {
// save to a temporary file initially before renaming to the desired file after successful download
// this prevents having a corrupt file
cacheFileName := d.cacheDownloadingFileName(url)
if err := d.host.Run("mkdir", "-p", filepath.Dir(cacheFileName)); err != nil {
return fmt.Errorf("error preparing cache dir: %w", err)
}
// ask curl to resume previous download if possible
if err := d.host.RunInteractive("curl", "-L", "-#", "-C", "-", "-o", cacheFileName, url); err != nil {
return err
}
return d.host.Run("cp", d.cacheDownloadingFileName(url), d.cacheFileName(url))

}

func (d downloader) hasCache(url string) bool {
_, err := os.Stat(d.cacheFileName(url))
return err == nil
}

func sha256Hash(s string) string {
sum := sha256.Sum256([]byte(s))
return fmt.Sprintf("%x", sum)
}
11 changes: 0 additions & 11 deletions util/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package util
import (
"bytes"
"fmt"
"gopkg.in/yaml.v3"
"os"
"text/template"
)
Expand Down Expand Up @@ -31,13 +30,3 @@ func ParseTemplate(body string, values interface{}) ([]byte, error) {

return b.Bytes(), err
}

// WriteYAML encodes struct to file as YAML.
func WriteYAML(value interface{}, file string) error {
b, err := yaml.Marshal(value)
if err != nil {
return fmt.Errorf("error encoding YAML: %w", err)
}

return os.WriteFile(file, b, 0644)
}
17 changes: 17 additions & 0 deletions util/yamlutil/yaml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package yamlutil

import (
"fmt"
"gopkg.in/yaml.v3"
"os"
)

// WriteYAML encodes struct to file as YAML.
func WriteYAML(value interface{}, file string) error {
b, err := yaml.Marshal(value)
if err != nil {
return fmt.Errorf("error encoding YAML: %w", err)
}

return os.WriteFile(file, b, 0644)
}

0 comments on commit c792a9d

Please sign in to comment.