package release import ( "fmt" "strings" "github.com/go-logr/logr" ociname "github.com/google/go-containerregistry/pkg/name" edgename "edge-infra.dev/pkg/f8n/warehouse/oci/name" "edge-infra.dev/pkg/f8n/warehouse/oci/remote" "edge-infra.dev/pkg/f8n/warehouse/packagelock" ) // A release Environment is the structure for turning a list of EdgeReleases into // a series of explicit pallets, their digests, and associated tags // // The CurrentVersion field indicates which version is the most recent and notes // which version should be tagged with the "latest" tag // Example (stage1): // // source_repository: // // name: "warehouse" // location: "us-east1" // project: "ret-edge-pltf-infra" // // current: "0.20.16" // additional: // - "0.19.11" // - "0.18.12" // // would create a packagelock.yaml file in the stage1 environment directory // that contains all of the packages and their sha256 values contained in the // above releases type Environment struct { SourceRepository Repository `yaml:"source_repository"` CurrentVersion string `yaml:"current"` AdditionalVersions []string `yaml:"additional,omitempty"` Log logr.Logger } func (e *Environment) PullReleases() ([]EdgeRelease, error) { versions := []string{e.CurrentVersion} versions = append(versions, e.AdditionalVersions...) releases := []EdgeRelease{} for _, version := range versions { pkgPath := fmt.Sprintf("%s/%s:%s", e.SourceRepository, ReleaseImageName, version) t, err := edgename.Tag( pkgPath, []ociname.Option{ ociname.WithDefaultRegistry(e.SourceRepository.Registry()), }..., ) if err != nil { return nil, err } e.Log.Info(fmt.Sprintf("pulling %s", pkgPath)) relDescr, err := remote.Get(t) if err != nil { return nil, err } release, err := ImageIndex(relDescr) if err != nil { return nil, err } releases = append(releases, release) } return releases, nil } func (e *Environment) LockReleases(releases []EdgeRelease) (packagelock.PackageLock, error) { palletVersionMap := map[string][]packagelock.Version{} for _, r := range releases { isLatest := false if r.Metadata.Version == e.CurrentVersion { isLatest = true } releaseLocks, err := lockRelease(r, isLatest) if err != nil { return packagelock.PackageLock{}, err } for _, rl := range releaseLocks { _, found := palletVersionMap[rl.Name] if !found { palletVersionMap[rl.Name] = rl.Versions } else { palletVersionMap[rl.Name] = append(palletVersionMap[rl.Name], rl.Versions...) } } } packages := packagelock.Packages{} for pName, versions := range palletVersionMap { packages = append(packages, packagelock.LockPackage{Name: pName, Versions: versions}) } return packagelock.PackageLock{Packages: packages}, nil } func lockRelease(r EdgeRelease, isLatest bool) ([]packagelock.LockPackage, error) { lockPackages := []packagelock.LockPackage{} for _, p := range r.Pallets { pHash, err := p.Digest() if err != nil { return nil, err } minor, err := semverPatchToMinor(r.Metadata.Version) if err != nil { return nil, err } tags := []string{r.Metadata.Version, minor} if isLatest { tags = append(tags, "latest") } lp := packagelock.LockPackage{ Name: p.Name(), Versions: []packagelock.Version{ { Digest: fmt.Sprintf("sha256:%s", pHash.Hex), Tags: tags, }, }, } lockPackages = append(lockPackages, lp) } return lockPackages, nil } func semverPatchToMinor(v string) (string, error) { elems := strings.Split(v, ".") if len(elems) != 3 { return "", fmt.Errorf("could not create minor version out of semver %s", v) } return fmt.Sprintf("%s.%s", elems[0], elems[1]), nil }