@backstage/plugin-techdocs-node 1.13.1 → 1.13.2-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/stages/publish/awsS3.cjs.js +10 -1
- package/dist/stages/publish/awsS3.cjs.js.map +1 -1
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @backstage/plugin-techdocs-node
|
|
2
2
|
|
|
3
|
+
## 1.13.2-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/integration@1.16.3-next.0
|
|
9
|
+
- @backstage/backend-plugin-api@1.2.1
|
|
10
|
+
- @backstage/catalog-model@1.7.3
|
|
11
|
+
- @backstage/config@1.3.2
|
|
12
|
+
- @backstage/errors@1.2.7
|
|
13
|
+
- @backstage/integration-aws-node@0.1.15
|
|
14
|
+
- @backstage/plugin-search-common@1.2.17
|
|
15
|
+
- @backstage/plugin-techdocs-common@0.1.0
|
|
16
|
+
|
|
17
|
+
## 1.13.2-next.0
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 304a422: Update AWS file retrieval logic from storing file in buffer array to piping to res for better memory efficiency.
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @backstage/backend-plugin-api@1.2.1
|
|
24
|
+
- @backstage/catalog-model@1.7.3
|
|
25
|
+
- @backstage/config@1.3.2
|
|
26
|
+
- @backstage/errors@1.2.7
|
|
27
|
+
- @backstage/integration@1.16.2
|
|
28
|
+
- @backstage/integration-aws-node@0.1.15
|
|
29
|
+
- @backstage/plugin-search-common@1.2.17
|
|
30
|
+
- @backstage/plugin-techdocs-common@0.1.0
|
|
31
|
+
|
|
3
32
|
## 1.13.1
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
|
@@ -331,7 +331,16 @@ class AwsS3Publish {
|
|
|
331
331
|
)) {
|
|
332
332
|
res.setHeader(headerKey, headerValue);
|
|
333
333
|
}
|
|
334
|
-
|
|
334
|
+
resp.Body.on("error", (err) => {
|
|
335
|
+
this.logger.warn(
|
|
336
|
+
`TechDocs S3 router failed to serve static files from bucket ${this.bucketName} at key ${filePath}: ${err.message}`
|
|
337
|
+
);
|
|
338
|
+
if (!res.headersSent) {
|
|
339
|
+
res.status(404).send("File Not Found");
|
|
340
|
+
} else {
|
|
341
|
+
res.destroy();
|
|
342
|
+
}
|
|
343
|
+
}).pipe(res);
|
|
335
344
|
} catch (err) {
|
|
336
345
|
errors.assertError(err);
|
|
337
346
|
this.logger.warn(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"awsS3.cjs.js","sources":["../../../src/stages/publish/awsS3.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n GetObjectCommand,\n CopyObjectCommand,\n DeleteObjectCommand,\n HeadBucketCommand,\n HeadObjectCommand,\n PutObjectCommandInput,\n ListObjectsV2CommandOutput,\n ListObjectsV2Command,\n S3Client,\n} from '@aws-sdk/client-s3';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { HttpsProxyAgent } from 'hpagent';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { Readable } from 'stream';\nimport {\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getFileTreeRecursively,\n getHeadersForFileExtension,\n getStaleFiles,\n isValidContentPath,\n lowerCaseEntityTriplet,\n lowerCaseEntityTripletInStoragePath,\n normalizeExternalStorageRootPath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst streamToBuffer = (stream: Readable): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', (e: Error) =>\n reject(new ForwardedError('Unable to read stream', e)),\n );\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n};\n\nexport class AwsS3Publish implements PublisherBase {\n private readonly storageClient: S3Client;\n private readonly bucketName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: LoggerService;\n private readonly bucketRootPath: string;\n private readonly sse?: 'aws:kms' | 'AES256';\n\n constructor(options: {\n storageClient: S3Client;\n bucketName: string;\n legacyPathCasing: boolean;\n logger: LoggerService;\n bucketRootPath: string;\n sse?: 'aws:kms' | 'AES256';\n }) {\n this.storageClient = options.storageClient;\n this.bucketName = options.bucketName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n this.bucketRootPath = options.bucketRootPath;\n this.sse = options.sse;\n }\n\n static async fromConfig(\n config: Config,\n logger: LoggerService,\n ): Promise<PublisherBase> {\n let bucketName = '';\n try {\n bucketName = config.getString('techdocs.publisher.awsS3.bucketName');\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'awsS3' in your app config, \" +\n 'techdocs.publisher.awsS3.bucketName is required.',\n );\n }\n\n const bucketRootPath = normalizeExternalStorageRootPath(\n config.getOptionalString('techdocs.publisher.awsS3.bucketRootPath') || '',\n );\n\n const sse = config.getOptionalString('techdocs.publisher.awsS3.sse') as\n | 'aws:kms'\n | 'AES256'\n | undefined;\n\n // AWS Region is an optional config. If missing, default AWS env variable AWS_REGION\n // or AWS shared credentials file at ~/.aws/credentials will be used.\n const region = config.getOptionalString('techdocs.publisher.awsS3.region');\n\n // Credentials can optionally be configured by specifying the AWS account ID, which will retrieve credentials\n // for the account from the 'aws' section of the app config.\n // Credentials can also optionally be directly configured in the techdocs awsS3 config, but this method is\n // deprecated.\n // If no credentials are configured, the AWS SDK V3's default credential chain will be used.\n const accountId = config.getOptionalString(\n 'techdocs.publisher.awsS3.accountId',\n );\n const credentialsConfig = config.getOptionalConfig(\n 'techdocs.publisher.awsS3.credentials',\n );\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n const sdkCredentialProvider = await AwsS3Publish.buildCredentials(\n credsManager,\n accountId,\n credentialsConfig,\n region,\n );\n\n // AWS endpoint is an optional config. If missing, the default endpoint is built from\n // the configured region.\n const endpoint = config.getOptionalString(\n 'techdocs.publisher.awsS3.endpoint',\n );\n\n // AWS HTTPS proxy is an optional config. If missing, no proxy is used\n const httpsProxy = config.getOptionalString(\n 'techdocs.publisher.awsS3.httpsProxy',\n );\n\n // AWS forcePathStyle is an optional config. If missing, it defaults to false. Needs to be enabled for cases\n // where endpoint url points to locally hosted S3 compatible storage like Localstack\n const forcePathStyle = config.getOptionalBoolean(\n 'techdocs.publisher.awsS3.s3ForcePathStyle',\n );\n\n // AWS MAX ATTEMPTS is an optional config. If missing, default value of 3 is used\n const maxAttempts = config.getOptionalNumber(\n 'techdocs.publisher.awsS3.maxAttempts',\n );\n\n const storageClient = new S3Client({\n customUserAgent: 'backstage-aws-techdocs-s3-publisher',\n credentialDefaultProvider: () => sdkCredentialProvider,\n ...(region && { region }),\n ...(endpoint && { endpoint }),\n ...(forcePathStyle && { forcePathStyle }),\n ...(maxAttempts && { maxAttempts }),\n ...(httpsProxy && {\n requestHandler: new NodeHttpHandler({\n httpsAgent: new HttpsProxyAgent({ proxy: httpsProxy }),\n }),\n }),\n });\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n return new AwsS3Publish({\n storageClient,\n bucketName,\n bucketRootPath,\n legacyPathCasing,\n logger,\n sse,\n });\n }\n\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return Promise.resolve({\n accessKeyId,\n secretAccessKey,\n });\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n accountId?: string,\n config?: Config,\n region?: string,\n ): Promise<AwsCredentialIdentityProvider> {\n // Pull credentials for the specified account ID from the 'aws' config section\n if (accountId) {\n return (await credsManager.getCredentialProvider({ accountId }))\n .sdkCredentialProvider;\n }\n\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!config) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n // Pull credentials from the techdocs config section (deprecated)\n const accessKeyId = config.getOptionalString('accessKeyId');\n const secretAccessKey = config.getOptionalString('secretAccessKey');\n const explicitCredentials: AwsCredentialIdentityProvider =\n accessKeyId && secretAccessKey\n ? AwsS3Publish.buildStaticCredentials(accessKeyId, secretAccessKey)\n : (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n\n const roleArn = config.getOptionalString('roleArn');\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-techdocs-s3-publisher',\n RoleArn: roleArn,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n /**\n * Check if the defined bucket exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n await this.storageClient.send(\n new HeadBucketCommand({ Bucket: this.bucketName }),\n );\n\n this.logger.info(\n `Successfully connected to the AWS S3 bucket ${this.bucketName}.`,\n );\n\n return { isAvailable: true };\n } catch (error) {\n this.logger.error(\n `Could not retrieve metadata about the AWS S3 bucket ${this.bucketName}. ` +\n 'Make sure the bucket exists. Also make sure that authentication is setup either by ' +\n 'explicitly defining credentials and region in techdocs.publisher.awsS3 in app config or ' +\n 'by using environment variables. Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n this.logger.error(`from AWS client library`, error);\n return {\n isAvailable: false,\n };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the S3 bucket.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n const bucketRootPath = this.bucketRootPath;\n const sse = this.sse;\n\n // First, try to retrieve a list of all individual files currently existing\n let existingFiles: string[] = [];\n try {\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n bucketRootPath,\n );\n existingFiles = await this.getAllObjectsFromBucket({\n prefix: remoteFolder,\n });\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.relative(directory, absoluteFilePath);\n const fileStream = fs.createReadStream(absoluteFilePath);\n\n const params: PutObjectCommandInput = {\n Bucket: this.bucketName,\n Key: getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n bucketRootPath,\n ),\n Body: fileStream,\n ...(sse && { ServerSideEncryption: sse }),\n };\n\n objects.push(params.Key!);\n\n const upload = new Upload({\n client: this.storageClient,\n params,\n });\n return upload.done();\n },\n absoluteFilesToUpload,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to AWS S3. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n bucketRootPath,\n ),\n );\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: relativeFilePath,\n }),\n );\n },\n staleFiles,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from AWS S3. ${error}`;\n this.logger.error(errorMessage);\n }\n return { objects };\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n try {\n return await new Promise<TechDocsMetadata>(async (resolve, reject) => {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {\n this.logger.error(\n `Invalid content path found while fetching TechDocs metadata: ${entityRootDir}`,\n );\n throw new Error(`Metadata Not Found`);\n }\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/techdocs_metadata.json`,\n }),\n );\n\n const techdocsMetadataJson = await streamToBuffer(\n resp.Body as Readable,\n );\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n\n resolve(techdocsMetadata);\n } catch (err) {\n assertError(err);\n this.logger.error(err.message);\n reject(new Error(err.message));\n }\n });\n } catch (e) {\n throw new ForwardedError('TechDocs metadata fetch failed', e);\n }\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return async (req, res) => {\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/component/documented-component/index.html\n const filePathNoRoot = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Prepend the root path to the relative file path\n const filePath = path.posix.join(this.bucketRootPath, filePathNoRoot);\n if (!isValidContentPath(this.bucketRootPath, filePath)) {\n this.logger.error(\n `Attempted to fetch TechDocs content for a file outside of the bucket root: ${filePathNoRoot}`,\n );\n res.status(404).send('File Not Found');\n return;\n }\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({ Bucket: this.bucketName, Key: filePath }),\n );\n\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n\n res.send(await streamToBuffer(resp.Body as Readable));\n } catch (err) {\n assertError(err);\n this.logger.warn(\n `TechDocs S3 router failed to serve static files from bucket ${this.bucketName} at key ${filePath}: ${err.message}`,\n );\n res.status(404).send('File Not Found');\n }\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n try {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {\n this.logger.error(\n `Invalid content path found while checking if docs have been generated: ${entityRootDir}`,\n );\n return Promise.resolve(false);\n }\n\n await this.storageClient.send(\n new HeadObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/index.html`,\n }),\n );\n return Promise.resolve(true);\n } catch (e) {\n return Promise.resolve(false);\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const allObjects = await this.getAllObjectsFromBucket();\n const limiter = createLimiter(concurrency);\n await Promise.all(\n allObjects.map(f =>\n limiter(async file => {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(file);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (file === newPath) {\n return;\n }\n\n try {\n this.logger.debug(`Migrating ${file}`);\n await this.storageClient.send(\n new CopyObjectCommand({\n Bucket: this.bucketName,\n CopySource: [this.bucketName, file].join('/'),\n Key: newPath,\n }),\n );\n\n if (removeOriginal) {\n await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: file,\n }),\n );\n }\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${file}: ${e.message}`);\n }\n }, f),\n ),\n );\n }\n\n /**\n * Returns a list of all object keys from the configured bucket.\n */\n protected async getAllObjectsFromBucket(\n { prefix } = { prefix: '' },\n ): Promise<string[]> {\n const objects: string[] = [];\n let nextContinuation: string | undefined;\n let allObjects: ListObjectsV2CommandOutput;\n // Iterate through every file in the root of the publisher.\n do {\n allObjects = await this.storageClient.send(\n new ListObjectsV2Command({\n Bucket: this.bucketName,\n ContinuationToken: nextContinuation,\n ...(prefix ? { Prefix: prefix } : {}),\n }),\n );\n objects.push(\n ...(allObjects.Contents || []).map(f => f.Key || '').filter(f => !!f),\n );\n nextContinuation = allObjects.NextContinuationToken;\n } while (nextContinuation);\n\n return objects;\n }\n}\n"],"names":["ForwardedError","normalizeExternalStorageRootPath","DefaultAwsCredentialsManager","S3Client","NodeHttpHandler","HttpsProxyAgent","fromTemporaryCredentials","HeadBucketCommand","getCloudPathForLocalPath","assertError","getFileTreeRecursively","bulkStorageOperation","path","fs","Upload","getStaleFiles","DeleteObjectCommand","lowerCaseEntityTriplet","isValidContentPath","GetObjectCommand","JSON5","lowerCaseEntityTripletInStoragePath","getHeadersForFileExtension","HeadObjectCommand","createLimiter","CopyObjectCommand","ListObjectsV2Command"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"awsS3.cjs.js","sources":["../../../src/stages/publish/awsS3.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Entity, CompoundEntityRef } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { assertError, ForwardedError } from '@backstage/errors';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n GetObjectCommand,\n CopyObjectCommand,\n DeleteObjectCommand,\n HeadBucketCommand,\n HeadObjectCommand,\n PutObjectCommandInput,\n ListObjectsV2CommandOutput,\n ListObjectsV2Command,\n S3Client,\n} from '@aws-sdk/client-s3';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\nimport { Upload } from '@aws-sdk/lib-storage';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { HttpsProxyAgent } from 'hpagent';\nimport express from 'express';\nimport fs from 'fs-extra';\nimport JSON5 from 'json5';\nimport createLimiter from 'p-limit';\nimport path from 'path';\nimport { Readable } from 'stream';\nimport {\n bulkStorageOperation,\n getCloudPathForLocalPath,\n getFileTreeRecursively,\n getHeadersForFileExtension,\n getStaleFiles,\n isValidContentPath,\n lowerCaseEntityTriplet,\n lowerCaseEntityTripletInStoragePath,\n normalizeExternalStorageRootPath,\n} from './helpers';\nimport {\n PublisherBase,\n PublishRequest,\n PublishResponse,\n ReadinessResponse,\n TechDocsMetadata,\n} from './types';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nconst streamToBuffer = (stream: Readable): Promise<Buffer> => {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', (e: Error) =>\n reject(new ForwardedError('Unable to read stream', e)),\n );\n stream.on('end', () => resolve(Buffer.concat(chunks)));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n};\n\nexport class AwsS3Publish implements PublisherBase {\n private readonly storageClient: S3Client;\n private readonly bucketName: string;\n private readonly legacyPathCasing: boolean;\n private readonly logger: LoggerService;\n private readonly bucketRootPath: string;\n private readonly sse?: 'aws:kms' | 'AES256';\n\n constructor(options: {\n storageClient: S3Client;\n bucketName: string;\n legacyPathCasing: boolean;\n logger: LoggerService;\n bucketRootPath: string;\n sse?: 'aws:kms' | 'AES256';\n }) {\n this.storageClient = options.storageClient;\n this.bucketName = options.bucketName;\n this.legacyPathCasing = options.legacyPathCasing;\n this.logger = options.logger;\n this.bucketRootPath = options.bucketRootPath;\n this.sse = options.sse;\n }\n\n static async fromConfig(\n config: Config,\n logger: LoggerService,\n ): Promise<PublisherBase> {\n let bucketName = '';\n try {\n bucketName = config.getString('techdocs.publisher.awsS3.bucketName');\n } catch (error) {\n throw new Error(\n \"Since techdocs.publisher.type is set to 'awsS3' in your app config, \" +\n 'techdocs.publisher.awsS3.bucketName is required.',\n );\n }\n\n const bucketRootPath = normalizeExternalStorageRootPath(\n config.getOptionalString('techdocs.publisher.awsS3.bucketRootPath') || '',\n );\n\n const sse = config.getOptionalString('techdocs.publisher.awsS3.sse') as\n | 'aws:kms'\n | 'AES256'\n | undefined;\n\n // AWS Region is an optional config. If missing, default AWS env variable AWS_REGION\n // or AWS shared credentials file at ~/.aws/credentials will be used.\n const region = config.getOptionalString('techdocs.publisher.awsS3.region');\n\n // Credentials can optionally be configured by specifying the AWS account ID, which will retrieve credentials\n // for the account from the 'aws' section of the app config.\n // Credentials can also optionally be directly configured in the techdocs awsS3 config, but this method is\n // deprecated.\n // If no credentials are configured, the AWS SDK V3's default credential chain will be used.\n const accountId = config.getOptionalString(\n 'techdocs.publisher.awsS3.accountId',\n );\n const credentialsConfig = config.getOptionalConfig(\n 'techdocs.publisher.awsS3.credentials',\n );\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n const sdkCredentialProvider = await AwsS3Publish.buildCredentials(\n credsManager,\n accountId,\n credentialsConfig,\n region,\n );\n\n // AWS endpoint is an optional config. If missing, the default endpoint is built from\n // the configured region.\n const endpoint = config.getOptionalString(\n 'techdocs.publisher.awsS3.endpoint',\n );\n\n // AWS HTTPS proxy is an optional config. If missing, no proxy is used\n const httpsProxy = config.getOptionalString(\n 'techdocs.publisher.awsS3.httpsProxy',\n );\n\n // AWS forcePathStyle is an optional config. If missing, it defaults to false. Needs to be enabled for cases\n // where endpoint url points to locally hosted S3 compatible storage like Localstack\n const forcePathStyle = config.getOptionalBoolean(\n 'techdocs.publisher.awsS3.s3ForcePathStyle',\n );\n\n // AWS MAX ATTEMPTS is an optional config. If missing, default value of 3 is used\n const maxAttempts = config.getOptionalNumber(\n 'techdocs.publisher.awsS3.maxAttempts',\n );\n\n const storageClient = new S3Client({\n customUserAgent: 'backstage-aws-techdocs-s3-publisher',\n credentialDefaultProvider: () => sdkCredentialProvider,\n ...(region && { region }),\n ...(endpoint && { endpoint }),\n ...(forcePathStyle && { forcePathStyle }),\n ...(maxAttempts && { maxAttempts }),\n ...(httpsProxy && {\n requestHandler: new NodeHttpHandler({\n httpsAgent: new HttpsProxyAgent({ proxy: httpsProxy }),\n }),\n }),\n });\n\n const legacyPathCasing =\n config.getOptionalBoolean(\n 'techdocs.legacyUseCaseSensitiveTripletPaths',\n ) || false;\n\n return new AwsS3Publish({\n storageClient,\n bucketName,\n bucketRootPath,\n legacyPathCasing,\n logger,\n sse,\n });\n }\n\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return Promise.resolve({\n accessKeyId,\n secretAccessKey,\n });\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n accountId?: string,\n config?: Config,\n region?: string,\n ): Promise<AwsCredentialIdentityProvider> {\n // Pull credentials for the specified account ID from the 'aws' config section\n if (accountId) {\n return (await credsManager.getCredentialProvider({ accountId }))\n .sdkCredentialProvider;\n }\n\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!config) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n // Pull credentials from the techdocs config section (deprecated)\n const accessKeyId = config.getOptionalString('accessKeyId');\n const secretAccessKey = config.getOptionalString('secretAccessKey');\n const explicitCredentials: AwsCredentialIdentityProvider =\n accessKeyId && secretAccessKey\n ? AwsS3Publish.buildStaticCredentials(accessKeyId, secretAccessKey)\n : (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n\n const roleArn = config.getOptionalString('roleArn');\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-techdocs-s3-publisher',\n RoleArn: roleArn,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n /**\n * Check if the defined bucket exists. Being able to connect means the configuration is good\n * and the storage client will work.\n */\n async getReadiness(): Promise<ReadinessResponse> {\n try {\n await this.storageClient.send(\n new HeadBucketCommand({ Bucket: this.bucketName }),\n );\n\n this.logger.info(\n `Successfully connected to the AWS S3 bucket ${this.bucketName}.`,\n );\n\n return { isAvailable: true };\n } catch (error) {\n this.logger.error(\n `Could not retrieve metadata about the AWS S3 bucket ${this.bucketName}. ` +\n 'Make sure the bucket exists. Also make sure that authentication is setup either by ' +\n 'explicitly defining credentials and region in techdocs.publisher.awsS3 in app config or ' +\n 'by using environment variables. Refer to https://backstage.io/docs/features/techdocs/using-cloud-storage',\n );\n this.logger.error(`from AWS client library`, error);\n return {\n isAvailable: false,\n };\n }\n }\n\n /**\n * Upload all the files from the generated `directory` to the S3 bucket.\n * Directory structure used in the bucket is - entityNamespace/entityKind/entityName/index.html\n */\n async publish({\n entity,\n directory,\n }: PublishRequest): Promise<PublishResponse> {\n const objects: string[] = [];\n const useLegacyPathCasing = this.legacyPathCasing;\n const bucketRootPath = this.bucketRootPath;\n const sse = this.sse;\n\n // First, try to retrieve a list of all individual files currently existing\n let existingFiles: string[] = [];\n try {\n const remoteFolder = getCloudPathForLocalPath(\n entity,\n undefined,\n useLegacyPathCasing,\n bucketRootPath,\n );\n existingFiles = await this.getAllObjectsFromBucket({\n prefix: remoteFolder,\n });\n } catch (e) {\n assertError(e);\n this.logger.error(\n `Unable to list files for Entity ${entity.metadata.name}: ${e.message}`,\n );\n }\n\n // Then, merge new files into the same folder\n let absoluteFilesToUpload;\n try {\n // Remove the absolute path prefix of the source directory\n // Path of all files to upload, relative to the root of the source directory\n // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png']\n absoluteFilesToUpload = await getFileTreeRecursively(directory);\n\n await bulkStorageOperation(\n async absoluteFilePath => {\n const relativeFilePath = path.relative(directory, absoluteFilePath);\n const fileStream = fs.createReadStream(absoluteFilePath);\n\n const params: PutObjectCommandInput = {\n Bucket: this.bucketName,\n Key: getCloudPathForLocalPath(\n entity,\n relativeFilePath,\n useLegacyPathCasing,\n bucketRootPath,\n ),\n Body: fileStream,\n ...(sse && { ServerSideEncryption: sse }),\n };\n\n objects.push(params.Key!);\n\n const upload = new Upload({\n client: this.storageClient,\n params,\n });\n return upload.done();\n },\n absoluteFilesToUpload,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully uploaded all the generated files for Entity ${entity.metadata.name}. Total number of files: ${absoluteFilesToUpload.length}`,\n );\n } catch (e) {\n const errorMessage = `Unable to upload file(s) to AWS S3. ${e}`;\n this.logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n // Last, try to remove the files that were *only* present previously\n try {\n const relativeFilesToUpload = absoluteFilesToUpload.map(\n absoluteFilePath =>\n getCloudPathForLocalPath(\n entity,\n path.relative(directory, absoluteFilePath),\n useLegacyPathCasing,\n bucketRootPath,\n ),\n );\n const staleFiles = getStaleFiles(relativeFilesToUpload, existingFiles);\n\n await bulkStorageOperation(\n async relativeFilePath => {\n return await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: relativeFilePath,\n }),\n );\n },\n staleFiles,\n { concurrencyLimit: 10 },\n );\n\n this.logger.info(\n `Successfully deleted stale files for Entity ${entity.metadata.name}. Total number of files: ${staleFiles.length}`,\n );\n } catch (error) {\n const errorMessage = `Unable to delete file(s) from AWS S3. ${error}`;\n this.logger.error(errorMessage);\n }\n return { objects };\n }\n\n async fetchTechDocsMetadata(\n entityName: CompoundEntityRef,\n ): Promise<TechDocsMetadata> {\n try {\n return await new Promise<TechDocsMetadata>(async (resolve, reject) => {\n const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {\n this.logger.error(\n `Invalid content path found while fetching TechDocs metadata: ${entityRootDir}`,\n );\n throw new Error(`Metadata Not Found`);\n }\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/techdocs_metadata.json`,\n }),\n );\n\n const techdocsMetadataJson = await streamToBuffer(\n resp.Body as Readable,\n );\n if (!techdocsMetadataJson) {\n throw new Error(\n `Unable to parse the techdocs metadata file ${entityRootDir}/techdocs_metadata.json.`,\n );\n }\n\n const techdocsMetadata = JSON5.parse(\n techdocsMetadataJson.toString('utf-8'),\n );\n\n resolve(techdocsMetadata);\n } catch (err) {\n assertError(err);\n this.logger.error(err.message);\n reject(new Error(err.message));\n }\n });\n } catch (e) {\n throw new ForwardedError('TechDocs metadata fetch failed', e);\n }\n }\n\n /**\n * Express route middleware to serve static files on a route in techdocs-backend.\n */\n docsRouter(): express.Handler {\n return async (req, res) => {\n const decodedUri = decodeURI(req.path.replace(/^\\//, ''));\n\n // filePath example - /default/component/documented-component/index.html\n const filePathNoRoot = this.legacyPathCasing\n ? decodedUri\n : lowerCaseEntityTripletInStoragePath(decodedUri);\n\n // Prepend the root path to the relative file path\n const filePath = path.posix.join(this.bucketRootPath, filePathNoRoot);\n if (!isValidContentPath(this.bucketRootPath, filePath)) {\n this.logger.error(\n `Attempted to fetch TechDocs content for a file outside of the bucket root: ${filePathNoRoot}`,\n );\n res.status(404).send('File Not Found');\n return;\n }\n\n // Files with different extensions (CSS, HTML) need to be served with different headers\n const fileExtension = path.extname(filePath);\n const responseHeaders = getHeadersForFileExtension(fileExtension);\n\n try {\n const resp = await this.storageClient.send(\n new GetObjectCommand({ Bucket: this.bucketName, Key: filePath }),\n );\n\n // Inject response headers\n for (const [headerKey, headerValue] of Object.entries(\n responseHeaders,\n )) {\n res.setHeader(headerKey, headerValue);\n }\n\n (resp.Body as Readable)\n .on('error', err => {\n this.logger.warn(\n `TechDocs S3 router failed to serve static files from bucket ${this.bucketName} at key ${filePath}: ${err.message}`,\n );\n if (!res.headersSent) {\n res.status(404).send('File Not Found');\n } else {\n res.destroy();\n }\n })\n .pipe(res);\n } catch (err) {\n assertError(err);\n this.logger.warn(\n `TechDocs S3 router failed to serve static files from bucket ${this.bucketName} at key ${filePath}: ${err.message}`,\n );\n res.status(404).send('File Not Found');\n }\n };\n }\n\n /**\n * A helper function which checks if index.html of an Entity's docs site is available. This\n * can be used to verify if there are any pre-generated docs available to serve.\n */\n async hasDocsBeenGenerated(entity: Entity): Promise<boolean> {\n try {\n const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;\n const entityDir = this.legacyPathCasing\n ? entityTriplet\n : lowerCaseEntityTriplet(entityTriplet);\n\n const entityRootDir = path.posix.join(this.bucketRootPath, entityDir);\n if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {\n this.logger.error(\n `Invalid content path found while checking if docs have been generated: ${entityRootDir}`,\n );\n return Promise.resolve(false);\n }\n\n await this.storageClient.send(\n new HeadObjectCommand({\n Bucket: this.bucketName,\n Key: `${entityRootDir}/index.html`,\n }),\n );\n return Promise.resolve(true);\n } catch (e) {\n return Promise.resolve(false);\n }\n }\n\n async migrateDocsCase({\n removeOriginal = false,\n concurrency = 25,\n }): Promise<void> {\n // Iterate through every file in the root of the publisher.\n const allObjects = await this.getAllObjectsFromBucket();\n const limiter = createLimiter(concurrency);\n await Promise.all(\n allObjects.map(f =>\n limiter(async file => {\n let newPath;\n try {\n newPath = lowerCaseEntityTripletInStoragePath(file);\n } catch (e) {\n assertError(e);\n this.logger.warn(e.message);\n return;\n }\n\n // If all parts are already lowercase, ignore.\n if (file === newPath) {\n return;\n }\n\n try {\n this.logger.debug(`Migrating ${file}`);\n await this.storageClient.send(\n new CopyObjectCommand({\n Bucket: this.bucketName,\n CopySource: [this.bucketName, file].join('/'),\n Key: newPath,\n }),\n );\n\n if (removeOriginal) {\n await this.storageClient.send(\n new DeleteObjectCommand({\n Bucket: this.bucketName,\n Key: file,\n }),\n );\n }\n } catch (e) {\n assertError(e);\n this.logger.warn(`Unable to migrate ${file}: ${e.message}`);\n }\n }, f),\n ),\n );\n }\n\n /**\n * Returns a list of all object keys from the configured bucket.\n */\n protected async getAllObjectsFromBucket(\n { prefix } = { prefix: '' },\n ): Promise<string[]> {\n const objects: string[] = [];\n let nextContinuation: string | undefined;\n let allObjects: ListObjectsV2CommandOutput;\n // Iterate through every file in the root of the publisher.\n do {\n allObjects = await this.storageClient.send(\n new ListObjectsV2Command({\n Bucket: this.bucketName,\n ContinuationToken: nextContinuation,\n ...(prefix ? { Prefix: prefix } : {}),\n }),\n );\n objects.push(\n ...(allObjects.Contents || []).map(f => f.Key || '').filter(f => !!f),\n );\n nextContinuation = allObjects.NextContinuationToken;\n } while (nextContinuation);\n\n return objects;\n }\n}\n"],"names":["ForwardedError","normalizeExternalStorageRootPath","DefaultAwsCredentialsManager","S3Client","NodeHttpHandler","HttpsProxyAgent","fromTemporaryCredentials","HeadBucketCommand","getCloudPathForLocalPath","assertError","getFileTreeRecursively","bulkStorageOperation","path","fs","Upload","getStaleFiles","DeleteObjectCommand","lowerCaseEntityTriplet","isValidContentPath","GetObjectCommand","JSON5","lowerCaseEntityTripletInStoragePath","getHeadersForFileExtension","HeadObjectCommand","createLimiter","CopyObjectCommand","ListObjectsV2Command"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-techdocs-node",
|
|
3
|
-
"version": "1.13.1",
|
|
3
|
+
"version": "1.13.2-next.1",
|
|
4
4
|
"description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library",
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
"@aws-sdk/types": "^3.347.0",
|
|
54
54
|
"@azure/identity": "^4.0.0",
|
|
55
55
|
"@azure/storage-blob": "^12.5.0",
|
|
56
|
-
"@backstage/backend-plugin-api": "
|
|
57
|
-
"@backstage/catalog-model": "
|
|
58
|
-
"@backstage/config": "
|
|
59
|
-
"@backstage/errors": "
|
|
60
|
-
"@backstage/integration": "
|
|
61
|
-
"@backstage/integration-aws-node": "
|
|
62
|
-
"@backstage/plugin-search-common": "
|
|
63
|
-
"@backstage/plugin-techdocs-common": "
|
|
56
|
+
"@backstage/backend-plugin-api": "1.2.1",
|
|
57
|
+
"@backstage/catalog-model": "1.7.3",
|
|
58
|
+
"@backstage/config": "1.3.2",
|
|
59
|
+
"@backstage/errors": "1.2.7",
|
|
60
|
+
"@backstage/integration": "1.16.3-next.0",
|
|
61
|
+
"@backstage/integration-aws-node": "0.1.15",
|
|
62
|
+
"@backstage/plugin-search-common": "1.2.17",
|
|
63
|
+
"@backstage/plugin-techdocs-common": "0.1.0",
|
|
64
64
|
"@google-cloud/storage": "^7.0.0",
|
|
65
65
|
"@smithy/node-http-handler": "^3.0.0",
|
|
66
66
|
"@trendyol-js/openstack-swift-sdk": "^0.0.7",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"winston": "^3.2.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@backstage/backend-test-utils": "
|
|
82
|
-
"@backstage/cli": "
|
|
81
|
+
"@backstage/backend-test-utils": "1.3.2-next.1",
|
|
82
|
+
"@backstage/cli": "0.32.0-next.1",
|
|
83
83
|
"@types/fs-extra": "^11.0.0",
|
|
84
84
|
"@types/js-yaml": "^4.0.0",
|
|
85
85
|
"@types/mime-types": "^2.1.0",
|