{internal/cmd}/worker: add Config struct
Put server-relevant config into a struct.
Change-Id: I865d78b17258b2aab3ba9090d240951f54d9a302
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/370214
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/cmd/worker/main.go b/cmd/worker/main.go
index cc5a9e0..2f5f27e 100644
--- a/cmd/worker/main.go
+++ b/cmd/worker/main.go
@@ -18,8 +18,6 @@
"strings"
"text/tabwriter"
- "cloud.google.com/go/errorreporting"
- "golang.org/x/vuln/internal/derrors"
"golang.org/x/vuln/internal/gitrepo"
"golang.org/x/vuln/internal/worker"
"golang.org/x/vuln/internal/worker/log"
@@ -27,19 +25,28 @@
)
var (
- project = flag.String("project", os.Getenv("GOOGLE_CLOUD_PROJECT"), "project ID (required)")
- namespace = flag.String("namespace", os.Getenv("VULN_WORKER_NAMESPACE"), "Firestore namespace (required)")
- errorReporting = flag.Bool("report-errors", os.Getenv("VULN_WORKER_REPORT_ERRORS") == "true", "use the error reporting API")
- localRepoPath = flag.String("local-cve-repo", "", "path to local repo, instead of cloning remote")
- force = flag.Bool("force", false, "force an update to happen")
- limit = flag.Int("limit", 0, "limit on number of things to list or issues to create (0 means unlimited)")
- issueRepo = flag.String("issue-repo", "", "repo to create issues in")
- githubTokenFile = flag.String("ghtokenfile", "", "path to file containing GitHub access token (for creating issues)")
+ // Flags only for the command-line tool.
+ localRepoPath = flag.String("local-cve-repo", "", "path to local repo, instead of cloning remote")
+ force = flag.Bool("force", false, "force an update to happen")
+ limit = flag.Int("limit", 0,
+ "limit on number of things to list or issues to create (0 means unlimited)")
+ githubTokenFile = flag.String("ghtokenfile", "",
+ "path to file containing GitHub access token (for creating issues)")
)
+// Config for both the server and the command-line tool.
+var cfg worker.Config
+
+func init() {
+ flag.StringVar(&cfg.Project, "project", os.Getenv("GOOGLE_CLOUD_PROJECT"), "project ID (required)")
+ flag.StringVar(&cfg.Namespace, "namespace", os.Getenv("VULN_WORKER_NAMESPACE"), "Firestore namespace (required)")
+ flag.BoolVar(&cfg.UseErrorReporting, "report-errors", os.Getenv("VULN_WORKER_REPORT_ERRORS") == "true",
+ "use the error reporting API")
+ flag.StringVar(&cfg.IssueRepo, "issue-repo", os.Getenv("VULN_WORKER_ISSUE_REPO"), "repo to create issues in")
+}
+
const (
pkgsiteURL = "https://pkg.go.dev"
- serviceID = "vuln-worker"
)
func main() {
@@ -58,49 +65,40 @@
fmt.Fprintln(out, "flags:")
flag.PrintDefaults()
}
- flag.Parse()
- if *project == "" {
- dieWithUsage("need -project or GOOGLE_CLOUD_PROJECT")
- }
- if *namespace == "" {
- dieWithUsage("need -namespace or VULN_WORKER_NAMESPACE")
- }
- ctx := log.WithLineLogger(context.Background())
- fstore, err := store.NewFireStore(ctx, *project, *namespace)
+ flag.Parse()
+ if *githubTokenFile != "" {
+ data, err := ioutil.ReadFile(*githubTokenFile)
+ if err != nil {
+ die("%v", err)
+ }
+ cfg.GitHubAccessToken = strings.TrimSpace(string(data))
+ }
+ if err := cfg.Validate(); err != nil {
+ dieWithUsage("%v", err)
+ }
+
+ ctx := log.WithLineLogger(context.Background())
+ var err error
+ cfg.Store, err = store.NewFireStore(ctx, cfg.Project, cfg.Namespace)
if err != nil {
die("firestore: %v", err)
}
if flag.NArg() > 0 {
- err = runCommandLine(ctx, fstore)
+ err = runCommandLine(ctx)
} else {
- err = runServer(ctx, fstore)
+ err = runServer(ctx)
}
if err != nil {
dieWithUsage("%v", err)
}
}
-func runServer(ctx context.Context, st store.Store) error {
+func runServer(ctx context.Context) error {
if os.Getenv("PORT") == "" {
return errors.New("need PORT")
}
-
- if *errorReporting {
- reportingClient, err := errorreporting.NewClient(ctx, *project, errorreporting.Config{
- ServiceName: serviceID,
- OnError: func(err error) {
- log.Errorf(ctx, "Error reporting failed: %v", err)
- },
- })
- if err != nil {
- return err
- }
- derrors.SetReportingClient(reportingClient)
- }
-
- _, err := worker.NewServer(ctx, *namespace, st)
- if err != nil {
+ if _, err := worker.NewServer(ctx, cfg); err != nil {
return err
}
addr := ":" + os.Getenv("PORT")
@@ -110,27 +108,27 @@
const timeFormat = "2006/01/02 15:04:05"
-func runCommandLine(ctx context.Context, st store.Store) error {
+func runCommandLine(ctx context.Context) error {
switch flag.Arg(0) {
case "list-updates":
- return listUpdatesCommand(ctx, st)
+ return listUpdatesCommand(ctx)
case "list-cves":
- return listCVEsCommand(ctx, st, flag.Arg(1))
+ return listCVEsCommand(ctx, flag.Arg(1))
case "update":
if flag.NArg() != 2 {
return errors.New("usage: update COMMIT")
}
- return updateCommand(ctx, st, flag.Arg(1))
+ return updateCommand(ctx, flag.Arg(1))
case "create-issues":
- return createIssuesCommand(ctx, st)
+ return createIssuesCommand(ctx)
default:
return fmt.Errorf("unknown command: %q", flag.Arg(1))
}
}
-func listUpdatesCommand(ctx context.Context, st store.Store) error {
- recs, err := st.ListCommitUpdateRecords(ctx, 0)
+func listUpdatesCommand(ctx context.Context) error {
+ recs, err := cfg.Store.ListCommitUpdateRecords(ctx, 0)
if err != nil {
return err
}
@@ -153,12 +151,12 @@
return tw.Flush()
}
-func listCVEsCommand(ctx context.Context, st store.Store, triageState string) error {
+func listCVEsCommand(ctx context.Context, triageState string) error {
ts := store.TriageState(triageState)
if err := ts.Validate(); err != nil {
return err
}
- crs, err := st.ListCVERecordsWithTriageState(ctx, ts)
+ crs, err := cfg.Store.ListCVERecordsWithTriageState(ctx, ts)
if err != nil {
return err
}
@@ -174,32 +172,25 @@
return tw.Flush()
}
-func updateCommand(ctx context.Context, st store.Store, commitHash string) error {
+func updateCommand(ctx context.Context, commitHash string) error {
repoPath := gitrepo.CVEListRepoURL
if *localRepoPath != "" {
repoPath = *localRepoPath
}
- err := worker.UpdateCommit(ctx, repoPath, commitHash, st, pkgsiteURL, *force)
+ err := worker.UpdateCommit(ctx, repoPath, commitHash, cfg.Store, pkgsiteURL, *force)
if cerr := new(worker.CheckUpdateError); errors.As(err, &cerr) {
return fmt.Errorf("%w; use -force to override", cerr)
}
return err
}
-func createIssuesCommand(ctx context.Context, st store.Store) error {
- owner, repoName, err := worker.ParseGithubRepo(*issueRepo)
+func createIssuesCommand(ctx context.Context) error {
+ owner, repoName, err := worker.ParseGithubRepo(cfg.IssueRepo)
if err != nil {
return err
}
- if *githubTokenFile == "" {
- return errors.New("need -ghtokenfile")
- }
- data, err := ioutil.ReadFile(*githubTokenFile)
- if err != nil {
- return err
- }
- token := strings.TrimSpace(string(data))
- return worker.CreateIssues(ctx, st, worker.NewGithubIssueClient(owner, repoName, token), *limit)
+ client := worker.NewGithubIssueClient(owner, repoName, cfg.GitHubAccessToken)
+ return worker.CreateIssues(ctx, cfg.Store, client, *limit)
}
func die(format string, args ...interface{}) {
diff --git a/internal/worker/config.go b/internal/worker/config.go
new file mode 100644
index 0000000..b1d74fc
--- /dev/null
+++ b/internal/worker/config.go
@@ -0,0 +1,49 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package worker
+
+import (
+ "errors"
+
+ "golang.org/x/vuln/internal/worker/store"
+)
+
+// serviceID names the Cloud Run service.
+const serviceID = "vuln-worker"
+
+// Config holds configuration information for the worker server.
+type Config struct {
+ // Project is the Google Cloud Project where the resources live.
+ Project string
+
+ // Namespace is the Firstore namespace to use.
+ Namespace string
+
+ // UseErrorReporting determines whether errors go to the Error Reporting API.
+ UseErrorReporting bool
+
+ // IssueRepo is the GitHub repo to use for issues.
+ // An empty string disables issue creation.
+ IssueRepo string
+
+ // GitHubAccessToken is the token needed to authorize to the GitHub API.
+ GitHubAccessToken string
+
+ // Store is the implementation of store.Store used by the server.
+ Store store.Store
+}
+
+func (c *Config) Validate() error {
+ if c.Project == "" {
+ return errors.New("missing project")
+ }
+ if c.Namespace == "" {
+ return errors.New("missing namespace")
+ }
+ if c.IssueRepo != "" && c.GitHubAccessToken == "" {
+ return errors.New("issue repo requires access token")
+ }
+ return nil
+}
diff --git a/internal/worker/server.go b/internal/worker/server.go
index b5e75d4..91ca65f 100644
--- a/internal/worker/server.go
+++ b/internal/worker/server.go
@@ -13,6 +13,7 @@
"path/filepath"
"time"
+ "cloud.google.com/go/errorreporting"
"github.com/google/safehtml/template"
"golang.org/x/exp/event"
"golang.org/x/sync/errgroup"
@@ -25,16 +26,28 @@
var staticPath = template.TrustedSourceFromConstant("internal/worker/static")
type Server struct {
- namespace string
- st store.Store
-
+ cfg Config
indexTemplate *template.Template
}
-func NewServer(ctx context.Context, namespace string, st store.Store) (_ *Server, err error) {
- defer derrors.Wrap(&err, "NewServer(%q)", namespace)
+func NewServer(ctx context.Context, cfg Config) (_ *Server, err error) {
+ defer derrors.Wrap(&err, "NewServer(%q)", cfg.Namespace)
- s := &Server{namespace: namespace, st: st}
+ s := &Server{cfg: cfg}
+
+ if cfg.UseErrorReporting {
+ reportingClient, err := errorreporting.NewClient(ctx, cfg.Project, errorreporting.Config{
+ ServiceName: serviceID,
+ OnError: func(err error) {
+ log.Errorf(ctx, "Error reporting failed: %v", err)
+ },
+ })
+ if err != nil {
+ return nil, err
+ }
+ derrors.SetReportingClient(reportingClient)
+ }
+
s.indexTemplate, err = parseTemplate(staticPath, template.TrustedSourceFromConstant("index.tmpl"))
if err != nil {
return nil, err
@@ -154,17 +167,17 @@
g, ctx := errgroup.WithContext(r.Context())
g.Go(func() error {
var err error
- updates, err = s.st.ListCommitUpdateRecords(ctx, 10)
+ updates, err = s.cfg.Store.ListCommitUpdateRecords(ctx, 10)
return err
})
g.Go(func() error {
var err error
- needingIssue, err = s.st.ListCVERecordsWithTriageState(ctx, store.TriageStateNeedsIssue)
+ needingIssue, err = s.cfg.Store.ListCVERecordsWithTriageState(ctx, store.TriageStateNeedsIssue)
return err
})
g.Go(func() error {
var err error
- updatedSince, err = s.st.ListCVERecordsWithTriageState(ctx, store.TriageStateUpdatedSinceIssueCreation)
+ updatedSince, err = s.cfg.Store.ListCVERecordsWithTriageState(ctx, store.TriageStateUpdatedSinceIssueCreation)
return err
})
if err := g.Wait(); err != nil {
@@ -173,7 +186,7 @@
page := indexPage{
CVEListRepoURL: gitrepo.CVEListRepoURL,
- Namespace: s.namespace,
+ Namespace: s.cfg.Namespace,
Updates: updates,
CVEsNeedingIssue: needingIssue,
CVEsUpdatedSince: updatedSince,