Merge pull request #21908 from overleaf/jpa-storage-class

[object-persistor] s3: add support for setting storage class on upload

GitOrigin-RevId: dc5480a95ec7f1551f08848f7fa45f760d97ab22
This commit is contained in:
Jakob Ackermann
2024-11-18 09:05:10 +00:00
committed by Copybot
parent 36acad4d1b
commit d6e94d2586
9 changed files with 98 additions and 5 deletions
@@ -15,6 +15,12 @@ const glob = promisify(globCallbacks)
module.exports = class FSPersistor extends AbstractPersistor {
constructor(settings = {}) {
if (settings.storageClass) {
throw new NotImplementedError(
'FS backend does not support storage classes'
)
}
super()
this.useSubdirectories = Boolean(settings.useSubdirectories)
}
+12 -2
View File
@@ -2,7 +2,12 @@ const fs = require('node:fs')
const { pipeline } = require('node:stream/promises')
const { PassThrough } = require('node:stream')
const { Storage, IdempotencyStrategy } = require('@google-cloud/storage')
const { WriteError, ReadError, NotFoundError } = require('./Errors')
const {
WriteError,
ReadError,
NotFoundError,
NotImplementedError,
} = require('./Errors')
const asyncPool = require('tiny-async-pool')
const AbstractPersistor = require('./AbstractPersistor')
const PersistorHelper = require('./PersistorHelper')
@@ -11,8 +16,13 @@ const zlib = require('node:zlib')
module.exports = class GcsPersistor extends AbstractPersistor {
constructor(settings) {
super()
if (settings.storageClass) {
throw new NotImplementedError(
'Use default bucket class for GCS instead of settings.storageClass'
)
}
super()
this.settings = settings
// endpoint settings will be null by default except for tests
@@ -311,6 +311,16 @@ class PerProjectEncryptedS3Persistor extends S3Persistor {
return await super.getObjectSize(bucketName, path, { ...opts, ssecOptions })
}
async getObjectStorageClass(bucketName, path, opts = {}) {
const ssecOptions =
opts.ssecOptions ||
(await this.#getExistingDataEncryptionKeyOptions(bucketName, path))
return await super.getObjectStorageClass(bucketName, path, {
...opts,
ssecOptions,
})
}
async directorySize(bucketName, path, continuationToken) {
// Note: Listing a bucket does not require SSE-C credentials.
return await super.directorySize(bucketName, path, continuationToken)
+18 -1
View File
@@ -64,6 +64,7 @@ class S3Persistor extends AbstractPersistor {
constructor(settings = {}) {
super()
settings.storageClass = settings.storageClass || {}
this.settings = settings
}
@@ -100,13 +101,17 @@ class S3Persistor extends AbstractPersistor {
// observer will catch errors, clean up and log a warning
pipeline(readStream, observer, () => {})
// if we have an md5 hash, pass this to S3 to verify the upload
/** @type {S3.PutObjectRequest} */
const uploadOptions = {
Bucket: bucketName,
Key: key,
Body: observer,
}
if (this.settings.storageClass[bucketName]) {
uploadOptions.StorageClass = this.settings.storageClass[bucketName]
}
if (opts.contentType) {
uploadOptions.ContentType = opts.contentType
}
@@ -336,6 +341,18 @@ class S3Persistor extends AbstractPersistor {
return response.ContentLength || 0
}
/**
* @param {string} bucketName
* @param {string} key
* @param {Object} opts
* @param {SSECOptions} [opts.ssecOptions]
* @return {Promise<string | undefined>}
*/
async getObjectStorageClass(bucketName, key, opts = {}) {
const response = await this.#headObject(bucketName, key, opts)
return response.StorageClass
}
/**
* @param {string} bucketName
* @param {string} key