diff options
| -rw-r--r-- | syz-cluster/controller/Dockerfile | 1 | ||||
| -rw-r--r-- | syz-cluster/controller/deployment.yaml | 7 | ||||
| -rw-r--r-- | syz-cluster/dashboard/Dockerfile | 1 | ||||
| -rw-r--r-- | syz-cluster/dashboard/deployment.yaml | 7 | ||||
| -rw-r--r-- | syz-cluster/db-mgmt/Dockerfile | 1 | ||||
| -rw-r--r-- | syz-cluster/overlays/dev/fake-gcs.yaml | 2 | ||||
| -rw-r--r-- | syz-cluster/overlays/dev/global-config.yaml | 3 | ||||
| -rw-r--r-- | syz-cluster/overlays/dev/kustomization.yaml | 1 | ||||
| -rw-r--r-- | syz-cluster/pkg/app/env.go | 19 | ||||
| -rw-r--r-- | syz-cluster/pkg/blob/gcs.go | 86 | ||||
| -rw-r--r-- | syz-cluster/pkg/blob/storage.go | 7 | ||||
| -rw-r--r-- | syz-cluster/series-tracker/deployment.yaml | 5 |
12 files changed, 104 insertions, 36 deletions
diff --git a/syz-cluster/controller/Dockerfile b/syz-cluster/controller/Dockerfile index c6692e290..7b05e16fe 100644 --- a/syz-cluster/controller/Dockerfile +++ b/syz-cluster/controller/Dockerfile @@ -6,6 +6,7 @@ WORKDIR /build COPY go.mod ./ COPY go.sum ./ RUN go mod download +COPY pkg/gcs/ pkg/gcs/ # Build the tool. COPY syz-cluster/controller/ syz-cluster/controller/ diff --git a/syz-cluster/controller/deployment.yaml b/syz-cluster/controller/deployment.yaml index 9b52864c8..05ece9aa3 100644 --- a/syz-cluster/controller/deployment.yaml +++ b/syz-cluster/controller/deployment.yaml @@ -23,10 +23,3 @@ spec: name: global-config ports: - containerPort: 8080 - volumeMounts: - - name: blobs-storage-disk - mountPath: /blob-storage - volumes: - - name: blobs-storage-disk - persistentVolumeClaim: - claimName: blob-storage-disk-claim diff --git a/syz-cluster/dashboard/Dockerfile b/syz-cluster/dashboard/Dockerfile index c813d856e..53925a53b 100644 --- a/syz-cluster/dashboard/Dockerfile +++ b/syz-cluster/dashboard/Dockerfile @@ -6,6 +6,7 @@ WORKDIR /build COPY go.mod ./ COPY go.sum ./ RUN go mod download +COPY pkg/gcs/ pkg/gcs/ # Build the tool. COPY syz-cluster/dashboard/ syz-cluster/dashboard/ diff --git a/syz-cluster/dashboard/deployment.yaml b/syz-cluster/dashboard/deployment.yaml index e6699f211..a3e56dadf 100644 --- a/syz-cluster/dashboard/deployment.yaml +++ b/syz-cluster/dashboard/deployment.yaml @@ -23,10 +23,3 @@ spec: name: global-config ports: - containerPort: 8081 - volumeMounts: - - name: blobs-storage-disk - mountPath: /blob-storage - volumes: - - name: blobs-storage-disk - persistentVolumeClaim: - claimName: blob-storage-disk-claim diff --git a/syz-cluster/db-mgmt/Dockerfile b/syz-cluster/db-mgmt/Dockerfile index a999a31d3..96e93bba6 100644 --- a/syz-cluster/db-mgmt/Dockerfile +++ b/syz-cluster/db-mgmt/Dockerfile @@ -6,6 +6,7 @@ WORKDIR /build COPY go.mod ./ COPY go.sum ./ RUN go mod download +COPY pkg/gcs/ pkg/gcs/ # Build the tool. COPY syz-cluster/db-mgmt/*.go syz-cluster/db-mgmt/ diff --git a/syz-cluster/overlays/dev/fake-gcs.yaml b/syz-cluster/overlays/dev/fake-gcs.yaml index 362da197c..e9ebcd4e8 100644 --- a/syz-cluster/overlays/dev/fake-gcs.yaml +++ b/syz-cluster/overlays/dev/fake-gcs.yaml @@ -18,7 +18,7 @@ spec: initContainers: - name: create-test-bucket image: busybox - command: ["sh", "-c", "mkdir -p /data/test-bucket"] + command: ["sh", "-c", "mkdir -p /data/test-bucket /data/blobs"] volumeMounts: - name: data-volume mountPath: /data diff --git a/syz-cluster/overlays/dev/global-config.yaml b/syz-cluster/overlays/dev/global-config.yaml index 0ee6bb8b5..83293e81e 100644 --- a/syz-cluster/overlays/dev/global-config.yaml +++ b/syz-cluster/overlays/dev/global-config.yaml @@ -8,5 +8,6 @@ metadata: data: SPANNER_EMULATOR_HOST: "cloud-spanner-emulator:9010" SPANNER_DATABASE_URI: "projects/my-project/instances/my-instance/databases/db" - LOCAL_BLOB_STORAGE_PATH: "/blob-storage" + STORAGE_EMULATOR_HOST: "http://fake-gcs-server.default.svc.cluster.local:4443" + BLOB_STORAGE_GCS_BUCKET: "blobs" # Initialized in fake-gcs.yaml PARALLEL_WORKERS: "1" # Process only one series at a time. diff --git a/syz-cluster/overlays/dev/kustomization.yaml b/syz-cluster/overlays/dev/kustomization.yaml index 815048f4e..0aa368cb6 100644 --- a/syz-cluster/overlays/dev/kustomization.yaml +++ b/syz-cluster/overlays/dev/kustomization.yaml @@ -11,7 +11,6 @@ resources: - workflow-roles.yaml - fake-gcs.yaml - workflow-artifacts.yaml - - blobs-pvc-dev.yaml patches: - target: diff --git a/syz-cluster/pkg/app/env.go b/syz-cluster/pkg/app/env.go index 53ba9a77f..e54cb30b2 100644 --- a/syz-cluster/pkg/app/env.go +++ b/syz-cluster/pkg/app/env.go @@ -25,7 +25,7 @@ func Environment(ctx context.Context) (*AppEnvironment, error) { if err != nil { return nil, fmt.Errorf("failed to set up a Spanner client: %w", err) } - storage, err := DefaultStorage() + storage, err := DefaultStorage(ctx) if err != nil { return nil, fmt.Errorf("failed to set up the blob storage: %w", err) } @@ -60,18 +60,13 @@ func DefaultSpanner(ctx context.Context) (*spanner.Client, error) { return spanner.NewClient(ctx, uri.Full) } -func DefaultStorage() (blob.Storage, error) { - // LOCAL_BLOB_STORAGE_PATH is set in the dev environment. - path := os.Getenv("LOCAL_BLOB_STORAGE_PATH") - if path == "" { - // TODO: implement GCS support. - return nil, fmt.Errorf("empty LOCAL_BLOB_STORAGE_PATH") +func DefaultStorage(ctx context.Context) (blob.Storage, error) { + // BLOB_STORAGE_GCS_BUCKET is the only supported option. + bucket := os.Getenv("BLOB_STORAGE_GCS_BUCKET") + if bucket == "" { + return nil, fmt.Errorf("empty BLOB0_STORAGE_GCS_BUCKET") } - err := os.MkdirAll(path, 0666) - if err != nil { - return nil, err - } - return blob.NewLocalStorage(path), nil + return blob.NewGCSClient(ctx, bucket) } func DefaultClient() *api.Client { diff --git a/syz-cluster/pkg/blob/gcs.go b/syz-cluster/pkg/blob/gcs.go new file mode 100644 index 000000000..1a865c1a2 --- /dev/null +++ b/syz-cluster/pkg/blob/gcs.go @@ -0,0 +1,86 @@ +// Copyright 2025 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package blob + +import ( + "context" + "fmt" + "io" + "regexp" + + "github.com/google/syzkaller/pkg/gcs" + "github.com/google/uuid" +) + +type gcsDriver struct { + bucket string + client *gcs.Client +} + +func NewGCSClient(ctx context.Context, bucket string) (Storage, error) { + client, err := gcs.NewClient(ctx) + if err != nil { + return nil, err + } + return &gcsDriver{ + bucket: bucket, + client: client, + }, nil +} + +func (gcs *gcsDriver) Store(source io.Reader) (string, error) { + object := uuid.New().String() + err := gcs.writeObject(object, source) + if err != nil { + return "", err + } + return gcs.objectURI(object), nil +} + +func (gcs *gcsDriver) Update(uri string, source io.Reader) error { + object, err := gcs.objectName(uri) + if err != nil { + return err + } + return gcs.writeObject(object, source) +} + +func (gcs *gcsDriver) Read(uri string) (io.ReadCloser, error) { + object, err := gcs.objectName(uri) + if err != nil { + return nil, err + } + file, err := gcs.client.Read(fmt.Sprintf("%s/%s", gcs.bucket, object)) + if err != nil { + return nil, err + } + return file.Reader() +} + +var gcsObjectRe = regexp.MustCompile(`^gcs://([\w-]+)/([\w-]+)$`) + +func (gcs *gcsDriver) objectName(uri string) (string, error) { + match := gcsObjectRe.FindStringSubmatch(uri) + if len(match) == 0 { + return "", fmt.Errorf("invalid GCS URI") + } else if match[1] != gcs.bucket { + return "", fmt.Errorf("unexpected GCS bucket") + } + return match[2], nil +} + +func (gcs *gcsDriver) objectURI(object string) string { + return fmt.Sprintf("gcs://%s/%s", gcs.bucket, object) +} + +func (gcs *gcsDriver) writeObject(object string, source io.Reader) error { + w, err := gcs.client.FileWriterExt(fmt.Sprintf("%s/%s", gcs.bucket, object), "", "") + if err != nil { + return err + } + defer w.Close() + + _, err = io.Copy(w, source) + return err +} diff --git a/syz-cluster/pkg/blob/storage.go b/syz-cluster/pkg/blob/storage.go index a38899c33..ba85d68d1 100644 --- a/syz-cluster/pkg/blob/storage.go +++ b/syz-cluster/pkg/blob/storage.go @@ -9,7 +9,8 @@ import ( "os" "path/filepath" "strings" - "time" + + "github.com/google/uuid" ) // Storage is not assumed to be used for partciularly large objects (e.g. GB of size), @@ -23,6 +24,8 @@ type Storage interface { var _ Storage = (*LocalStorage)(nil) +// LocalStorage keeps objets in the specified local directory. +// It's intended to be used only for unit tests. type LocalStorage struct { baseFolder string } @@ -34,7 +37,7 @@ func NewLocalStorage(baseFolder string) *LocalStorage { const localStoragePrefix = "local://" func (ls *LocalStorage) Store(source io.Reader) (string, error) { - name := fmt.Sprint(time.Now().UnixNano()) + name := uuid.New().String() err := ls.writeFile(name, source) if err != nil { return "", err diff --git a/syz-cluster/series-tracker/deployment.yaml b/syz-cluster/series-tracker/deployment.yaml index 2a84f0722..b6e067a37 100644 --- a/syz-cluster/series-tracker/deployment.yaml +++ b/syz-cluster/series-tracker/deployment.yaml @@ -24,12 +24,7 @@ spec: volumeMounts: - name: series-tracker-repo-disk mountPath: /git-repo - - name: blobs-storage-disk - mountPath: /blob-storage volumes: - name: series-tracker-repo-disk persistentVolumeClaim: claimName: series-tracker-repo-disk-claim - - name: blobs-storage-disk - persistentVolumeClaim: - claimName: blob-storage-disk-claim |
