Conversation
1513f8b to
5ab32eb
Compare
Signed-off-by: or-shachar <or.shachar@wiz.io>
5ab32eb to
66b2de7
Compare
klauspost
left a comment
There was a problem hiding this comment.
Was going to write my own, but saw you had already made the bulk of the work.
| body, err := io.ReadAll(result.Body) | ||
| if err != nil { | ||
| return "", "", err | ||
| } | ||
| if err := json.Unmarshal(body, &av); err != nil { |
There was a problem hiding this comment.
Let's stream the response:
| body, err := io.ReadAll(result.Body) | |
| if err != nil { | |
| return "", "", err | |
| } | |
| if err := json.Unmarshal(body, &av); err != nil { | |
| dec := json.NewDecoder(result.Body) | |
| if err := dec.Decode(&av); err != nil { |
(but maybe drop, see later)
There was a problem hiding this comment.
changed implementation here - or-shachar@0bc8aa9#diff-3996ec7951ff9218f18b180f064a24e55ee57da5f81810fcb063e37f339896caR69
| if c.verbose { | ||
| log.Printf("error S3 get for %s: %v", actionKey, err) | ||
| } | ||
| return "", "", fmt.Errorf("unexpected S3 get for %s: %v", actionKey, err) |
There was a problem hiding this comment.
| return "", "", fmt.Errorf("unexpected S3 get for %s: %v", actionKey, err) | |
| return "", "", fmt.Errorf("unexpected S3 get for %s: %w", actionKey, err) |
| var ae smithy.APIError | ||
| if errors.As(err, &ae) { | ||
| code := ae.ErrorCode() | ||
| return code == "AccessDenied" || code == "NoSuchKey" |
There was a problem hiding this comment.
Good question. Not sure why I chose AccessDenied, maybe my original permissions were only to s3:GetObject without s3:ListBucket which results in AccessDenied in case key cannot be found.
| if c.verbose { | ||
| log.Printf("error S3 get for %s: %v", outputKey, getOutputErr) | ||
| } | ||
| return "", "", fmt.Errorf("unexpected S3 get for %s: %v", outputKey, getOutputErr) |
There was a problem hiding this comment.
| return "", "", fmt.Errorf("unexpected S3 get for %s: %v", outputKey, getOutputErr) | |
| return "", "", fmt.Errorf("unexpected S3 get for %s: %w", outputKey, getOutputErr) |
| We support S3 backend for caching. | ||
| You can connect to S3 backend by setting the following parameters: | ||
| - `GOCACHE_S3_BUCKET` - Name of S3 bucket | ||
| - `GOCACHE_AWS_REGION` - AWS Region of bucket |
There was a problem hiding this comment.
| - `GOCACHE_AWS_REGION` - AWS Region of bucket | |
| - `GOCACHE_S3_REGION` - AWS Region of bucket |
I think having the same prefix makes it clearer. I suggest using the service name rather than the vendor name. (same goes for other env vars)
| os := runtime.GOOS | ||
| // get current version of Go | ||
| ver := strings.ReplaceAll(strings.ReplaceAll(runtime.Version(), " ", "-"), ":", "-") | ||
| prefix := fmt.Sprintf("cache/%s/%s/%s/%s", cacheKey, arc, os, ver) |
There was a problem hiding this comment.
It would be good behavior to make the cache prefix configurable. No biggie. Consider the default to be gocache to make it a bit easier to identify.
There was a problem hiding this comment.
|
|
||
| putBody = outputResult.Body | ||
| } | ||
| diskPath, err = c.diskCache.Put(ctx, actionID, outputID, av.Size, putBody) |
There was a problem hiding this comment.
Need help: Documentation indicates that modtime of the file is used for "something".
You may need some way to set the mod-time to the object write time. This should be available from S3.
There was a problem hiding this comment.
Can you please reference the relevant documentation?
| OutputID: outputID, | ||
| Size: size, | ||
| } | ||
| avj, err := json.Marshal(av) |
There was a problem hiding this comment.
2 PutObject calls per write seems like one to many. And a place where inconsistencies could creep in. Having 1 write will make it atomic, so probably that is a win here.
I suggest you store the object using the actionID only and add objectID as a custom header.
There is a 2KB limit on metadata, so maybe check if that is likely to be exceeded.
There was a problem hiding this comment.
This was done on the main branch of my fork
| _, err = client.PutObject(ctx, &s3.PutObjectInput{ | ||
| Bucket: &c.Bucket, | ||
| Key: &outputKey, | ||
| Body: &readerForS3, | ||
| ContentLength: size, | ||
| }) |
There was a problem hiding this comment.
| _, err = client.PutObject(ctx, &s3.PutObjectInput{ | |
| Bucket: &c.Bucket, | |
| Key: &outputKey, | |
| Body: &readerForS3, | |
| ContentLength: size, | |
| }) | |
| _, err = client.PutObject(ctx, &s3.PutObjectInput{ | |
| Bucket: &c.Bucket, | |
| Key: &outputKey, | |
| Body: &readerForS3, | |
| ContentLength: size, | |
| Metadata: map[string]string{"gocache-output-id": outputID}, | |
| }) |
There was a problem hiding this comment.
| }) | ||
| } | ||
| if size > 0 && err == nil { | ||
| outputKey := c.outputKey(outputID) |
There was a problem hiding this comment.
| outputKey := c.outputKey(outputID) | |
| outputKey := c.actionKey(actionID) |
|
@or-shachar @bradfitz Let me know if you are not interested in pursuing this, and I will just do a fork. |
|
Oh seeing this only now. I can probably work on this on Friday but not earlier unfortunately... Thanks for the feedback! 🙏 |
|
@or-shachar Wasn't pushing - just asking, since I didn't know if you were still interested after having it open for a year. Either way, you can just ping me for S3 questions. And we can decide if we fork or not. If you want a custom endpoint to test against, you can use To create a bucket, using our commandline client, use the default config and |
|
We use my flavor of S3 for more than a year. A major improvement over traditional CI cache. |
|
Hey @klauspost - thanks for your kind feedback... I did made some progress on my fork and started working on main branch there. I'll incorporate your feedback there. Generally - I understand you want to abstract AWS terms so it can work with any S3 compatible API, right? Feel free to open another PR to the fork as I don't think @bradfitz is here and I'm not the maintainer of this repo. |
|
To avoid confusing - I'm closing this PR as we've made a lot of progress on my fork, main branch, since then. |
My humble attempt to do #6