[autoroll] Filter rollers whose required GCS artifacts don't exist
Change-Id: I08c3bf2a441aa2019f8db686d64224a85d602416
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/633496
Reviewed-by: Ravi Mistry <rmistry@google.com>
Commit-Queue: Eric Boren <borenet@google.com>
diff --git a/autoroll/go/autoroll-config-converter/BUILD.bazel b/autoroll/go/autoroll-config-converter/BUILD.bazel
index 11d6a58..e2ac3ed 100644
--- a/autoroll/go/autoroll-config-converter/BUILD.bazel
+++ b/autoroll/go/autoroll-config-converter/BUILD.bazel
@@ -16,6 +16,7 @@
"//cd/go/cd",
"//go/chrome_branch",
"//go/exec",
+ "//go/gcs/gcsclient",
"//go/git",
"//go/gitauth",
"//go/gitiles",
@@ -25,6 +26,8 @@
"//kube/go/kube_conf_gen_lib",
"//task_driver/go/lib/git_steps",
"//task_driver/go/td",
+ "@com_google_cloud_go_storage//:storage",
+ "@org_golang_google_api//iterator",
"@org_golang_google_api//oauth2/v2:oauth2",
"@org_golang_google_api//option",
"@org_golang_google_protobuf//encoding/protojson",
diff --git a/autoroll/go/autoroll-config-converter/main.go b/autoroll/go/autoroll-config-converter/main.go
index 7826f4e..3f4bf57 100644
--- a/autoroll/go/autoroll-config-converter/main.go
+++ b/autoroll/go/autoroll-config-converter/main.go
@@ -10,18 +10,23 @@
"fmt"
"io/fs"
"io/ioutil"
+ "net/http"
"os"
+ "path"
"path/filepath"
+ "regexp"
"sort"
"strings"
"sync"
"text/template"
+ "cloud.google.com/go/storage"
"go.skia.org/infra/autoroll/go/config"
"go.skia.org/infra/autoroll/go/config_vars"
"go.skia.org/infra/cd/go/cd"
"go.skia.org/infra/go/chrome_branch"
"go.skia.org/infra/go/exec"
+ "go.skia.org/infra/go/gcs/gcsclient"
"go.skia.org/infra/go/git"
"go.skia.org/infra/go/gitauth"
"go.skia.org/infra/go/gitiles"
@@ -32,6 +37,7 @@
"go.skia.org/infra/task_driver/go/lib/git_steps"
"go.skia.org/infra/task_driver/go/td"
"golang.org/x/sync/errgroup"
+ "google.golang.org/api/iterator"
"google.golang.org/api/oauth2/v2"
"google.golang.org/api/option"
"google.golang.org/protobuf/encoding/protojson"
@@ -208,7 +214,7 @@
if err != nil {
return skerr.Wrapf(err, "failed to read template file %s", tmplPath)
}
- generatedConfigs, err := processTemplate(ctx, path, string(tmplContents), vars)
+ generatedConfigs, err := processTemplate(ctx, client, path, string(tmplContents), vars)
if err != nil {
return skerr.Wrapf(err, "failed to process template file %s", path)
}
@@ -379,7 +385,7 @@
}
// processTemplate converts a single template into at least one config.
-func processTemplate(ctx context.Context, srcPath, tmplContents string, vars *TemplateVars) (map[string][]byte, error) {
+func processTemplate(ctx context.Context, client *http.Client, srcPath, tmplContents string, vars *TemplateVars) (map[string][]byte, error) {
// Read and execute the template.
tmpl, err := template.New(filepath.Base(srcPath)).Funcs(funcMap).Parse(tmplContents)
if err != nil {
@@ -397,6 +403,20 @@
}
sklog.Infof(" Found %d configs in %s", len(configs.Config), srcPath)
+ // Filter out any rollers whose required GCS artifacts do not exist.
+ filteredConfigs := make([]*config.Config, 0, len(configs.Config))
+ for _, cfg := range configs.Config {
+ missing, err := gcsArtifactIsMissing(ctx, client, cfg)
+ if err != nil {
+ return nil, skerr.Wrapf(err, "failed to check whether GCS artifact exists for %s (from %s)", cfg.RollerName, srcPath)
+ }
+ if missing {
+ sklog.Warningf("Skipping roller %s; required GCS artifact does not exist.", cfg.RollerName)
+ } else {
+ filteredConfigs = append(filteredConfigs, cfg)
+ }
+ }
+
// Split off the template file name and the "templates" directory name.
srcPathSplit := []string{}
for _, elem := range strings.Split(srcPath, string(filepath.Separator)) {
@@ -406,8 +426,8 @@
}
srcRelPath := filepath.Join(srcPathSplit...)
- changes := make(map[string][]byte, len(configs.Config))
- for _, cfg := range configs.Config {
+ changes := make(map[string][]byte, len(filteredConfigs))
+ for _, cfg := range filteredConfigs {
encBytes, err := protoMarshalOptions.Marshal(cfg)
if err != nil {
return nil, skerr.Wrapf(err, "failed to encode config from %q", srcPath)
@@ -417,6 +437,42 @@
return changes, nil
}
+func gcsArtifactIsMissing(ctx context.Context, client *http.Client, cfg *config.Config) (bool, error) {
+ pcrm := cfg.GetParentChildRepoManager()
+ if pcrm == nil {
+ return false, nil
+ }
+ semVerGCSChild := pcrm.GetSemverGcsChild()
+ if semVerGCSChild == nil {
+ return false, nil
+ }
+ gcsChild := semVerGCSChild.Gcs
+ if gcsChild == nil {
+ // This shouldn't happen with a valid config.
+ return false, nil
+ }
+ regex, err := regexp.Compile(semVerGCSChild.VersionRegex)
+ if err != nil {
+ return false, skerr.Wrapf(err, "failed compiling regex for %s", cfg.RollerName)
+ }
+ storageClient, err := storage.NewClient(ctx, option.WithHTTPClient(client))
+ if err != nil {
+ return false, skerr.Wrap(err)
+ }
+ gcsClient := gcsclient.New(storageClient, gcsChild.GcsBucket)
+ missing := true
+ if err := gcsClient.AllFilesInDirectory(ctx, gcsChild.GcsPath, func(item *storage.ObjectAttrs) error {
+ if regex.MatchString(path.Base(item.Name)) {
+ missing = false
+ return iterator.Done
+ }
+ return nil
+ }); err != nil && err != iterator.Done {
+ return false, skerr.Wrapf(err, "failed searching %s/%s", gcsChild.GcsBucket, gcsChild.GcsPath)
+ }
+ return missing, nil
+}
+
func makeMap(elems ...interface{}) (map[string]interface{}, error) {
if len(elems)%2 != 0 {
return nil, skerr.Fmt("Requires an even number of elements, not %d", len(elems))