@causa/workspace-google 1.3.1 → 1.4.0-beta.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/README.md +9 -0
- package/dist/functions/event-topic/create-backfill-source-bigquery.call.js +2 -2
- package/dist/functions/event-topic/query-events-bigquery.call.js +2 -2
- package/dist/functions/google-firestore/generate-typescript-decorators.js +2 -1
- package/dist/functions/google-pubsub/index.d.ts +1 -1
- package/dist/functions/google-pubsub/index.js +1 -1
- package/dist/functions/google-pubsub/write-topics.d.ts +7 -0
- package/dist/functions/google-pubsub/write-topics.js +10 -1
- package/dist/functions/google-spanner/generate-typescript-decorators.js +2 -1
- package/dist/functions/google-spanner/list-databases.d.ts +1 -1
- package/dist/functions/graph/index.d.ts +1 -0
- package/dist/functions/graph/index.js +1 -0
- package/dist/functions/graph/list-rules.d.ts +11 -0
- package/dist/functions/graph/list-rules.js +16 -0
- package/dist/functions/index.js +2 -1
- package/dist/graph/cloud-run.d.ts +98 -0
- package/dist/graph/cloud-run.js +102 -0
- package/dist/graph/ids.d.ts +35 -0
- package/dist/graph/ids.js +44 -0
- package/dist/graph/index.d.ts +6 -0
- package/dist/graph/index.js +6 -0
- package/dist/graph/rules/configuration/enqueues-assumed-from-google-task-trigger.d.ts +6 -0
- package/dist/graph/rules/configuration/enqueues-assumed-from-google-task-trigger.js +39 -0
- package/dist/graph/rules/configuration/firestore.d.ts +11 -0
- package/dist/graph/rules/configuration/firestore.js +93 -0
- package/dist/graph/rules/configuration/index.d.ts +5 -0
- package/dist/graph/rules/configuration/index.js +11 -0
- package/dist/graph/rules/configuration/service-container.d.ts +13 -0
- package/dist/graph/rules/configuration/service-container.js +123 -0
- package/dist/graph/rules/terraform/api-router.d.ts +15 -0
- package/dist/graph/rules/terraform/api-router.js +117 -0
- package/dist/graph/rules/terraform/cloud-run-cron-triggers.d.ts +11 -0
- package/dist/graph/rules/terraform/cloud-run-cron-triggers.js +67 -0
- package/dist/graph/rules/terraform/cloud-run-grants.d.ts +16 -0
- package/dist/graph/rules/terraform/cloud-run-grants.js +118 -0
- package/dist/graph/rules/terraform/cloud-run-module.d.ts +6 -0
- package/dist/graph/rules/terraform/cloud-run-module.js +29 -0
- package/dist/graph/rules/terraform/cloud-run-pubsub-triggers.d.ts +14 -0
- package/dist/graph/rules/terraform/cloud-run-pubsub-triggers.js +103 -0
- package/dist/graph/rules/terraform/cloud-run-services.d.ts +12 -0
- package/dist/graph/rules/terraform/cloud-run-services.js +61 -0
- package/dist/graph/rules/terraform/cloud-run-tasks-triggers.d.ts +14 -0
- package/dist/graph/rules/terraform/cloud-run-tasks-triggers.js +97 -0
- package/dist/graph/rules/terraform/event-topics.d.ts +18 -0
- package/dist/graph/rules/terraform/event-topics.js +193 -0
- package/dist/graph/rules/terraform/index.d.ts +5 -0
- package/dist/graph/rules/terraform/index.js +13 -0
- package/dist/graph/rules/terraform/spanner-databases.d.ts +17 -0
- package/dist/graph/rules/terraform/spanner-databases.js +180 -0
- package/dist/graph/spanner.d.ts +106 -0
- package/dist/graph/spanner.js +118 -0
- package/dist/graph/terraform-modules.d.ts +87 -0
- package/dist/graph/terraform-modules.js +107 -0
- package/package.json +27 -26
package/README.md
CHANGED
|
@@ -74,6 +74,15 @@ This module implements the `DatabaseQueryRecords`, `ServiceContainerQueryLogs`,
|
|
|
74
74
|
- `ServiceContainerQueryLogs` is supported when `serviceContainer.platform` is `google.cloudRun`. It queries Cloud Logging for log entries emitted by the service's Cloud Run revisions. By default, only the last hour of logs and up to 1 000 entries are returned.
|
|
75
75
|
- `EventTopicQueryEvents` is supported when `events.broker` is `google.pubSub`, `events.format` is `json`, and `google.pubSub.bigQueryStorage.rawEventsDatasetId` is set. It reads events from the topic's BigQuery raw events table. Same defaults as for log queries: last hour and up to 1 000 events.
|
|
76
76
|
|
|
77
|
+
### Architecture graph
|
|
78
|
+
|
|
79
|
+
This module contributes to the architecture graph extracted by `cs graph extract` (see the core module):
|
|
80
|
+
|
|
81
|
+
- Some rules read the workspace configuration and model: the Firestore database and the collections schemas bind to (`firestoreFromConfiguration`), the triggers of type `google.pubSub` and the entities projects access through the databases and collections listed in `serviceContainer.outputs` (`googleServiceContainerFromConfiguration`), and the triggers of type `google.task(s)`.
|
|
82
|
+
- Other rules mirror the resources created by the Causa Terraform modules for Google Cloud, one rule per module (Cloud Run services, event topics, Spanner databases, and API router), by joining the arguments of their blocks with the configuration the modules read. Each resource is linked by a `deploys` edge from the projects applying the block.
|
|
83
|
+
|
|
84
|
+
Infrastructure nodes carry the Google Cloud resource they stand for in `data.resource`: its `type` (e.g. `pubsub.googleapis.com/Topic`), its `id`, i.e. its full resource name (or `idPrefix` when the full name is not known), and the `scope`, i.e. the project whose configuration should be used to render the identifier.
|
|
85
|
+
|
|
77
86
|
### Secrets backend
|
|
78
87
|
|
|
79
88
|
This module implements the `google.secretManager` secret backend, allowing fetching secrets from the Google Secret Manager service. Here are some example of how secrets with the `google.secretManager` backend should be defined:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BigQueryService } from '../../services/index.js';
|
|
2
|
+
import { rawEventsTableName } from '../google-pubsub/index.js';
|
|
2
3
|
import { BIGQUERY_SOURCE_REGEX, } from './create-backfill-source-bigquery.js';
|
|
3
4
|
/**
|
|
4
5
|
* Resolves the full BigQuery table ID from the function arguments and configuration.
|
|
@@ -18,8 +19,7 @@ function resolveTableId(self, context) {
|
|
|
18
19
|
const googleConf = context.asConfiguration();
|
|
19
20
|
const projectId = googleConf.getOrThrow('google.project');
|
|
20
21
|
const rawEventsDatasetId = googleConf.getOrThrow('google.pubSub.bigQueryStorage.rawEventsDatasetId');
|
|
21
|
-
|
|
22
|
-
return `${projectId}.${rawEventsDatasetId}.${tableName}`;
|
|
22
|
+
return `${projectId}.${rawEventsDatasetId}.${rawEventsTableName(self.eventTopic)}`;
|
|
23
23
|
}
|
|
24
24
|
export default async function call() {
|
|
25
25
|
const tableId = resolveTableId(this, this._context);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BigQueryService } from '../../services/index.js';
|
|
2
|
+
import { rawEventsTableName } from '../google-pubsub/index.js';
|
|
2
3
|
/**
|
|
3
4
|
* The default duration applied to `from` when it is not set, in milliseconds.
|
|
4
5
|
*/
|
|
@@ -13,8 +14,7 @@ export default async function call() {
|
|
|
13
14
|
const googleConf = this._context.asConfiguration();
|
|
14
15
|
const projectId = googleConf.getOrThrow('google.project');
|
|
15
16
|
const rawEventsDatasetId = googleConf.getOrThrow('google.pubSub.bigQueryStorage.rawEventsDatasetId');
|
|
16
|
-
const
|
|
17
|
-
const tableId = `${projectId}.${rawEventsDatasetId}.${tableName}`;
|
|
17
|
+
const tableId = `${projectId}.${rawEventsDatasetId}.${rawEventsTableName(this.topic)}`;
|
|
18
18
|
const conditions = [`publish_time >= @from`];
|
|
19
19
|
const params = { from: from.toISOString() };
|
|
20
20
|
if (this.to) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { splitSchemaPath } from '@causa/workspace-core/jsonschema';
|
|
1
2
|
import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
|
|
2
3
|
import { addDecoratorToList, } from '@causa/workspace-typescript/code-generation';
|
|
3
4
|
import micromatch from 'micromatch';
|
|
@@ -32,7 +33,7 @@ export class ModelGenerateTypeScriptDecoratorsForGoogleFirestore extends ModelGe
|
|
|
32
33
|
if (Array.isArray(globs)) {
|
|
33
34
|
const projectPath = this._context.getProjectPathOrThrow();
|
|
34
35
|
const absoluteGlobs = globs.map((g) => join(projectPath, g));
|
|
35
|
-
const schemaPath = this.schema.path
|
|
36
|
+
const { file: schemaPath } = splitSchemaPath(this.schema.path);
|
|
36
37
|
if (!micromatch.isMatch(schemaPath, absoluteGlobs)) {
|
|
37
38
|
return [];
|
|
38
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { GooglePubSubWriteTopics } from './write-topics.js';
|
|
1
|
+
export { GooglePubSubWriteTopics, rawEventsTableName } from './write-topics.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { GooglePubSubWriteTopics } from './write-topics.js';
|
|
1
|
+
export { GooglePubSubWriteTopics, rawEventsTableName } from './write-topics.js';
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { type ProcessorResult, WorkspaceFunction } from '@causa/workspace';
|
|
2
2
|
import { type InfrastructureProcessor } from '@causa/workspace-core';
|
|
3
|
+
/**
|
|
4
|
+
* Returns the name of the BigQuery table storing the raw events of a topic.
|
|
5
|
+
*
|
|
6
|
+
* @param topic The ID of the topic.
|
|
7
|
+
* @returns The name of the BigQuery table.
|
|
8
|
+
*/
|
|
9
|
+
export declare function rawEventsTableName(topic: string): string;
|
|
3
10
|
/**
|
|
4
11
|
* A function that uses {@link EventTopicList} to find all the topics in the workspace, and writes their configurations
|
|
5
12
|
* to a directory.
|
|
@@ -18,6 +18,15 @@ import { join } from 'path';
|
|
|
18
18
|
* The default directory where Pub/Sub topic configurations are written, relative to the workspace root.
|
|
19
19
|
*/
|
|
20
20
|
const DEFAULT_TOPIC_CONFIGURATIONS_DIRECTORY = join(CAUSA_FOLDER, 'pubsub-topics');
|
|
21
|
+
/**
|
|
22
|
+
* Returns the name of the BigQuery table storing the raw events of a topic.
|
|
23
|
+
*
|
|
24
|
+
* @param topic The ID of the topic.
|
|
25
|
+
* @returns The name of the BigQuery table.
|
|
26
|
+
*/
|
|
27
|
+
export function rawEventsTableName(topic) {
|
|
28
|
+
return topic.replace(/[-.]/g, '_');
|
|
29
|
+
}
|
|
21
30
|
/**
|
|
22
31
|
* A function that uses {@link EventTopicList} to find all the topics in the workspace, and writes their configurations
|
|
23
32
|
* to a directory.
|
|
@@ -56,7 +65,7 @@ export class GooglePubSubWriteTopics extends WorkspaceFunction {
|
|
|
56
65
|
await Promise.all(topics.map(async (topic) => {
|
|
57
66
|
const topicConfiguration = {
|
|
58
67
|
...topic,
|
|
59
|
-
bigQueryTableName: topic.id
|
|
68
|
+
bigQueryTableName: rawEventsTableName(topic.id),
|
|
60
69
|
};
|
|
61
70
|
const topicFile = join(absoluteDir, `${topic.id}.json`);
|
|
62
71
|
await writeFile(topicFile, JSON.stringify(topicConfiguration));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { splitSchemaPath } from '@causa/workspace-core/jsonschema';
|
|
1
2
|
import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
|
|
2
3
|
import { addDecoratorToList, } from '@causa/workspace-typescript/code-generation';
|
|
3
4
|
import micromatch from 'micromatch';
|
|
@@ -41,7 +42,7 @@ export class ModelGenerateTypeScriptDecoratorsForGoogleSpanner extends ModelGene
|
|
|
41
42
|
if (Array.isArray(globs)) {
|
|
42
43
|
const projectPath = this._context.getProjectPathOrThrow();
|
|
43
44
|
const absoluteGlobs = globs.map((g) => join(projectPath, g));
|
|
44
|
-
const schemaPath = this.schema.path
|
|
45
|
+
const { file: schemaPath } = splitSchemaPath(this.schema.path);
|
|
45
46
|
if (!micromatch.isMatch(schemaPath, absoluteGlobs)) {
|
|
46
47
|
return [];
|
|
47
48
|
}
|
|
@@ -8,7 +8,7 @@ export type SpannerDatabase = {
|
|
|
8
8
|
*/
|
|
9
9
|
id: string;
|
|
10
10
|
/**
|
|
11
|
-
* The paths
|
|
11
|
+
* The absolute paths of the files containing DDL statements for this database.
|
|
12
12
|
*/
|
|
13
13
|
ddlFiles: string[];
|
|
14
14
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { GraphListRulesForGoogle } from './list-rules.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { GraphListRulesForGoogle } from './list-rules.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GraphListRules, type GraphRule } from '@causa/workspace-core';
|
|
2
|
+
/**
|
|
3
|
+
* Implements {@link GraphListRules} for Google Cloud.
|
|
4
|
+
* The rules read the Google-specific parts of the workspace configuration and model (Firestore collections, the
|
|
5
|
+
* entities projects access through their `google.*` outputs, triggers of Google-specific types), and mirror the
|
|
6
|
+
* resources created by the Causa Terraform modules for Google Cloud.
|
|
7
|
+
*/
|
|
8
|
+
export declare class GraphListRulesForGoogle extends GraphListRules {
|
|
9
|
+
_call(): GraphRule[];
|
|
10
|
+
_supports(): boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GraphListRules } from '@causa/workspace-core';
|
|
2
|
+
import { GOOGLE_GRAPH_RULES, GOOGLE_TERRAFORM_GRAPH_RULES, } from '../../graph/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Implements {@link GraphListRules} for Google Cloud.
|
|
5
|
+
* The rules read the Google-specific parts of the workspace configuration and model (Firestore collections, the
|
|
6
|
+
* entities projects access through their `google.*` outputs, triggers of Google-specific types), and mirror the
|
|
7
|
+
* resources created by the Causa Terraform modules for Google Cloud.
|
|
8
|
+
*/
|
|
9
|
+
export class GraphListRulesForGoogle extends GraphListRules {
|
|
10
|
+
_call() {
|
|
11
|
+
return [...GOOGLE_GRAPH_RULES, ...GOOGLE_TERRAFORM_GRAPH_RULES];
|
|
12
|
+
}
|
|
13
|
+
_supports() {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
}
|
package/dist/functions/index.js
CHANGED
|
@@ -8,10 +8,11 @@ import { GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenera
|
|
|
8
8
|
import { GooglePubSubWriteTopics } from './google-pubsub/index.js';
|
|
9
9
|
import { GoogleServicesEnable } from './google-services/index.js';
|
|
10
10
|
import { DatabaseQueryRecordsForSpanner, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelSchemaExtractDatabaseForGoogleSpanner, } from './google-spanner/index.js';
|
|
11
|
+
import { GraphListRulesForGoogle } from './graph/index.js';
|
|
11
12
|
import { ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, } from './project/index.js';
|
|
12
13
|
import { SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, } from './secret/index.js';
|
|
13
14
|
import { ServiceContainerQueryLogsForCloudRun } from './service-container/index.js';
|
|
14
15
|
import { ModelGenerateTypeScriptTriggerDecoratorsForGoogle } from './typescript/index.js';
|
|
15
16
|
export function registerFunctions(context) {
|
|
16
|
-
context.registerFunctionImplementations(CausaListConfigurationSchemasForGoogle, DatabaseQueryRecordsForFirestore, DatabaseQueryRecordsForSpanner, EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForCloudRunService, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicBrokerWaitForProcessingForPubSub, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GooglePubSubWriteTopics, GoogleServicesEnable, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelGenerateTypeScriptDecoratorsForGoogleFirestore, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelGenerateTypeScriptTriggerDecoratorsForGoogle, ModelSchemaExtractDatabaseForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleSpanner, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, ServiceContainerQueryLogsForCloudRun);
|
|
17
|
+
context.registerFunctionImplementations(CausaListConfigurationSchemasForGoogle, DatabaseQueryRecordsForFirestore, DatabaseQueryRecordsForSpanner, EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForCloudRunService, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicBrokerWaitForProcessingForPubSub, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GooglePubSubWriteTopics, GoogleServicesEnable, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, GraphListRulesForGoogle, ModelGenerateTypeScriptDecoratorsForGoogleFirestore, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelGenerateTypeScriptTriggerDecoratorsForGoogle, ModelSchemaExtractDatabaseForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleSpanner, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, ServiceContainerQueryLogsForCloudRun);
|
|
17
18
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ServiceContainerConfiguration } from '@causa/workspace-core';
|
|
2
|
+
import { GraphFact, type GraphContext, type GraphFactOutput, type GraphTemplatePart, type WorkspaceProject } from '@causa/workspace-core/graph';
|
|
3
|
+
import { type TerraformModuleBlock } from '@causa/workspace-terraform';
|
|
4
|
+
/**
|
|
5
|
+
* A trigger defined in the `serviceContainer.triggers` configuration.
|
|
6
|
+
*/
|
|
7
|
+
type ServiceContainerTrigger = NonNullable<NonNullable<ServiceContainerConfiguration['serviceContainer']>['triggers']>[string];
|
|
8
|
+
/**
|
|
9
|
+
* The source of the Causa Terraform module deploying a service container to Cloud Run.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CLOUD_RUN_MODULE_SOURCE = "causa-io/service-container-cloud-run/google";
|
|
12
|
+
/**
|
|
13
|
+
* A block of the Cloud Run module, i.e. a deployed service, with the module's logic evaluated from the block's
|
|
14
|
+
* arguments and the project's configuration.
|
|
15
|
+
*/
|
|
16
|
+
export type CloudRunService = {
|
|
17
|
+
/**
|
|
18
|
+
* The Terraform module block defining the Cloud Run service.
|
|
19
|
+
*/
|
|
20
|
+
readonly block: TerraformModuleBlock;
|
|
21
|
+
/**
|
|
22
|
+
* The project whose configuration file the block reads.
|
|
23
|
+
*/
|
|
24
|
+
readonly project: WorkspaceProject;
|
|
25
|
+
/**
|
|
26
|
+
* The name of the service, `coalesce(var.name, project.name)`.
|
|
27
|
+
*/
|
|
28
|
+
readonly name: string;
|
|
29
|
+
/**
|
|
30
|
+
* The ID of the `service` node.
|
|
31
|
+
*/
|
|
32
|
+
readonly id: string;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the service's HTTP endpoints are exposed through the API router (`enable_public_http_endpoints`, `false` by
|
|
35
|
+
* default).
|
|
36
|
+
*/
|
|
37
|
+
readonly enablePublicHttpEndpoints: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Whether the block grants the publisher role on the project's `outputs.eventTopics` (`set_pubsub_permissions`,
|
|
40
|
+
* defaulting to `set_iam_permissions`).
|
|
41
|
+
*/
|
|
42
|
+
readonly setPubsubPermissions: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Whether the block grants access to the Spanner databases of the project's outputs (`set_spanner_permissions`,
|
|
45
|
+
* defaulting to `set_iam_permissions`).
|
|
46
|
+
*/
|
|
47
|
+
readonly setSpannerPermissions: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether the block grants access to the Firestore database for the collections of the project's outputs
|
|
50
|
+
* (`set_firestore_permissions`, defaulting to `set_iam_permissions`).
|
|
51
|
+
*/
|
|
52
|
+
readonly setFirestorePermissions: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the block grants the enqueuer role on the queues of the project's task triggers (`set_tasks_permissions`,
|
|
55
|
+
* defaulting to `set_iam_permissions`).
|
|
56
|
+
*/
|
|
57
|
+
readonly setTasksPermissions: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* The triggers the module turns into Pub/Sub push subscriptions, keyed by name: `event` or `google.pubSub` triggers
|
|
60
|
+
* with an HTTP endpoint, not disabled.
|
|
61
|
+
*/
|
|
62
|
+
readonly pubsubTriggers: ReadonlyMap<string, ServiceContainerTrigger>;
|
|
63
|
+
/**
|
|
64
|
+
* The triggers the module turns into Cloud Tasks queues, keyed by name. A disabled trigger still has its * queue,
|
|
65
|
+
* paused.
|
|
66
|
+
*/
|
|
67
|
+
readonly tasksTriggers: ReadonlyMap<string, ServiceContainerTrigger>;
|
|
68
|
+
/**
|
|
69
|
+
* The triggers the module turns into Cloud Scheduler jobs, keyed by name. A disabled trigger still has its job,
|
|
70
|
+
* paused.
|
|
71
|
+
*/
|
|
72
|
+
readonly cronTriggers: ReadonlyMap<string, ServiceContainerTrigger>;
|
|
73
|
+
/**
|
|
74
|
+
* The GCP project part of resource names.
|
|
75
|
+
*/
|
|
76
|
+
readonly projectPart: GraphTemplatePart;
|
|
77
|
+
/**
|
|
78
|
+
* The location part of resource names, shared by the service, its queues, and its jobs.
|
|
79
|
+
*/
|
|
80
|
+
readonly locationPart: GraphTemplatePart;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* The blocks of the Cloud Run module, evaluated against the configuration of the projects they deploy.
|
|
84
|
+
* Blocks whose `configuration_file` does not name a project of the workspace cannot be mirrored, and are reported.
|
|
85
|
+
*/
|
|
86
|
+
export declare class CloudRunFact extends GraphFact<CloudRunService[]> {
|
|
87
|
+
compute(graph: GraphContext): Promise<GraphFactOutput<CloudRunService[]>>;
|
|
88
|
+
/**
|
|
89
|
+
* Evaluates a Cloud Run module block, mirroring the defaults of the module.
|
|
90
|
+
*
|
|
91
|
+
* @param block The module block.
|
|
92
|
+
* @param project The project whose configuration file the block reads.
|
|
93
|
+
* @param warnings The warnings of the fact, to which the ones about the block are added.
|
|
94
|
+
* @returns The {@link CloudRunService}.
|
|
95
|
+
*/
|
|
96
|
+
private evaluate;
|
|
97
|
+
}
|
|
98
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { GraphFact, ProjectsFact, serviceId, } from '@causa/workspace-core/graph';
|
|
2
|
+
import { modulesWithSource, TerraformProjectsFact, } from '@causa/workspace-terraform';
|
|
3
|
+
import { argumentOrConfiguration, projectOfConfigurationFile, } from './terraform-modules.js';
|
|
4
|
+
/**
|
|
5
|
+
* The source of the Causa Terraform module deploying a service container to Cloud Run.
|
|
6
|
+
*/
|
|
7
|
+
export const CLOUD_RUN_MODULE_SOURCE = 'causa-io/service-container-cloud-run/google';
|
|
8
|
+
/**
|
|
9
|
+
* The major version of the Cloud Run module whose behavior is mirrored (trigger filters, IAM grants, resource names).
|
|
10
|
+
*/
|
|
11
|
+
const MIRRORED_CLOUD_RUN_MAJOR = 1;
|
|
12
|
+
/**
|
|
13
|
+
* The blocks of the Cloud Run module, evaluated against the configuration of the projects they deploy.
|
|
14
|
+
* Blocks whose `configuration_file` does not name a project of the workspace cannot be mirrored, and are reported.
|
|
15
|
+
*/
|
|
16
|
+
export class CloudRunFact extends GraphFact {
|
|
17
|
+
async compute(graph) {
|
|
18
|
+
const [terraformProjects, projects] = await Promise.all([
|
|
19
|
+
graph.get(TerraformProjectsFact),
|
|
20
|
+
graph.get(ProjectsFact),
|
|
21
|
+
]);
|
|
22
|
+
const services = [];
|
|
23
|
+
const warnings = [];
|
|
24
|
+
for (const block of modulesWithSource(terraformProjects, CLOUD_RUN_MODULE_SOURCE)) {
|
|
25
|
+
const project = projectOfConfigurationFile(block.arguments['configuration_file'], projects);
|
|
26
|
+
if (!project) {
|
|
27
|
+
warnings.push({
|
|
28
|
+
message: "The Cloud Run module block is skipped, as its 'configuration_file' does not name a project of the workspace.",
|
|
29
|
+
sources: [block.declaration],
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
services.push(this.evaluate(block, project, warnings));
|
|
34
|
+
}
|
|
35
|
+
return { value: services, warnings };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Evaluates a Cloud Run module block, mirroring the defaults of the module.
|
|
39
|
+
*
|
|
40
|
+
* @param block The module block.
|
|
41
|
+
* @param project The project whose configuration file the block reads.
|
|
42
|
+
* @param warnings The warnings of the fact, to which the ones about the block are added.
|
|
43
|
+
* @returns The {@link CloudRunService}.
|
|
44
|
+
*/
|
|
45
|
+
evaluate(block, project, warnings) {
|
|
46
|
+
const sources = [block.declaration];
|
|
47
|
+
const major = Number(block.version?.split('.')[0]);
|
|
48
|
+
if (major !== MIRRORED_CLOUD_RUN_MAJOR) {
|
|
49
|
+
warnings.push({
|
|
50
|
+
message: `The Cloud Run module version '${block.version ?? 'unset'}' is not the one being mirrored (${MIRRORED_CLOUD_RUN_MAJOR}.x). Resources are extracted as for that version.`,
|
|
51
|
+
sources,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const argument = (name, fallback) => {
|
|
55
|
+
const value = block.arguments[name];
|
|
56
|
+
if (value === undefined) {
|
|
57
|
+
return fallback;
|
|
58
|
+
}
|
|
59
|
+
if (!('value' in value)) {
|
|
60
|
+
const assumed = typeof fallback === 'string' ? fallback : JSON.stringify(fallback);
|
|
61
|
+
warnings.push({
|
|
62
|
+
message: `The argument '${name}' is computed (${value.expression}). Assuming ${assumed}.`,
|
|
63
|
+
sources,
|
|
64
|
+
});
|
|
65
|
+
return fallback;
|
|
66
|
+
}
|
|
67
|
+
return (value.value ?? fallback);
|
|
68
|
+
};
|
|
69
|
+
const name = argument('name', project.name) || project.name;
|
|
70
|
+
const enableTriggers = argument('enable_triggers', false);
|
|
71
|
+
const triggers = Object.entries({
|
|
72
|
+
...(project.context
|
|
73
|
+
.asConfiguration()
|
|
74
|
+
.get('serviceContainer.triggers', { unsafe: true }) ?? {}),
|
|
75
|
+
...argument('triggers', {}),
|
|
76
|
+
}).filter(([, t]) => t.endpoint?.type === 'http');
|
|
77
|
+
const ofTypes = (enabled, types, excludeDisabled = false) => new Map(enabled
|
|
78
|
+
? triggers.filter(([, t]) => types.includes(t.type ?? '') &&
|
|
79
|
+
!(excludeDisabled && t.enabled === false))
|
|
80
|
+
: []);
|
|
81
|
+
const setIamPermissions = argument('set_iam_permissions', true);
|
|
82
|
+
return {
|
|
83
|
+
block,
|
|
84
|
+
project,
|
|
85
|
+
name,
|
|
86
|
+
id: serviceId(project.directory, name),
|
|
87
|
+
enablePublicHttpEndpoints: argument('enable_public_http_endpoints', false),
|
|
88
|
+
setPubsubPermissions: argument('set_pubsub_permissions', setIamPermissions),
|
|
89
|
+
setSpannerPermissions: argument('set_spanner_permissions', setIamPermissions),
|
|
90
|
+
setFirestorePermissions: argument('set_firestore_permissions', setIamPermissions),
|
|
91
|
+
setTasksPermissions: argument('set_tasks_permissions', setIamPermissions),
|
|
92
|
+
pubsubTriggers: ofTypes(argument('enable_pubsub_triggers', enableTriggers), ['event', 'google.pubSub'], true),
|
|
93
|
+
tasksTriggers: ofTypes(argument('enable_tasks_triggers', enableTriggers), ['task', 'google.task', 'google.tasks']),
|
|
94
|
+
cronTriggers: ofTypes(argument('enable_cron_triggers', enableTriggers), [
|
|
95
|
+
'cron',
|
|
96
|
+
'google.scheduler',
|
|
97
|
+
]),
|
|
98
|
+
projectPart: argumentOrConfiguration(block, 'gcp_project_id', 'google.project', warnings),
|
|
99
|
+
locationPart: argumentOrConfiguration(block, 'location', 'google.cloudRun.location', warnings),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine of Spanner databases. It is also the key of `serviceContainer.outputs` listing the databases a project
|
|
3
|
+
* owns, and the `engine` of Spanner database bindings.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SPANNER_ENGINE = "google.spanner";
|
|
6
|
+
/**
|
|
7
|
+
* The engine of Firestore databases. It is also the key of `serviceContainer.outputs` listing the collections a
|
|
8
|
+
* project owns, and the `engine` of Firestore database bindings.
|
|
9
|
+
*/
|
|
10
|
+
export declare const FIRESTORE_ENGINE = "google.firestore";
|
|
11
|
+
/**
|
|
12
|
+
* The engine of BigQuery datasets.
|
|
13
|
+
*/
|
|
14
|
+
export declare const BIGQUERY_ENGINE = "google.bigquery";
|
|
15
|
+
export declare const spannerInstanceId: (instance: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* The name of a Spanner database within its engine, `<instance>.<database>`, as `outputs['google.spanner']` lists it.
|
|
18
|
+
*/
|
|
19
|
+
export declare const spannerDatabaseName: (instance: string, database: string) => string;
|
|
20
|
+
export declare const spannerDatabaseLocator: (instance: string, database: string) => string;
|
|
21
|
+
export declare const firestoreDatabaseLocator: (database: string) => string;
|
|
22
|
+
export declare const bigQueryDatasetLocator: (dataset: string) => string;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the path of the collection holding the documents of a Firestore binding, independently of the properties
|
|
25
|
+
* used as document IDs: the last segment (the document) is dropped, and the other placeholders are replaced with `{}`.
|
|
26
|
+
* For example, `users/{user}/bookmarkFolders/{id}` becomes `users/{}/bookmarkFolders`.
|
|
27
|
+
*
|
|
28
|
+
* @param bindingTable The table of the binding, i.e. the path of its documents.
|
|
29
|
+
* @returns The collection path, or `undefined` if the root collection is not named by the binding.
|
|
30
|
+
*/
|
|
31
|
+
export declare function firestoreCollectionPath(bindingTable: string): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* The locator of the BigQuery subscription archiving a topic's raw events.
|
|
34
|
+
*/
|
|
35
|
+
export declare const rawEventsSubscriptionLocator: (topic: string) => string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { databaseLocator, nodeId } from '@causa/workspace-core/graph';
|
|
2
|
+
/**
|
|
3
|
+
* The engine of Spanner databases. It is also the key of `serviceContainer.outputs` listing the databases a project
|
|
4
|
+
* owns, and the `engine` of Spanner database bindings.
|
|
5
|
+
*/
|
|
6
|
+
export const SPANNER_ENGINE = 'google.spanner';
|
|
7
|
+
/**
|
|
8
|
+
* The engine of Firestore databases. It is also the key of `serviceContainer.outputs` listing the collections a
|
|
9
|
+
* project owns, and the `engine` of Firestore database bindings.
|
|
10
|
+
*/
|
|
11
|
+
export const FIRESTORE_ENGINE = 'google.firestore';
|
|
12
|
+
/**
|
|
13
|
+
* The engine of BigQuery datasets.
|
|
14
|
+
*/
|
|
15
|
+
export const BIGQUERY_ENGINE = 'google.bigquery';
|
|
16
|
+
export const spannerInstanceId = (instance) => nodeId('google.spanner.instance', instance);
|
|
17
|
+
/**
|
|
18
|
+
* The name of a Spanner database within its engine, `<instance>.<database>`, as `outputs['google.spanner']` lists it.
|
|
19
|
+
*/
|
|
20
|
+
export const spannerDatabaseName = (instance, database) => `${instance}.${database}`;
|
|
21
|
+
export const spannerDatabaseLocator = (instance, database) => databaseLocator(SPANNER_ENGINE, spannerDatabaseName(instance, database));
|
|
22
|
+
export const firestoreDatabaseLocator = (database) => databaseLocator(FIRESTORE_ENGINE, database);
|
|
23
|
+
export const bigQueryDatasetLocator = (dataset) => databaseLocator(BIGQUERY_ENGINE, dataset);
|
|
24
|
+
/**
|
|
25
|
+
* Returns the path of the collection holding the documents of a Firestore binding, independently of the properties
|
|
26
|
+
* used as document IDs: the last segment (the document) is dropped, and the other placeholders are replaced with `{}`.
|
|
27
|
+
* For example, `users/{user}/bookmarkFolders/{id}` becomes `users/{}/bookmarkFolders`.
|
|
28
|
+
*
|
|
29
|
+
* @param bindingTable The table of the binding, i.e. the path of its documents.
|
|
30
|
+
* @returns The collection path, or `undefined` if the root collection is not named by the binding.
|
|
31
|
+
*/
|
|
32
|
+
export function firestoreCollectionPath(bindingTable) {
|
|
33
|
+
const segments = bindingTable.split('/').slice(0, -1);
|
|
34
|
+
if (segments.length === 0 || /^\{.*\}$/.test(segments[0])) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return segments
|
|
38
|
+
.map((segment) => (/^\{.*\}$/.test(segment) ? '{}' : segment))
|
|
39
|
+
.join('/');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The locator of the BigQuery subscription archiving a topic's raw events.
|
|
43
|
+
*/
|
|
44
|
+
export const rawEventsSubscriptionLocator = (topic) => `rawEvents/${topic}`;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type GraphRule } from '@causa/workspace-core';
|
|
2
|
+
/**
|
|
3
|
+
* An `enqueues` edge from a service container project to each of its own `google.task` or `google.tasks` triggers,
|
|
4
|
+
* assuming the owning project is the producer.
|
|
5
|
+
*/
|
|
6
|
+
export declare const enqueuesAssumedFromGoogleTaskTrigger: GraphRule;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { GraphOriginKind, } from '@causa/workspace-core';
|
|
2
|
+
import { projectId, triggerId, ProjectsFact, } from '@causa/workspace-core/graph';
|
|
3
|
+
/**
|
|
4
|
+
* An `enqueues` edge from a service container project to each of its own `google.task` or `google.tasks` triggers,
|
|
5
|
+
* assuming the owning project is the producer.
|
|
6
|
+
*/
|
|
7
|
+
export const enqueuesAssumedFromGoogleTaskTrigger = {
|
|
8
|
+
name: 'enqueuesAssumedFromGoogleTaskTrigger',
|
|
9
|
+
kind: GraphOriginKind.Inferred,
|
|
10
|
+
description: 'One `enqueues` edge from a service container project to each of its own `google.task` or `google.tasks` triggers, assuming the owning project is the producer.',
|
|
11
|
+
async run(graph) {
|
|
12
|
+
const { locator } = graph;
|
|
13
|
+
const projects = await graph.get(ProjectsFact);
|
|
14
|
+
const edges = [];
|
|
15
|
+
for (const project of projects.filter((p) => p.type === 'serviceContainer')) {
|
|
16
|
+
const triggers = project.context
|
|
17
|
+
.asConfiguration()
|
|
18
|
+
.get('serviceContainer.triggers', { unsafe: true }) ?? {};
|
|
19
|
+
for (const [name, trigger] of Object.entries(triggers)) {
|
|
20
|
+
if (!['google.task', 'google.tasks'].includes(trigger.type ?? '')) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
edges.push({
|
|
24
|
+
type: 'enqueues',
|
|
25
|
+
from: projectId(project.directory),
|
|
26
|
+
to: triggerId(project.directory, name),
|
|
27
|
+
sources: [
|
|
28
|
+
await locator.configurationSource(project.context, [
|
|
29
|
+
'serviceContainer',
|
|
30
|
+
'triggers',
|
|
31
|
+
name,
|
|
32
|
+
]),
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { edges };
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type GraphRule } from '@causa/workspace-core';
|
|
2
|
+
/**
|
|
3
|
+
* The Firestore database of the workspace, `google.firestore.database`, and the collections schemas bind to:
|
|
4
|
+
*
|
|
5
|
+
* - A `database` node for the database.
|
|
6
|
+
* - A `table` node per Firestore collection a schema binds to (`causa.googleFirestoreCollection`). The locator is the
|
|
7
|
+
* collection path, with `{}` in place of document IDs (e.g. `users/{}/bookmarks`), under the single Firestore database
|
|
8
|
+
* of the workspace. A binding that does not name its root collection is reported.
|
|
9
|
+
* - A `realizes` edge from each collection to the entity whose binding declares it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const firestoreFromConfiguration: GraphRule;
|