Skip to content
Open
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
23 changes: 22 additions & 1 deletion environment/container/kubernetes/k3s.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/abiosoft/colima/environment/container/containerd"
"github.com/abiosoft/colima/environment/container/docker"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/abiosoft/colima/store"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/downloader"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -204,6 +205,7 @@ func installK3sCluster(
func getPortNumber(guest environment.GuestActions, k3sListenPort int) (int, error) {
// port previously set, reuse it
if port, err := strconv.Atoi(guest.Get(listenPortKey)); err == nil && port > 0 {
saveDiskPortNumber(port)
return port, nil
}

Expand All @@ -214,7 +216,10 @@ func getPortNumber(guest environment.GuestActions, k3sListenPort int) (int, erro
}

var port int
if k3sListenPort > 0 {
if p := diskPortNumber(); p > 0 {
// the VM was recreated on a kept runtime disk, whose k3s state still uses this port
port = p
} else if k3sListenPort > 0 {
// template configured port
port = k3sListenPort
} else {
Expand All @@ -225,6 +230,22 @@ func getPortNumber(guest environment.GuestActions, k3sListenPort int) (int, erro
if err := guest.Set(listenPortKey, strconv.Itoa(port)); err != nil {
return 0, err
}
saveDiskPortNumber(port)

return port, nil
}

// diskPortNumber returns the port k3s used on the runtime disk, if any.
func diskPortNumber() int {
s, _ := store.Load()
if !s.DiskFormatted {
return 0
}
return s.K3sListenPort
}

func saveDiskPortNumber(port int) {
if err := store.Set(func(s *store.Store) { s.K3sListenPort = port }); err != nil {
logrus.Traceln(fmt.Errorf("error persisting k3s port: %w", err))
}
}
98 changes: 98 additions & 0 deletions environment/container/kubernetes/k3s_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package kubernetes

import (
"os"
"strconv"
"strings"
"testing"

"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/store"
)

func TestMain(m *testing.M) {
// config dirs are cached on first use, so point them at a temp dir before any test runs
home, err := os.MkdirTemp("", "colima-test")
if err != nil {
panic(err)
}
_ = os.Setenv("COLIMA_HOME", home)
_ = os.Unsetenv("LIMA_HOME")
code := m.Run()
_ = os.RemoveAll(home)
os.Exit(code)
}

type fakeGuest struct {
environment.GuestActions
conf map[string]string
}

func (f fakeGuest) Get(key string) string { return f.conf[key] }

func (f fakeGuest) Set(key, value string) error {
f.conf[key] = value
return nil
}

func Test_getPortNumber(t *testing.T) {
config.SetProfile("k3s-port-test")
if file := config.CurrentProfile().StoreFile(); !strings.HasPrefix(file, os.Getenv("COLIMA_HOME")) {
t.Fatalf("store file %s is outside COLIMA_HOME", file)
}

tests := []struct {
name string
store store.Store
guestPort string
configured int
want int
}{
{
name: "recreated VM on a kept disk reuses the disk port",
store: store.Store{DiskFormatted: true, K3sListenPort: 51234},
want: 51234,
},
{
name: "port in the VM is kept for the disk",
store: store.Store{DiskFormatted: true},
guestPort: "52345",
want: 52345,
},
{
name: "stored port is ignored without a formatted disk",
store: store.Store{K3sListenPort: 51234},
configured: 6443,
want: 6443,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := store.Set(func(s *store.Store) { *s = tt.store }); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = store.Reset() })

guest := fakeGuest{conf: map[string]string{}}
if tt.guestPort != "" {
guest.conf[listenPortKey] = tt.guestPort
}

got, err := getPortNumber(guest, tt.configured)
if err != nil {
t.Fatal(err)
}
if got != tt.want {
t.Errorf("getPortNumber() = %d, want %d", got, tt.want)
}
if guest.conf[listenPortKey] != strconv.Itoa(tt.want) {
t.Errorf("VM port = %s, want %d", guest.conf[listenPortKey], tt.want)
}
if s, _ := store.Load(); s.K3sListenPort != tt.want {
t.Errorf("stored port = %d, want %d", s.K3sListenPort, tt.want)
}
})
}
}
2 changes: 2 additions & 0 deletions store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type Store struct {
DiskRuntime string `json:"disk_runtime"`
// if ramalama has been provisioned in the VM
RamalamaProvisioned bool `json:"ramalama_provisioned"`
// the k3s listen port, kept with the runtime disk that holds the k3s state
K3sListenPort int `json:"k3s_listen_port,omitempty"`
}

func storeFile() string { return config.CurrentProfile().StoreFile() }
Expand Down
Loading