Skip to content

Commit be434f1

Browse files
authored
[deckhouse-cli] feat/new module mechanism draft (#234)
Signed-off-by: Pavel Okhlopkov <[email protected]>
1 parent d28caf3 commit be434f1

File tree

4 files changed

+196
-70
lines changed

4 files changed

+196
-70
lines changed

internal/mirror/modules/layout.go

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,45 @@ import (
2828
regimage "github.com/deckhouse/deckhouse-cli/pkg/registry/image"
2929
)
3030

31+
type ModulesDownloadList struct {
32+
rootURL string
33+
list map[string]*ImageDownloadList
34+
}
35+
36+
func NewModulesDownloadList(rootURL string) *ModulesDownloadList {
37+
return &ModulesDownloadList{
38+
rootURL: rootURL,
39+
list: make(map[string]*ImageDownloadList),
40+
}
41+
}
42+
43+
func (l *ModulesDownloadList) Module(moduleName string) *ImageDownloadList {
44+
return l.list[moduleName]
45+
}
46+
47+
func (l *ModulesDownloadList) FillModulesImages(modules []string) {
48+
for _, moduleName := range modules {
49+
list := NewImageDownloadList(filepath.Join(l.rootURL, moduleName))
50+
list.FillForTag("")
51+
l.list[moduleName] = list
52+
}
53+
}
54+
3155
type ImageDownloadList struct {
3256
rootURL string
3357

34-
Modules map[string]*puller.ImageMeta
35-
ModulesReleaseChannels map[string]*puller.ImageMeta
36-
ModulesExtra map[string]*puller.ImageMeta
58+
Module map[string]*puller.ImageMeta
59+
ModuleReleaseChannels map[string]*puller.ImageMeta
60+
ModuleExtra map[string]*puller.ImageMeta
3761
}
3862

3963
func NewImageDownloadList(rootURL string) *ImageDownloadList {
4064
return &ImageDownloadList{
4165
rootURL: rootURL,
4266

43-
Modules: make(map[string]*puller.ImageMeta),
44-
ModulesReleaseChannels: make(map[string]*puller.ImageMeta),
45-
ModulesExtra: make(map[string]*puller.ImageMeta),
46-
}
47-
}
48-
49-
func (l *ImageDownloadList) FillModulesImages(modules []string) {
50-
for _, module := range modules {
51-
l.Modules[filepath.Join(l.rootURL, internal.ModulesSegment, module)+":latest"] = nil
52-
l.ModulesReleaseChannels[filepath.Join(l.rootURL, internal.ModulesSegment, module, internal.ModulesReleasesSegment)+":latest"] = nil
67+
Module: make(map[string]*puller.ImageMeta),
68+
ModuleReleaseChannels: make(map[string]*puller.ImageMeta),
69+
ModuleExtra: make(map[string]*puller.ImageMeta),
5370
}
5471
}
5572

@@ -59,8 +76,41 @@ func (l *ImageDownloadList) FillForTag(tag string) {
5976
return
6077
}
6178

62-
// For modules, release channels might be handled differently
63-
// TODO: implement if needed
79+
for _, channel := range internal.GetAllDefaultReleaseChannels() {
80+
l.ModuleReleaseChannels[l.rootURL+":"+channel] = nil
81+
}
82+
}
83+
84+
type ModulesImageLayouts struct {
85+
platform v1.Platform
86+
workingDir string
87+
88+
list map[string]*ImageLayouts
89+
}
90+
91+
func NewModulesImageLayouts(rootFolder string) *ModulesImageLayouts {
92+
l := &ModulesImageLayouts{
93+
workingDir: rootFolder,
94+
platform: v1.Platform{Architecture: "amd64", OS: "linux"},
95+
list: make(map[string]*ImageLayouts),
96+
}
97+
98+
return l
99+
}
100+
101+
func (l *ModulesImageLayouts) Module(moduleName string) *ImageLayouts {
102+
return l.list[moduleName]
103+
}
104+
105+
// AsList returns a list of layout.Path's from all modules. Undefined path's are not included in the list.
106+
func (l *ModulesImageLayouts) AsList() []layout.Path {
107+
var paths []layout.Path
108+
for _, imgLayout := range l.list {
109+
if imgLayout != nil {
110+
paths = append(paths, imgLayout.AsList()...)
111+
}
112+
}
113+
return paths
64114
}
65115

