Skip to content

Commit

Permalink
test: mock snap channel lookup from the store correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
jnsgruk committed Jan 6, 2025
1 parent b42f6bb commit b2c2180
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 24 deletions.
29 changes: 8 additions & 21 deletions internal/providers/microk8s.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package providers

import (
"errors"
"fmt"
"log/slog"
"os"
"path"
"slices"
"strings"
"time"

"github.com/jnsgruk/concierge/internal/config"
"github.com/jnsgruk/concierge/internal/packages"
"github.com/jnsgruk/concierge/internal/system"
snapdClient "github.com/snapcore/snapd/client"
)

// Default channel from which MicroK8s is installed when the latest strict
Expand All @@ -27,7 +23,7 @@ func NewMicroK8s(r system.Worker, config *config.Config) *MicroK8s {
if config.Overrides.MicroK8sChannel != "" {
channel = config.Overrides.MicroK8sChannel
} else if config.Providers.MicroK8s.Channel == "" {
channel = computeDefaultChannel()
channel = computeDefaultChannel(r)
} else {
channel = config.Providers.MicroK8s.Channel
}
Expand Down Expand Up @@ -206,29 +202,20 @@ func (m *MicroK8s) setupKubectl() error {
return m.system.WriteHomeDirFile(path.Join(".kube", "config"), result)
}

// Try to compute the "correct" default channel. Concerige prefers that the 'strict'
// Try to compute the "correct" default channel. Concierge prefers that the 'strict'
// variants are installed, so we filter available channels and sort descending by
// version. If the list cannot be retrieved, default to a know good version.
func computeDefaultChannel() string {
// If the snapd socket doesn't exist on the system, return a default value
if _, err := os.Stat("/run/snapd.socket"); errors.Is(err, os.ErrNotExist) {
return defaultMicroK8sChannel
}

snap, _, err := snapdClient.New(nil).FindOne("microk8s")
func computeDefaultChannel(s system.Worker) string {
channels, err := s.SnapChannels("microk8s")
if err != nil {
return defaultMicroK8sChannel
}

keys := []string{}
for k := range snap.Channels {
if strings.Contains(k, "strict") && strings.Contains(k, "stable") {
keys = append(keys, k)
for _, c := range channels {
if strings.Contains(c, "strict") && strings.Contains(c, "stable") {
return c
}
}

slices.Sort(keys)
slices.Reverse(keys)

return keys[0]
return defaultMicroK8sChannel
}
2 changes: 2 additions & 0 deletions internal/system/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ type Worker interface {
// SnapInfo returns information about a given snap, looking up details in the snap
// store using the snapd client API where necessary.
SnapInfo(snap string, channel string) (*SnapInfo, error)
// SnapChannels returns the list of channels available for a given snap.
SnapChannels(snap string) ([]string, error)
}
22 changes: 19 additions & 3 deletions internal/system/mock_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ type MockSystem struct {
CreatedDirectories []string
Deleted []string

mockFiles map[string][]byte
mockReturns map[string]MockCommandReturn
mockSnapInfo map[string]*SnapInfo
mockFiles map[string][]byte
mockReturns map[string]MockCommandReturn
mockSnapInfo map[string]*SnapInfo
mockSnapChannels map[string][]string
}

// MockCommandReturn sets a static return value representing command combined output,
Expand All @@ -55,6 +56,11 @@ func (r *MockSystem) MockSnapStoreLookup(name, channel string, classic, installe
return &Snap{Name: name, Channel: channel}
}

// MockSnapChannels mocks the set of available channels for a snap in the store.
func (r *MockSystem) MockSnapChannels(snap string, channels []string) {
r.mockSnapChannels[snap] = channels
}

// User returns the user the system executes commands on behalf of.
func (r *MockSystem) User() *user.User {
return &user.User{
Expand Down Expand Up @@ -159,3 +165,13 @@ func (r *MockSystem) SnapInfo(snap string, channel string) (*SnapInfo, error) {
Classic: false,
}, nil
}

// SnapChannels returns the list of channels available for a given snap.
func (r *MockSystem) SnapChannels(snap string) ([]string, error) {
val, ok := r.mockSnapChannels[snap]
if ok {
return val, nil
}

return nil, fmt.Errorf("channels for snap '%s' not found", snap)
}
29 changes: 29 additions & 0 deletions internal/system/snap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package system

import (
"context"
"errors"
"fmt"
"log/slog"
"os"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -54,6 +57,32 @@ func (s *System) SnapInfo(snap string, channel string) (*SnapInfo, error) {
return &SnapInfo{Installed: installed, Classic: classic}, nil
}

// SnapChannels returns the list of channels available for a given snap.
func (s *System) SnapChannels(snap string) ([]string, error) {
// Fetch the channels from
if _, err := os.Stat("/run/snapd.socket"); errors.Is(err, os.ErrNotExist) {
return nil, err
}

storeSnap, _, err := s.snapd.FindOne("microk8s")
if err != nil {
return nil, err
}

channels := make([]string, len(storeSnap.Channels))

i := 0
for k := range storeSnap.Channels {
channels[i] = k
i++
}

slices.Sort(channels)
slices.Reverse(channels)

return channels, nil
}

// snapInstalled is a helper that reports if the snap is currently Installed.
func (s *System) snapInstalled(name string) bool {
snap, err := s.withRetry(func(ctx context.Context) (*client.Snap, error) {
Expand Down

0 comments on commit b2c2180

Please sign in to comment.