generatebundlefile/ecr_helper.go (81 lines of code) (raw):
package main
import (
"fmt"
"os/exec"
"reflect"
"strings"
"time"
ecrtypes "github.com/aws/aws-sdk-go-v2/service/ecr/types"
"github.com/pkg/errors"
api "github.com/aws/eks-anywhere-packages/api/v1alpha1"
)
// removeDuplicates removes any duplicates from Version list, useful for scenarios when
// multiple tags for an image are present, this would cause duplicates on the bundle CRD,
// so we remove the first one in this case since they are the same thing.
// EX sha1234 is tagged 1.1 and 1.2 and sha5678 is tagged 1.2 this would result in a double match of 1.2 so we run this.
func removeDuplicates(s []api.SourceVersion) []api.SourceVersion {
k := make(map[string]bool)
l := []api.SourceVersion{}
for _, i := range s {
if _, j := k[i.Name]; !j {
k[i.Name] = true
l = append(l, api.SourceVersion{Name: i.Name, Digest: i.Digest})
}
}
return l
}
// removeStringSlice removes a named string from a slice, without knowing it's index or it being ordered.
func removeStringSlice(l []string, item string) []string {
for i, other := range l {
if other == item {
return append(l[:i], l[i+1:]...)
}
}
return l
}
func deleteEmptyStringSlice(s []string) []string {
var r []string
for _, str := range s {
if str != "" {
r = append(r, str)
}
}
return r
}
// ExecCommand runs a given command, and constructs the log/output.
func ExecCommand(cmd *exec.Cmd) (string, error) {
commandOutput, err := cmd.CombinedOutput()
commandOutputStr := strings.TrimSpace(string(commandOutput))
if err != nil {
return commandOutputStr, errors.Cause(err)
}
return commandOutputStr, nil
}
// splitECRName is a helper function where some ECR repo's are formatted with "org/repo", and for aws repos it's just "repo"
func splitECRName(s string) (string, string, error) {
chartNameList := strings.Split(s, "/")
if len(chartNameList) > 1 {
return strings.Join(chartNameList[1:], "/"), chartNameList[len(chartNameList)-1], nil
}
return "", "", fmt.Errorf("parsing chartName, check the input URI is a valid ECR URI")
}
// imageTagFilter is used when filtering a list of images for a specific tag or tag substring
func ImageTagFilter(details []ecrtypes.ImageDetail, version string) []ecrtypes.ImageDetail {
var filteredDetails []ecrtypes.ImageDetail
for _, detail := range details {
for _, tag := range detail.ImageTags {
if strings.HasPrefix(tag, version) && strings.Contains(tag, "latest") {
filteredDetails = append(filteredDetails, detail)
}
}
}
return filteredDetails
}
// getLatestImageSha Iterates list of Helm Charts, to find latest pushed image and return tag/sha of the latest pushed image
func getLatestImageSha(details []ecrtypes.ImageDetail) (*api.SourceVersion, error) {
var latest ecrtypes.ImageDetail
latest.ImagePushedAt = &time.Time{}
for _, detail := range details {
if len(details) < 1 || detail.ImagePushedAt == nil || detail.ImageDigest == nil || detail.ImageTags == nil || len(detail.ImageTags) == 0 || *detail.ImageManifestMediaType != "application/vnd.oci.image.manifest.v1+json" {
continue
}
if detail.ImagePushedAt != nil && latest.ImagePushedAt.Before(*detail.ImagePushedAt) {
latest = detail
}
}
// Check if latest is equal to empty struct, and return error if that's the case.
if reflect.DeepEqual(latest, ecrtypes.ImageDetail{}) {
return nil, fmt.Errorf("error no images found")
}
return &api.SourceVersion{Name: latest.ImageTags[0], Digest: *latest.ImageDigest}, nil
}