66116
type ImageLayouts struct {

internal/mirror/modules/modules.go

Lines changed: 106 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ package modules
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"io"
2324
"os"
2425
"path/filepath"
2526
"time"
2627

2728
dkplog "github.com/deckhouse/deckhouse/pkg/log"
29+
"github.com/deckhouse/deckhouse/pkg/registry/client"
2830

2931
"github.com/deckhouse/deckhouse-cli/internal"
3032
"github.com/deckhouse/deckhouse-cli/internal/mirror/chunked"
@@ -33,17 +35,18 @@ import (
3335
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/bundle"
3436
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/layouts"
3537
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/util/log"
36-
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/validation"
3738
registryservice "github.com/deckhouse/deckhouse-cli/pkg/registry/service"
3839
)
3940

4041
type Service struct {
42+
workingDir string
43+
4144
// modulesService handles Deckhouse platform registry operations
4245
modulesService *registryservice.ModulesService
4346
// layout manages the OCI image layouts for different components
44-
layout *ImageLayouts
45-
// downloadList manages the list of images to be downloaded
46-
downloadList *ImageDownloadList
47+
layout *ModulesImageLayouts
48+
// modulesDownloadList manages the list of images to be downloaded
49+
modulesDownloadList *ModulesDownloadList
4750
// pullerService handles the pulling of images
4851
pullerService *puller.PullerService
4952

@@ -64,36 +67,28 @@ func NewService(
6467
) *Service {
6568
userLogger.Infof("Creating OCI Image Layouts for Modules")
6669

67-
tmpDir := filepath.Join(workingDir, "modules")
68-
69-
layout, err := createOCIImageLayoutsForModules(tmpDir)
70-
if err != nil {
71-
//TODO: handle error
72-
userLogger.Warnf("Create OCI Image Layouts: %v", err)
73-
}
74-
7570
rootURL := registryService.GetRoot()
7671

7772
return &Service{
78-
modulesService: registryService.ModuleService(),
79-
layout: layout,
80-
downloadList: NewImageDownloadList(rootURL),
81-
pullerService: puller.NewPullerService(logger, userLogger),
82-
rootURL: rootURL,
83-
logger: logger,
84-
userLogger: userLogger,
73+
workingDir: workingDir,
74+
modulesService: registryService.ModuleService(),
75+
modulesDownloadList: NewModulesDownloadList(rootURL),
76+
pullerService: puller.NewPullerService(logger, userLogger),
77+
rootURL: rootURL,
78+
logger: logger,
79+
userLogger: userLogger,
8580
}
8681
}
8782

8883
// PullModules pulls the Deckhouse modules
8984
// It validates access to the registry and pulls the module images
90-
func (svc *Service) PullModules(ctx context.Context, modules []string) error {
85+
func (svc *Service) PullModules(ctx context.Context) error {
9186
err := svc.validateModulesAccess(ctx)
9287
if err != nil {
9388
return fmt.Errorf("validate modules access: %w", err)
9489
}
9590

96-
err = svc.pullModules(ctx, modules)
91+
err = svc.pullModules(ctx)
9792
if err != nil {
9893
return fmt.Errorf("pull modules: %w", err)
9994
}
@@ -110,56 +105,96 @@ func (svc *Service) validateModulesAccess(ctx context.Context) error {
110105
ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
111106
defer cancel()
112107

113-
modulesRepo := filepath.Join(svc.rootURL, internal.ModulesSegment)
114-
validator := validation.NewRemoteRegistryAccessValidator()
115-
err := validator.ValidateListAccessForRepo(ctx, modulesRepo, []validation.Option{}...) // TODO: add options
108+
// For specific tags, check if the tag exists
109+
_, err := svc.modulesService.ListTags(ctx)
110+
if errors.Is(err, client.ErrImageNotFound) {
111+
svc.userLogger.Warnf("Skipping pull of modules: %v", err)
112+
113+
return nil
114+
}
115+
116116
if err != nil {
117-
return fmt.Errorf("modules registry is not accessible: %w", err)
117+
return fmt.Errorf("failed to check modules lists: %w", err)
118118
}
119119

120120
return nil
121121
}
122122

123-
func (svc *Service) pullModules(ctx context.Context, modules []string) error {
123+
func (svc *Service) pullModules(ctx context.Context) error {
124124
logger := svc.userLogger
125125

126-
// Fill download list with modules images
127-
svc.downloadList.FillModulesImages(modules)
128-
129-
// Pull modules images
130-
err := logger.Process("Pull Modules", func() error {
131-
config := puller.PullConfig{
132-
Name: "Modules",
133-
ImageSet: svc.downloadList.Modules,
134-
Layout: svc.layout.Modules,
135-
AllowMissingTags: true, // Allow missing module images
136-
GetterService: svc.modulesService,
137-
}
126+
tmpDir := filepath.Join(svc.workingDir, "modules")
138127

139-
return svc.pullerService.PullImages(ctx, config)
140-
})
128+
modules, err := svc.modulesService.ListTags(ctx)
141129
if err != nil {
142-
return err
130+
return fmt.Errorf("list modules: %w", err)
131+
}
132+
133+
for _, module := range modules {
134+
logger.Infof("Module found: %s", module)
135+
}
136+
137+
moduleImagesLayout, err := createOCIImageLayoutsForModules(tmpDir, modules)
138+
if err != nil {
139+
return fmt.Errorf("create OCI image layouts for modules: %w", err)
143140
}
141+
svc.layout = moduleImagesLayout
142+
143+
// Fill download list with modules images
144+
svc.modulesDownloadList.FillModulesImages(modules)
145+
146+
err = logger.Process("Pull Modules", func() error {
147+
for _, module := range modules {
148+
config := puller.PullConfig{
149+
Name: module + " release channels",
150+
ImageSet: svc.modulesDownloadList.Module(module).ModuleReleaseChannels,
151+
Layout: svc.layout.Module(module).ModulesReleaseChannels,
152+
AllowMissingTags: true,
153+
GetterService: svc.modulesService.Module(module).ReleaseChannels(),
154+
}
155+
156+
err = svc.pullerService.PullImages(ctx, config)
157+
if err != nil {
158+
return err
159+
}
160+
161+
// TODO:
162+
// we must extract module images tags from release channels before pulling module images
163+
164+
// Pull modules images
165+
config = puller.PullConfig{
166+
Name: module,
167+
ImageSet: svc.modulesDownloadList.Module(module).Module,
168+
Layout: svc.layout.Module(module).Modules,
169+
AllowMissingTags: true, // Allow missing module images
170+
GetterService: svc.modulesService.Module(module),
171+
}
172+
173+
err := svc.pullerService.PullImages(ctx, config)
174+
if err != nil {
175+
return err
176+
}
177+
178+
config = puller.PullConfig{
179+
Name: module + " extra",
180+
ImageSet: svc.modulesDownloadList.Module(module).ModuleExtra,
181+
Layout: svc.layout.Module(module).ModulesExtra,
182+
AllowMissingTags: true,
183+
GetterService: svc.modulesService.Module(module).Extra(),
184+
}
144185

145-
// Pull modules release channels
146-
err = logger.Process("Pull Modules Release Channels", func() error {
147-
config := puller.PullConfig{
148-
Name: "Modules Release Channels",
149-
ImageSet: svc.downloadList.ModulesReleaseChannels,
150-
Layout: svc.layout.ModulesReleaseChannels,
151-
AllowMissingTags: true,
152-
GetterService: svc.modulesService,
186+
err = svc.pullerService.PullImages(ctx, config)
187+
if err != nil {
188+
return err
189+
}
153190
}
154191

155-
return svc.pullerService.PullImages(ctx, config)
192+
return nil
156193
})
157194
if err != nil {
158195
return err
159196
}
160197

161-
// TODO: Pull modules extra images if needed
162-
163198
err = logger.Process("Processing modules image indexes", func() error {
164199
for _, l := range svc.layout.AsList() {
165200
err = layouts.SortIndexManifests(l)
@@ -204,6 +239,25 @@ func (svc *Service) pullModules(ctx context.Context, modules []string) error {
204239

205240
func createOCIImageLayoutsForModules(
206241
rootFolder string,
242+
modules []string,
243+
) (*ModulesImageLayouts, error) {
244+
layouts := NewModulesImageLayouts(rootFolder)
245+
246+
for _, moduleName := range modules {
247+
moduleLayouts, err := createOCIImageLayoutsForModule(
248+
filepath.Join(rootFolder, moduleName),
249+
)
250+
if err != nil {
251+
return nil, fmt.Errorf("create OCI image layouts for module %s: %w", moduleName, err)
252+
}
253+
layouts.list[moduleName] = moduleLayouts
254+
}
255+
256+
return layouts, nil
257+
}
258+
259+
func createOCIImageLayoutsForModule(
260+
rootFolder string,
207261
) (*ImageLayouts, error) {
208262
layouts := NewImageLayouts(rootFolder)
209263

internal/mirror/pull.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (svc *PullService) Pull(ctx context.Context) error {
7878
return fmt.Errorf("pull security databases: %w", err)
7979
}
8080

81-
err = svc.modulesService.PullModules(ctx, nil)
81+
err = svc.modulesService.PullModules(ctx)
8282
if err != nil {
8383
return fmt.Errorf("pull modules: %w", err)
8484
}

0 commit comments

Comments
 (0)