Skip to content
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
14 changes: 13 additions & 1 deletion internal/mirror/modules/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,11 @@ func (svc *Service) discoverChannelVersions(ctx context.Context, moduleName stri
downloadList.ModuleReleaseChannels[svc.rootURL+"/modules/"+moduleName+"/release:"+channel] = nil
}

// Add LTS channel if it exists
if err := svc.modulesService.Module(moduleName).ReleaseChannels().CheckImageExists(ctx, internal.LTSChannel); err == nil {
downloadList.ModuleReleaseChannels[svc.rootURL+"/modules/"+moduleName+"/release:"+internal.LTSChannel] = nil
}

if !svc.options.DryRun {
config := puller.PullConfig{
Name: moduleName + " release channels",
Expand Down Expand Up @@ -589,7 +594,14 @@ func (svc *Service) findVexImage(ctx context.Context, moduleName string, imageRe
func (svc *Service) extractVersionsFromReleaseChannels(ctx context.Context, moduleName string) []string {
versions := make([]string, 0)

for _, channel := range internal.GetAllDefaultReleaseChannels() {
channels := internal.GetAllDefaultReleaseChannels()

// Add LTS channel if it exists
if err := svc.modulesService.Module(moduleName).ReleaseChannels().CheckImageExists(ctx, internal.LTSChannel); err == nil {
channels = append(channels, internal.LTSChannel)
}

for _, channel := range channels {
img, err := svc.modulesService.Module(moduleName).ReleaseChannels().GetImage(ctx, channel)
if err != nil {
svc.logger.Debug(fmt.Sprintf("Failed to get release channel image for %s/%s: %v", moduleName, channel, err))
Expand Down
47 changes: 46 additions & 1 deletion internal/mirror/modules/pull_modules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ import (
"sync/atomic"
"testing"

golayout "github.com/google/go-containerregistry/pkg/v1/layout"
v1 "github.com/google/go-containerregistry/pkg/v1"
golayout "github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

dkplog "github.com/deckhouse/deckhouse/pkg/log"
dkpreg "github.com/deckhouse/deckhouse/pkg/registry"
upfake "github.com/deckhouse/deckhouse/pkg/registry/fake"

"github.com/deckhouse/deckhouse-cli/internal"
"github.com/deckhouse/deckhouse-cli/pkg"
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/util/log"
pkgclient "github.com/deckhouse/deckhouse-cli/pkg/registry/client"
Expand Down Expand Up @@ -296,6 +297,7 @@ func addModule(reg *upfake.Registry, name, channelVer string, versions []string)
reg.MustAddImage("modules", name, versionImage(channelVer))
for _, v := range versions {
reg.MustAddImage("modules/"+name, v, versionImage(v))
reg.MustAddImage("modules/"+name+"/release", v, versionImage(v))
}
for _, ch := range []string{"alpha", "beta", "early-access", "stable", "rock-solid"} {
reg.MustAddImage("modules/"+name+"/release", ch, versionImage(channelVer))
Expand All @@ -309,6 +311,11 @@ func singleModuleRegistry(name, channelVer string, versions []string) *upfake.Re
return reg
}

// addLTSReleaseChannel adds the optional LTS release channel (CSE editions).
func addLTSReleaseChannel(reg *upfake.Registry, name, channelVer string) {
reg.MustAddImage("modules/"+name+"/release", internal.LTSChannel, versionImage(channelVer))
}

// versionImage builds a v1.Image carrying only version.json. Missing
// images_digests.json / extra_images.json is tolerated downstream.
func versionImage(version string) v1.Image {
Expand All @@ -328,6 +335,10 @@ func taggedModuleRef(moduleName, version string) string {
return testHost + "/modules/" + moduleName + ":" + version
}

func moduleReleaseChannelRef(moduleName, channel string) string {
return testHost + "/modules/" + moduleName + "/release:" + channel
}

func taggedModuleRefs(moduleName string, versions []string) []string {
refs := make([]string, 0, len(versions))
for _, v := range versions {
Expand Down Expand Up @@ -497,3 +508,37 @@ func TestImageLayouts_HasImages_WithImage(t *testing.T) {
assert.True(t, layouts.HasImages(),
"HasImages must return true after at least one image is appended")
}

// =============================================================================
// Tests: LTS release channel
// =============================================================================

// CSE editions expose an optional LTS release channel in addition to the five
// default channels. discoverChannelVersions must detect it and include it in
// the pull without failing.
func TestPullModules_LTSChannel(t *testing.T) {
reg := singleModuleRegistry(testModuleName, channelVersion, defaultRegistryVersions)
addLTSReleaseChannel(reg, testModuleName, channelVersion)

bundleDir := t.TempDir()
svc := newService(t, pkgclient.Adapt(upfake.NewClient(reg)), nil)
svc.options.BundleDir = bundleDir

require.NoError(t, svc.PullModules(context.Background()))

moduleDL := svc.modulesDownloadList.Module(testModuleName)
require.NotNil(t, moduleDL, "modulesDownloadList must have an entry for module %q", testModuleName)

ltsRef := moduleReleaseChannelRef(testModuleName, internal.LTSChannel)
_, ok := moduleDL.ModuleReleaseChannels[ltsRef]
assert.True(t, ok,
"ModuleReleaseChannels should contain LTS ref %q; actual keys: %v",
ltsRef, moduleDL.ModuleReleaseChannels)

assert.Contains(t, pulledModuleVersionRefs(t, svc, testModuleName), taggedModuleRef(testModuleName, channelVersion),
"LTS channel must contribute %s to the pulled module versions", channelVersion)

entries, err := os.ReadDir(bundleDir)
require.NoError(t, err)
require.NotEmpty(t, entries, "bundle dir must contain a tar when LTS channel pull succeeds")
}
Loading