hack: create latest endpoint in add-version script

Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
This commit is contained in:
Paul Meyer 2022-12-05 18:35:25 +01:00 committed by Malte Poll
parent f23a2fe073
commit 4795fe9695
2 changed files with 103 additions and 18 deletions

View File

@ -53,6 +53,7 @@ func main() {
stream: flag.String("stream", "", "Stream to add the version to"), stream: flag.String("stream", "", "Stream to add the version to"),
ref: flag.String("ref", "", "Ref to add the version to"), ref: flag.String("ref", "", "Ref to add the version to"),
release: flag.Bool("release", false, "Whether the version is a release"), release: flag.Bool("release", false, "Whether the version is a release"),
latest: flag.Bool("latest", false, "Whether to set this version as the new latest version"),
dryRun: flag.Bool("dryrun", false, "Whether to run in dry-run mode (no changes are made)"), dryRun: flag.Bool("dryrun", false, "Whether to run in dry-run mode (no changes are made)"),
region: flag.String("region", defaultRegion, "AWS region"), region: flag.String("region", defaultRegion, "AWS region"),
bucket: flag.String("bucket", defaultBucket, "S3 bucket"), bucket: flag.String("bucket", defaultBucket, "S3 bucket"),
@ -79,10 +80,18 @@ func main() {
log.With(zap.Error(err)).Fatalf("Failed to ensure minor version") log.With(zap.Error(err)).Fatalf("Failed to ensure minor version")
} }
if err := ensurePatchVersion(ctx, versionManager, ver, log); err != nil { added, err := ensurePatchVersion(ctx, versionManager, ver, log)
if err != nil {
log.With(zap.Error(err)).Fatalf("Failed to ensure patch version") log.With(zap.Error(err)).Fatalf("Failed to ensure patch version")
} }
if added && *flags.latest {
if err := versionManager.addLatest(ctx, ver); err != nil {
log.With(zap.Error(err)).Fatalf("Failed to update latest version object")
}
log.Infof("Added %q as latest version.", ver)
}
log.Infof("Major to minor url: %s", ver.URL(granularityMajor)) log.Infof("Major to minor url: %s", ver.URL(granularityMajor))
log.Infof("Minor to patch url: %s", ver.URL(granularityMinor)) log.Infof("Minor to patch url: %s", ver.URL(granularityMinor))
@ -133,7 +142,7 @@ func ensureMinorVersion(ctx context.Context, versionManager *versionManager, ver
return nil return nil
} }
func ensurePatchVersion(ctx context.Context, versionManager *versionManager, ver version, log *logger.Logger) error { func ensurePatchVersion(ctx context.Context, versionManager *versionManager, ver version, log *logger.Logger) (bool, error) {
pathVerList, err := versionManager.getVersionList(ctx, ver, granularityMinor) pathVerList, err := versionManager.getVersionList(ctx, ver, granularityMinor)
if errors.Is(err, errVersionListMissing) { if errors.Is(err, errVersionListMissing) {
log.Infof("Version list for patch versions under %q does not exist. Creating new list.", ver.MajorMinor()) log.Infof("Version list for patch versions under %q does not exist. Creating new list.", ver.MajorMinor())
@ -146,22 +155,22 @@ func ensurePatchVersion(ctx context.Context, versionManager *versionManager, ver
Versions: []string{}, Versions: []string{},
} }
} else if err != nil { } else if err != nil {
return fmt.Errorf("failed to get patch versions: %w", err) return false, fmt.Errorf("failed to get patch versions: %w", err)
} }
if pathVerList.Contains(ver.MajorMinorPatch()) { if pathVerList.Contains(ver.String()) {
log.Infof("Version %q already exists in list %v.", ver.MajorMinorPatch(), pathVerList.Versions) log.Infof("Version %q already exists in list %v.", ver.String(), pathVerList.Versions)
return nil return false, nil
} }
pathVerList.Versions = append(pathVerList.Versions, ver.MajorMinorPatch()) pathVerList.Versions = append(pathVerList.Versions, ver.String())
if err := versionManager.updateVersionList(ctx, pathVerList); err != nil { if err := versionManager.updateVersionList(ctx, pathVerList); err != nil {
log.With(zap.Error(err)).Fatalf("Failed to add patch version") log.With(zap.Error(err)).Fatalf("Failed to add patch version")
} }
log.Infof("Added %q to list.", ver.MajorMinorPatch()) log.Infof("Added %q to list.", ver.String())
return nil return true, nil
} }
type version struct { type version struct {
@ -170,7 +179,7 @@ type version struct {
ref string ref string
} }
func (v *version) MajorMinorPatch() string { func (v *version) String() string {
return semver.Canonical(v.versionStr) return semver.Canonical(v.versionStr)
} }
@ -214,6 +223,7 @@ type flags struct {
stream *string stream *string
ref *string ref *string
release *bool release *bool
latest *bool
dryRun *bool dryRun *bool
region *string region *string
bucket *string bucket *string
@ -230,11 +240,15 @@ func (f *flags) validate() error {
return fmt.Errorf("branch flag must be set for non-release versions") return fmt.Errorf("branch flag must be set for non-release versions")
} }
} }
if *f.ref != "" && *f.release { if *f.ref != "" && *f.release {
return fmt.Errorf("branch flag must not be set for release versions") return fmt.Errorf("branch flag must not be set for release versions")
} }
if *f.release { if *f.release {
*f.ref = skipRefStr *f.ref = skipRefStr
} else {
*f.latest = true // always set latest for non-release versions
} }
ref := versionsapi.CanonicalRef(*f.ref) ref := versionsapi.CanonicalRef(*f.ref)
@ -276,7 +290,7 @@ func ensurePatchVersionExists(ctx context.Context, fetcher *versionsapi.Fetcher,
if err != nil { if err != nil {
return err return err
} }
if !existingPatchVersions.Contains(ver.MajorMinorPatch()) { if !existingPatchVersions.Contains(ver.String()) {
return errors.New("patch version does not exist") return errors.New("patch version does not exist")
} }
return nil return nil
@ -349,13 +363,46 @@ func (m *versionManager) updateVersionList(ctx context.Context, list *versionsap
in := &s3.PutObjectInput{ in := &s3.PutObjectInput{
Bucket: aws.String(m.bucket), Bucket: aws.String(m.bucket),
Key: aws.String(listJSONPath(list)), Key: aws.String(list.JSONPath()),
Body: bytes.NewBuffer(rawList), Body: bytes.NewBuffer(rawList),
} }
if m.dryRun { if m.dryRun {
m.log.Infof("dryRun: s3 put object {Bucket: %v, Key: %v, Body: %v", m.bucket, listJSONPath(list), string(rawList)) m.log.Infof("dryRun: s3 put object {Bucket: %v, Key: %v, Body: %v", m.bucket, list.JSONPath(), string(rawList))
return nil
}
m.dirty = true
_, err = m.uploader.Upload(ctx, in)
return err
}
func (m *versionManager) addLatest(ctx context.Context, ver version) error {
latest := &versionsapi.Latest{
Ref: ver.Ref(),
Stream: ver.Stream(),
Kind: imageKind,
Version: ver.String(),
}
if err := latest.Validate(); err != nil {
return err
}
rawLatest, err := json.Marshal(latest)
if err != nil {
return err
}
in := &s3.PutObjectInput{
Bucket: aws.String(m.bucket),
Key: aws.String(latest.JSONPath()),
Body: bytes.NewBuffer(rawLatest),
}
if m.dryRun {
m.log.Infof("dryRun: s3 put object {Bucket: %v, Key: %v, Body: %v", m.bucket, latest.JSONPath(), string(rawLatest))
return nil return nil
} }
@ -414,10 +461,6 @@ func waitForCacheUpdate(ctx context.Context, updateFetcher *versionsapi.Fetcher,
} }
} }
func listJSONPath(list *versionsapi.List) string {
return path.Join(constants.CDNAPIPrefix, "ref", list.Ref, "stream", list.Stream, "versions", list.Granularity, list.Base, imageKind+".json")
}
type granularity int type granularity int
const ( const (

View File

@ -32,7 +32,6 @@ type List struct {
// Ref is the branch name the list belongs to. // Ref is the branch name the list belongs to.
Ref string `json:"ref,omitempty"` Ref string `json:"ref,omitempty"`
// Stream is the update stream of the list. // Stream is the update stream of the list.
// Currently, only "stable" and "debug" are supported.
Stream string `json:"stream,omitempty"` Stream string `json:"stream,omitempty"`
// Granularity is the granularity of the base version of this list. // Granularity is the granularity of the base version of this list.
// It can be either "major" or "minor". // It can be either "major" or "minor".
@ -97,6 +96,49 @@ func (l *List) Validate() error {
return nil return nil
} }
// JSONPath returns the S3 JSON path for this object.
func (l *List) JSONPath() string {
return path.Join(constants.CDNAPIPrefix, "ref", l.Ref, "stream", l.Stream, "versions", l.Granularity, l.Base, l.Kind+".json")
}
// Latest is the latest version of a kind of resource.
type Latest struct {
// Ref is the branch name this latest version belongs to.
Ref string `json:"ref,omitempty"`
// Stream is stream name this latest version belongs to.
Stream string `json:"stream,omitempty"`
// Kind is the kind of resource this latest version is for.
Kind string `json:"kind,omitempty"`
// Version is the latest version for this ref, stream and kind.
Version string `json:"version,omitempty"`
}
// Validate checks if this latest version is valid.
func (l *Latest) Validate() error {
var issues []string
if !IsValidRef(l.Ref) {
issues = append(issues, "ref is empty")
}
if !IsValidStream(l.Ref, l.Stream) {
issues = append(issues, fmt.Sprintf("stream %q is not supported on ref %q", l.Stream, l.Ref))
}
if l.Kind != "image" {
issues = append(issues, fmt.Sprintf("kind %q is not supported", l.Kind))
}
if !semver.IsValid(l.Version) {
issues = append(issues, fmt.Sprintf("version %q is not a valid semantic version", l.Version))
}
if len(issues) > 0 {
return fmt.Errorf("latest version is invalid:\n%s", strings.Join(issues, "\n"))
}
return nil
}
// JSONPath returns the S3 JSON path for this object.
func (l *Latest) JSONPath() string {
return path.Join(constants.CDNAPIPrefix, "ref", l.Ref, "stream", l.Stream, "versions", "latest", l.Kind+".json")
}
// Contains returns true if the list contains the given version. // Contains returns true if the list contains the given version.
func (l *List) Contains(version string) bool { func (l *List) Contains(version string) bool {
for _, v := range l.Versions { for _, v := range l.Versions {