Skip to content

Commit e94affd

Browse files
authored
[deckhouse-cli] add download list (#219)
Signed-off-by: Pavel Okhlopkov <[email protected]>
1 parent 3d11cf7 commit e94affd

File tree

4 files changed

+148
-136
lines changed

4 files changed

+148
-136
lines changed

internal/mirror/platform/layout.go

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,72 +13,80 @@ import (
1313
regimage "github.com/deckhouse/deckhouse-cli/pkg/registry/image"
1414
)
1515

16-
type ImageDownloadRequest struct {
17-
DeckhouseImages map[string]*puller.ImageMeta
18-
InstallImages map[string]*puller.ImageMeta
19-
InstallStandaloneImages map[string]*puller.ImageMeta
20-
ReleaseChannelImages map[string]*puller.ImageMeta
16+
type ImageDownloadList struct {
17+
rootURL string
18+
19+
Deckhouse map[string]*puller.ImageMeta
20+
DeckhouseExtra map[string]*puller.ImageMeta
21+
DeckhouseInstall map[string]*puller.ImageMeta
22+
DeckhouseInstallStandalone map[string]*puller.ImageMeta
23+
DeckhouseReleaseChannel map[string]*puller.ImageMeta
2124
}
2225

23-
type ImageLayouts struct {
24-
platform v1.Platform
25-
workingDir string
26-
rootURL string
27-
28-
Deckhouse *regimage.ImageLayout
29-
DeckhouseImages map[string]*puller.ImageMeta
30-
31-
DeckhouseInstall *regimage.ImageLayout
32-
InstallImages map[string]*puller.ImageMeta
33-
34-
DeckhouseInstallStandalone *regimage.ImageLayout
35-
InstallStandaloneImages map[string]*puller.ImageMeta
36-
37-
DeckhouseReleaseChannel *regimage.ImageLayout
38-
ReleaseChannelImages map[string]*puller.ImageMeta
39-
}
26+
func NewImageDownloadList(rootURL string) *ImageDownloadList {
27+
return &ImageDownloadList{
28+
rootURL: rootURL,
4029

41-
func NewImageLayouts(rootFolder, rootURL string) *ImageLayouts {
42-
l := &ImageLayouts{
43-
workingDir: rootFolder,
44-
rootURL: rootURL,
45-
platform: v1.Platform{Architecture: "amd64", OS: "linux"},
46-
47-
DeckhouseImages: map[string]*puller.ImageMeta{},
48-
InstallImages: map[string]*puller.ImageMeta{},
49-
InstallStandaloneImages: map[string]*puller.ImageMeta{},
50-
ReleaseChannelImages: map[string]*puller.ImageMeta{},
30+
Deckhouse: make(map[string]*puller.ImageMeta),
31+
DeckhouseExtra: make(map[string]*puller.ImageMeta),
32+
DeckhouseInstall: make(map[string]*puller.ImageMeta),
33+
DeckhouseInstallStandalone: make(map[string]*puller.ImageMeta),
34+
DeckhouseReleaseChannel: make(map[string]*puller.ImageMeta),
5135
}
52-
53-
return l
5436
}
5537

56-
func (l *ImageLayouts) FillDeckhouseImages(deckhouseVersions []string) {
38+
func (l *ImageDownloadList) FillDeckhouseImages(deckhouseVersions []string) {
5739
for _, version := range deckhouseVersions {
58-
l.DeckhouseImages[l.rootURL+":"+version] = nil
59-
l.InstallImages[path.Join(l.rootURL, internal.InstallSegment)+":"+version] = nil
60-
l.InstallStandaloneImages[path.Join(l.rootURL, internal.InstallStandaloneSegment)+":"+version] = nil
40+
l.Deckhouse[l.rootURL+":"+version] = nil
41+
l.DeckhouseInstall[path.Join(l.rootURL, internal.InstallSegment)+":"+version] = nil
42+
l.DeckhouseInstallStandalone[path.Join(l.rootURL, internal.InstallStandaloneSegment)+":"+version] = nil
6143
}
6244
}
6345

64-
func (l *ImageLayouts) FillForTag(tag string) {
46+
func (l *ImageDownloadList) FillForTag(tag string) {
6547
// If we are to pull only the specific requested version, we should not pull any release channels at all.
6648
if tag != "" {
6749
return
6850
}
6951

7052
for _, channel := range internal.GetAllDefaultReleaseChannels() {
71-
l.DeckhouseImages[l.rootURL+":"+channel] = nil
72-
l.InstallImages[path.Join(l.rootURL, internal.InstallSegment)+":"+channel] = nil
73-
l.InstallStandaloneImages[path.Join(l.rootURL, internal.InstallStandaloneSegment)+":"+channel] = nil
53+
l.Deckhouse[l.rootURL+":"+channel] = nil
54+
l.DeckhouseInstall[path.Join(l.rootURL, internal.InstallSegment)+":"+channel] = nil
55+
l.DeckhouseInstallStandalone[path.Join(l.rootURL, internal.InstallStandaloneSegment)+":"+channel] = nil
7456
key := path.Join(l.rootURL, internal.ReleaseChannelSegment) + ":" + channel
75-
if _, exists := l.ReleaseChannelImages[key]; !exists {
76-
l.ReleaseChannelImages[key] = nil
57+
if _, exists := l.DeckhouseReleaseChannel[key]; !exists {
58+
l.DeckhouseReleaseChannel[key] = nil
7759
}
7860
}
7961
}
8062

81-
func (l *ImageLayouts) setLayoutByMirrorType(mirrorType internal.MirrorType, layout *regimage.ImageLayout) {
63+
type ImageLayouts struct {
64+
platform v1.Platform
65+
workingDir string
66+
67+
Deckhouse *regimage.ImageLayout
68+
DeckhouseInstall *regimage.ImageLayout
69+
DeckhouseInstallStandalone *regimage.ImageLayout
70+
DeckhouseReleaseChannel *regimage.ImageLayout
71+
}
72+
73+
func NewImageLayouts(rootFolder string) *ImageLayouts {
74+
l := &ImageLayouts{
75+
workingDir: rootFolder,
76+
platform: v1.Platform{Architecture: "amd64", OS: "linux"},
77+
}
78+
79+
return l
80+
}
81+
82+
func (l *ImageLayouts) setLayoutByMirrorType(rootFolder string, mirrorType internal.MirrorType) error {
83+
layoutPath := path.Join(rootFolder, internal.InstallSegmentByMirrorType(mirrorType))
84+
85+
layout, err := regimage.NewImageLayout(layoutPath)
86+
if err != nil {
87+
return fmt.Errorf("failed to create image layout: %w", err)
88+
}
89+
8290
switch mirrorType {
8391
case internal.MirrorTypeDeckhouse:
8492
l.Deckhouse = layout
@@ -89,8 +97,10 @@ func (l *ImageLayouts) setLayoutByMirrorType(mirrorType internal.MirrorType, lay
8997
case internal.MirrorTypeDeckhouseInstallStandalone:
9098
l.DeckhouseInstallStandalone = layout
9199
default:
92-
panic(fmt.Sprintf("wrong mirror type in platform image layout: %v", mirrorType))
100+
return fmt.Errorf("wrong mirror type in platform image layout: %v", mirrorType)
93101
}
102+
103+
return nil
94104
}
95105

96106
// AsList returns a list of layout.Path's in it. Undefined path's are not included in the list.

internal/mirror/platform/platform.go

Lines changed: 26 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"time"
1616

1717
"github.com/Masterminds/semver/v3"
18-
"github.com/google/go-containerregistry/pkg/v1/layout"
1918
"github.com/samber/lo"
2019

2120
dkplog "github.com/deckhouse/deckhouse/pkg/log"
@@ -28,8 +27,8 @@ import (
2827
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/bundle"
2928
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/layouts"
3029
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/util/log"
30+
"github.com/deckhouse/deckhouse-cli/pkg/registry/client"
3131
regclient "github.com/deckhouse/deckhouse-cli/pkg/registry/client"
32-
regimage "github.com/deckhouse/deckhouse-cli/pkg/registry/image"
3332
registryservice "github.com/deckhouse/deckhouse-cli/pkg/registry/service"
3433
)
3534

@@ -38,6 +37,8 @@ type Service struct {
3837
deckhouseService *registryservice.DeckhouseService
3938
// layout manages the OCI image layouts for different components
4039
layout *ImageLayouts
40+
// downloadList manages the list of images to be downloaded
41+
downloadList *ImageDownloadList
4142
// pullerService handles the pulling of images
4243
pullerService *puller.PullerService
4344

@@ -68,7 +69,7 @@ func NewService(
6869

6970
tmpDir := filepath.Join(workingDir, "platform")
7071

71-
layout, err := createOCIImageLayoutsForDeckhouse(tmpDir, deckhouseService.GetRoot())
72+
layout, err := createOCIImageLayoutsForPlatform(tmpDir)
7273
if err != nil {
7374
//TODO: handle error
7475
userLogger.Warnf("Create OCI Image Layouts: %v", err)
@@ -77,6 +78,7 @@ func NewService(
7778
return &Service{
7879
deckhouseService: deckhouseService,
7980
layout: layout,
81+
downloadList: NewImageDownloadList(deckhouseService.GetRoot()),
8082
pullerService: puller.NewPullerService(deckhouseService, logger, userLogger),
8183
sinceVersion: sinceVersion,
8284
targetTag: targetTag,
@@ -100,8 +102,8 @@ func (svc *Service) PullPlatform(ctx context.Context) error {
100102
return fmt.Errorf("find tags to mirror: %w", err)
101103
}
102104

103-
svc.layout.FillDeckhouseImages(tagsToMirror)
104-
svc.layout.FillForTag(svc.targetTag)
105+
svc.downloadList.FillDeckhouseImages(tagsToMirror)
106+
svc.downloadList.FillForTag(svc.targetTag)
105107

106108
err = svc.pullDeckhousePlatform(ctx, tagsToMirror)
107109
if err != nil {
@@ -189,7 +191,11 @@ func (svc *Service) versionsToMirrorFunc(ctx context.Context) ([]semver.Version,
189191
version, err := svc.getReleaseChannelVersionFromRegistry(ctx, channel)
190192
if err != nil {
191193
if channel == internal.LTSChannel {
192-
svc.userLogger.Warnf("Skipping LTS channel: %v", err)
194+
if !errors.Is(err, client.ErrImageNotFound) {
195+
svc.userLogger.Warnf("Skipping LTS channel: %v", err)
196+
} else {
197+
svc.userLogger.Warnf("Skipping LTS channel, because it's not required")
198+
}
193199

194200
continue
195201
}
@@ -277,7 +283,7 @@ func (svc *Service) getReleaseChannelVersionFromRegistry(ctx context.Context, re
277283
return nil, fmt.Errorf("append %s release channel image to layout: %w", releaseChannel, err)
278284
}
279285

280-
svc.layout.ReleaseChannelImages[imageMeta.GetTagReference()] = puller.NewImageMeta(meta.Version, imageMeta.GetTagReference(), &digest)
286+
svc.downloadList.DeckhouseReleaseChannel[imageMeta.GetTagReference()] = puller.NewImageMeta(meta.Version, imageMeta.GetTagReference(), &digest)
281287

282288
return ver, nil
283289
}
@@ -318,7 +324,7 @@ func (svc *Service) pullDeckhousePlatform(ctx context.Context, tagsToMirror []st
318324
logger.Infof("Searching for Deckhouse built-in modules digests")
319325

320326
var uniqueImages = make(map[string]string, 0)
321-
for _, imageMeta := range svc.layout.InstallImages {
327+
for _, imageMeta := range svc.downloadList.DeckhouseInstall {
322328
if _, ok := uniqueImages[imageMeta.DigestReference]; ok {
323329
continue
324330
}
@@ -328,15 +334,17 @@ func (svc *Service) pullDeckhousePlatform(ctx context.Context, tagsToMirror []st
328334

329335
var prevDigests = make(map[string]struct{}, 0)
330336
for _, tag := range uniqueImages {
337+
svc.userLogger.Infof("Extracting images digests from Deckhouse installer %s", tag)
338+
331339
digests, err := svc.ExtractImageDigestsFromDeckhouseInstallerNew(tag, prevDigests)
332340
if err != nil {
333341
return fmt.Errorf("extract images digests: %w", err)
334342
}
335343

336-
maps.Copy(svc.layout.DeckhouseImages, digests)
344+
maps.Copy(svc.downloadList.Deckhouse, digests)
337345
}
338346

339-
logger.Infof("Found %d images", len(svc.layout.DeckhouseImages))
347+
logger.Infof("Found %d images", len(svc.downloadList.Deckhouse))
340348

341349
if err = logger.Process("Pull Deckhouse images", func() error {
342350
if err := svc.pullDeckhouseImages(ctx); err != nil {
@@ -419,7 +427,7 @@ func (svc *Service) pullDeckhousePlatform(ctx context.Context, tagsToMirror []st
419427
func (svc *Service) pullDeckhouseReleaseChannels(ctx context.Context) error {
420428
config := puller.PullConfig{
421429
Name: "Deckhouse release channels information",
422-
ImageSet: svc.layout.ReleaseChannelImages,
430+
ImageSet: svc.downloadList.DeckhouseReleaseChannel,
423431
Layout: svc.layout.DeckhouseReleaseChannel,
424432
AllowMissingTags: svc.targetTag != "",
425433
GetterService: svc.deckhouseService.ReleaseChannels(),
@@ -431,7 +439,7 @@ func (svc *Service) pullDeckhouseReleaseChannels(ctx context.Context) error {
431439
func (svc *Service) pullInstallers(ctx context.Context) error {
432440
config := puller.PullConfig{
433441
Name: "installers",
434-
ImageSet: svc.layout.InstallImages,
442+
ImageSet: svc.downloadList.DeckhouseInstall,
435443
Layout: svc.layout.DeckhouseInstall,
436444
AllowMissingTags: true, // Allow missing installer images
437445
GetterService: svc.deckhouseService.Installer(),
@@ -443,7 +451,7 @@ func (svc *Service) pullInstallers(ctx context.Context) error {
443451
func (svc *Service) pullStandaloneInstallers(ctx context.Context) error {
444452
config := puller.PullConfig{
445453
Name: "standalone installers",
446-
ImageSet: svc.layout.InstallStandaloneImages,
454+
ImageSet: svc.downloadList.DeckhouseInstallStandalone,
447455
Layout: svc.layout.DeckhouseInstallStandalone,
448456
AllowMissingTags: true,
449457
GetterService: svc.deckhouseService.StandaloneInstaller(),
@@ -455,7 +463,7 @@ func (svc *Service) pullStandaloneInstallers(ctx context.Context) error {
455463
func (svc *Service) pullDeckhouseImages(ctx context.Context) error {
456464
config := puller.PullConfig{
457465
Name: "Deckhouse releases",
458-
ImageSet: svc.layout.DeckhouseImages,
466+
ImageSet: svc.downloadList.Deckhouse,
459467
Layout: svc.layout.Deckhouse,
460468
AllowMissingTags: false,
461469
GetterService: svc.deckhouseService,
@@ -613,14 +621,6 @@ func (svc *Service) FindVexImage(
613621
splitIndex := strings.LastIndex(vexImageName, ":")
614622
tag := vexImageName[splitIndex+1:]
615623

616-
// imageSegmentsRaw := strings.TrimPrefix(imagePath, svc.deckhouseService.GetRoot())
617-
// imageSegments := strings.Split(imageSegmentsRaw, "/")
618-
619-
// for i, segment := range imageSegments {
620-
// client = client.WithSegment(segment)
621-
// logger.Debugf("Segment %d: %s", i, segment)
622-
// }
623-
624624
err := svc.deckhouseService.CheckImageExists(context.TODO(), tag)
625625
if errors.Is(err, regclient.ErrImageNotFound) {
626626
// Image not found, which is expected for non-vulnerable images
@@ -703,21 +703,10 @@ func deduplicateVersions(versions []*semver.Version) []semver.Version {
703703
return vers
704704
}
705705

706-
func createOCIImageLayoutsForDeckhouse(
706+
func createOCIImageLayoutsForPlatform(
707707
rootFolder string,
708-
rootURL string,
709708
) (*ImageLayouts, error) {
710-
var err error
711-
712-
layouts := NewImageLayouts(rootFolder, rootURL)
713-
714-
fsPath := rootFolder
715-
layoutPtr, err := createEmptyImageLayout(fsPath)
716-
if err != nil {
717-
return nil, fmt.Errorf("create OCI Image Layout at %s: %w", fsPath, err)
718-
}
719-
720-
layouts.Deckhouse = regimage.NewImageLayout(layoutPtr)
709+
layouts := NewImageLayouts(rootFolder)
721710

722711
mirrorTypes := []internal.MirrorType{
723712
internal.MirrorTypeDeckhouse,
@@ -727,62 +716,11 @@ func createOCIImageLayoutsForDeckhouse(
727716
}
728717

729718
for _, mtype := range mirrorTypes {
730-
fsPath = filepath.Join(rootFolder, internal.InstallSegmentByMirrorType(mtype))
731-
layoutPtr, err = createEmptyImageLayout(fsPath)
719+
err := layouts.setLayoutByMirrorType(rootFolder, mtype)
732720
if err != nil {
733-
return nil, fmt.Errorf("create OCI Image Layout at %s: %w", fsPath, err)
721+
return nil, fmt.Errorf("set layout by mirror type %v: %w", mtype, err)
734722
}
735-
736-
layouts.setLayoutByMirrorType(mtype, regimage.NewImageLayout(layoutPtr))
737723
}
738724

739725
return layouts, nil
740726
}
741-
742-
func createEmptyImageLayout(path string) (layout.Path, error) {
743-
layoutFilePath := filepath.Join(path, "oci-layout")
744-
indexFilePath := filepath.Join(path, "index.json")
745-
blobsPath := filepath.Join(path, "blobs")
746-
747-
if err := os.MkdirAll(blobsPath, 0o755); err != nil {
748-
return "", fmt.Errorf("mkdir for blobs: %w", err)
749-
}
750-
751-
layoutContents := ociLayout{ImageLayoutVersion: "1.0.0"}
752-
indexContents := indexSchema{
753-
SchemaVersion: 2,
754-
MediaType: "application/vnd.oci.image.index.v1+json",
755-
}
756-
757-
rawJSON, err := json.MarshalIndent(indexContents, "", " ")
758-
if err != nil {
759-
return "", fmt.Errorf("create index.json: %w", err)
760-
}
761-
if err = os.WriteFile(indexFilePath, rawJSON, 0o644); err != nil {
762-
return "", fmt.Errorf("create index.json: %w", err)
763-
}
764-
765-
rawJSON, err = json.MarshalIndent(layoutContents, "", " ")
766-
if err != nil {
767-
return "", fmt.Errorf("create oci-layout: %w", err)
768-
}
769-
if err = os.WriteFile(layoutFilePath, rawJSON, 0o644); err != nil {
770-
return "", fmt.Errorf("create oci-layout: %w", err)
771-
}
772-
773-
return layout.Path(path), nil
774-
}
775-
776-
type indexSchema struct {
777-
SchemaVersion int `json:"schemaVersion"`
778-
MediaType string `json:"mediaType"`
779-
Manifests []struct {
780-
MediaType string `json:"mediaType,omitempty"`
781-
Size int `json:"size,omitempty"`
782-
Digest string `json:"digest,omitempty"`
783-
} `json:"manifests"`
784-
}
785-
786-
type ociLayout struct {
787-
ImageLayoutVersion string `json:"imageLayoutVersion"`
788-
}

pkg/libmirror/layouts/layouts.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ func CreateOCIImageLayoutsForDeckhouse(
129129
&layouts.InstallStandalone: filepath.Join(rootFolder, "install-standalone"),
130130
&layouts.ReleaseChannel: filepath.Join(rootFolder, "release-channel"),
131131
}
132+
132133
for layoutPtr, fsPath := range fsPaths {
133134
*layoutPtr, err = CreateEmptyImageLayout(fsPath)
134135
if err != nil {

0 commit comments

Comments
 (0)