@backstage/backend-defaults 0.15.1 → 0.15.2
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 +50 -6
- package/config.d.ts +26 -0
- package/dist/PackageDiscoveryService.cjs.js +1 -1
- package/dist/PackageDiscoveryService.cjs.js.map +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js +2 -2
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js +2 -2
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheClient.cjs.js +2 -2
- package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -1
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js +2 -2
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js +191 -157
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js +2 -2
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +4 -4
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js +2 -2
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js +2 -2
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js +4 -4
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js +6 -6
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js +25 -7
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js +30 -13
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/util.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
- package/dist/httpRouter.cjs.js +2 -0
- package/dist/httpRouter.cjs.js.map +1 -1
- package/dist/httpRouter.d.ts +10 -1
- package/dist/package.json.cjs.js +1 -1
- package/dist/rootHttpRouter.d.ts +2 -3
- package/dist/urlReader.d.ts +1 -1
- package/package.json +16 -15
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js +0 -12
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +0 -1
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var config = require('@backstage/config');
|
|
4
4
|
var errors = require('@backstage/errors');
|
|
5
|
+
var types = require('@backstage/types');
|
|
5
6
|
var knexFactory = require('knex');
|
|
6
7
|
var lodash = require('lodash');
|
|
7
8
|
var limiterFactory = require('p-limit');
|
|
8
|
-
var defaultNameOverride = require('./defaultNameOverride.cjs.js');
|
|
9
|
-
var defaultSchemaOverride = require('./defaultSchemaOverride.cjs.js');
|
|
10
9
|
var mergeDatabaseConfig = require('./mergeDatabaseConfig.cjs.js');
|
|
11
10
|
var format = require('pg-format');
|
|
12
11
|
|
|
@@ -33,7 +32,7 @@ async function createPgDatabaseClient(dbConfig, overrides) {
|
|
|
33
32
|
return database;
|
|
34
33
|
}
|
|
35
34
|
async function buildPgDatabaseConfig(dbConfig, overrides) {
|
|
36
|
-
const config = mergeDatabaseConfig.mergeDatabaseConfig(
|
|
35
|
+
const config$1 = mergeDatabaseConfig.mergeDatabaseConfig(
|
|
37
36
|
dbConfig.get(),
|
|
38
37
|
{
|
|
39
38
|
connection: getPgConnectionConfig(dbConfig, !!overrides),
|
|
@@ -41,19 +40,90 @@ async function buildPgDatabaseConfig(dbConfig, overrides) {
|
|
|
41
40
|
},
|
|
42
41
|
overrides
|
|
43
42
|
);
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
const mergedConfigReader = new config.ConfigReader(config$1);
|
|
44
|
+
if (config$1.connection.type === "default" || !config$1.connection.type) {
|
|
45
|
+
const connectionValue = config$1.connection;
|
|
46
|
+
const sanitizedConnection = typeof connectionValue === "string" || connectionValue instanceof String ? connectionValue : (
|
|
47
|
+
// connection is an object, omit config-only props
|
|
48
|
+
lodash.omit(connectionValue, [
|
|
49
|
+
"type",
|
|
50
|
+
"instance",
|
|
51
|
+
"tokenCredential"
|
|
52
|
+
])
|
|
53
|
+
);
|
|
54
|
+
return {
|
|
55
|
+
...config$1,
|
|
56
|
+
connection: sanitizedConnection
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
switch (config$1.connection.type) {
|
|
60
|
+
case "azure":
|
|
61
|
+
return buildAzurePgConfig(mergedConfigReader);
|
|
62
|
+
case "cloudsql":
|
|
63
|
+
return buildCloudSqlConfig(mergedConfigReader);
|
|
64
|
+
default:
|
|
65
|
+
throw new Error(`Unknown connection type: ${config$1.connection.type}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function buildAzurePgConfig(config$1) {
|
|
69
|
+
const {
|
|
70
|
+
DefaultAzureCredential,
|
|
71
|
+
ManagedIdentityCredential,
|
|
72
|
+
ClientSecretCredential
|
|
73
|
+
} = require("@azure/identity");
|
|
74
|
+
const tokenConfig = config$1.getOptionalConfig("connection.tokenCredential");
|
|
75
|
+
const tokenRenewableOffsetTime = types.durationToMilliseconds(
|
|
76
|
+
tokenConfig?.has("tokenRenewableOffsetTime") ? config.readDurationFromConfig(tokenConfig, { key: "tokenRenewableOffsetTime" }) : { minutes: 5 }
|
|
77
|
+
);
|
|
78
|
+
const clientId = tokenConfig?.getOptionalString("clientId");
|
|
79
|
+
const tenantId = tokenConfig?.getOptionalString("tenantId");
|
|
80
|
+
const clientSecret = tokenConfig?.getOptionalString("clientSecret");
|
|
81
|
+
let credential;
|
|
82
|
+
if (clientId && tenantId && clientSecret) {
|
|
83
|
+
credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
|
84
|
+
} else if (clientId) {
|
|
85
|
+
credential = new ManagedIdentityCredential(clientId);
|
|
86
|
+
} else {
|
|
87
|
+
credential = new DefaultAzureCredential();
|
|
49
88
|
}
|
|
50
|
-
|
|
51
|
-
|
|
89
|
+
const rawConfig = config$1.get();
|
|
90
|
+
const normalized = normalizeConnection(rawConfig.connection);
|
|
91
|
+
const sanitizedConnection = lodash.omit(normalized, [
|
|
92
|
+
"type",
|
|
93
|
+
"instance",
|
|
94
|
+
"tokenCredential"
|
|
95
|
+
]);
|
|
96
|
+
async function getConnectionConfig() {
|
|
97
|
+
const token = await credential.getToken(
|
|
98
|
+
"https://ossrdbms-aad.database.windows.net/.default"
|
|
99
|
+
);
|
|
100
|
+
if (!token) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
"Failed to acquire Azure access token for database authentication"
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const connectionConfig = {
|
|
106
|
+
...sanitizedConnection,
|
|
107
|
+
password: token.token,
|
|
108
|
+
expirationChecker: () => (
|
|
109
|
+
/* return true if the token is within the renewable offset time */
|
|
110
|
+
token.expiresOnTimestamp - tokenRenewableOffsetTime <= Date.now()
|
|
111
|
+
)
|
|
112
|
+
};
|
|
113
|
+
return connectionConfig;
|
|
52
114
|
}
|
|
53
|
-
|
|
115
|
+
return {
|
|
116
|
+
...rawConfig,
|
|
117
|
+
connection: getConnectionConfig
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function buildCloudSqlConfig(config) {
|
|
121
|
+
const client = config.getOptionalString("client");
|
|
122
|
+
if (client && client !== "pg") {
|
|
54
123
|
throw new Error("Cloud SQL only supports the pg client");
|
|
55
124
|
}
|
|
56
|
-
|
|
125
|
+
const instance = config.getOptionalString("connection.instance");
|
|
126
|
+
if (!instance) {
|
|
57
127
|
throw new Error("Missing instance connection name for Cloud SQL");
|
|
58
128
|
}
|
|
59
129
|
const {
|
|
@@ -62,16 +132,36 @@ async function buildPgDatabaseConfig(dbConfig, overrides) {
|
|
|
62
132
|
AuthTypes
|
|
63
133
|
} = require("@google-cloud/cloud-sql-connector");
|
|
64
134
|
const connector = new CloudSqlConnector();
|
|
135
|
+
const ipTypeRaw = config.getOptionalString("connection.ipAddressType");
|
|
136
|
+
let ipType;
|
|
137
|
+
if (ipTypeRaw !== void 0) {
|
|
138
|
+
if (!Object.values(IpAddressTypes).includes(
|
|
139
|
+
ipTypeRaw
|
|
140
|
+
)) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Invalid connection.ipAddressType: ${ipTypeRaw}; valid values: ${Object.values(
|
|
143
|
+
IpAddressTypes
|
|
144
|
+
).join(", ")}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
ipType = ipTypeRaw;
|
|
148
|
+
}
|
|
65
149
|
const clientOpts = await connector.getOptions({
|
|
66
|
-
instanceConnectionName:
|
|
67
|
-
ipType:
|
|
150
|
+
instanceConnectionName: instance,
|
|
151
|
+
ipType: ipType ?? IpAddressTypes.PUBLIC,
|
|
68
152
|
authType: AuthTypes.IAM
|
|
69
153
|
});
|
|
154
|
+
const rawConfig = config.get();
|
|
155
|
+
const normalized = normalizeConnection(rawConfig.connection);
|
|
156
|
+
const sanitizedConnection = lodash.omit(normalized, [
|
|
157
|
+
"type",
|
|
158
|
+
"instance"
|
|
159
|
+
]);
|
|
70
160
|
return {
|
|
71
|
-
...
|
|
161
|
+
...rawConfig,
|
|
72
162
|
client: "pg",
|
|
73
163
|
connection: {
|
|
74
|
-
...
|
|
164
|
+
...sanitizedConnection,
|
|
75
165
|
...clientOpts
|
|
76
166
|
}
|
|
77
167
|
};
|
|
@@ -160,6 +250,73 @@ function normalizeConnection(connection) {
|
|
|
160
250
|
}
|
|
161
251
|
return typeof connection === "string" || connection instanceof String ? parsePgConnectionString(connection) : connection;
|
|
162
252
|
}
|
|
253
|
+
function computePgPluginConfig(config, pluginId, prefix) {
|
|
254
|
+
const pluginClient = config.getOptionalString(
|
|
255
|
+
`${pluginPath(pluginId)}.client`
|
|
256
|
+
);
|
|
257
|
+
const baseClient = config.getString("client");
|
|
258
|
+
const client = pluginClient ?? baseClient;
|
|
259
|
+
const clientOverridden = client !== baseClient;
|
|
260
|
+
const role = config.getOptionalString(`${pluginPath(pluginId)}.role`) ?? config.getOptionalString("role");
|
|
261
|
+
const pluginKnexConfig = config.getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)?.get();
|
|
262
|
+
const baseKnexConfig = config.getOptionalConfig("knexConfig")?.get();
|
|
263
|
+
const additionalKnexConfig = lodash.merge(baseKnexConfig, pluginKnexConfig);
|
|
264
|
+
const baseEnsureExists = config.getOptionalBoolean("ensureExists") ?? true;
|
|
265
|
+
const ensureExists = config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ?? baseEnsureExists;
|
|
266
|
+
const baseEnsureSchemaExists = config.getOptionalBoolean("ensureSchemaExists") ?? false;
|
|
267
|
+
const ensureSchemaExists = config.getOptionalBoolean(
|
|
268
|
+
`${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`
|
|
269
|
+
) ?? baseEnsureSchemaExists;
|
|
270
|
+
const pluginDivisionMode = config.getOptionalString("pluginDivisionMode") ?? "database";
|
|
271
|
+
let baseConnection = normalizeConnection(config.get("connection"));
|
|
272
|
+
if (pluginDivisionMode !== "schema") {
|
|
273
|
+
baseConnection = lodash.omit(baseConnection, "database");
|
|
274
|
+
}
|
|
275
|
+
const pluginConnection = normalizeConnection(
|
|
276
|
+
config.getOptional(`${pluginPath(pluginId)}.connection`)
|
|
277
|
+
);
|
|
278
|
+
baseConnection.application_name ||= `backstage_plugin_${pluginId}`;
|
|
279
|
+
const connection = {
|
|
280
|
+
// Include base connection if client type has not been overridden
|
|
281
|
+
...clientOverridden ? {} : baseConnection,
|
|
282
|
+
...pluginConnection
|
|
283
|
+
};
|
|
284
|
+
const connectionDatabaseName = connection?.database;
|
|
285
|
+
let databaseName;
|
|
286
|
+
if (pluginDivisionMode === "schema") {
|
|
287
|
+
databaseName = connectionDatabaseName;
|
|
288
|
+
} else {
|
|
289
|
+
databaseName = connectionDatabaseName ?? `${prefix}${pluginId}`;
|
|
290
|
+
}
|
|
291
|
+
let databaseClientOverrides = {};
|
|
292
|
+
if (databaseName) {
|
|
293
|
+
databaseClientOverrides = { connection: { database: databaseName } };
|
|
294
|
+
}
|
|
295
|
+
if (pluginDivisionMode === "schema") {
|
|
296
|
+
databaseClientOverrides = mergeDatabaseConfig.mergeDatabaseConfig({}, databaseClientOverrides, {
|
|
297
|
+
searchPath: [pluginId]
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
const knexConfig = {
|
|
301
|
+
...additionalKnexConfig,
|
|
302
|
+
client,
|
|
303
|
+
connection,
|
|
304
|
+
...role && { role }
|
|
305
|
+
};
|
|
306
|
+
return {
|
|
307
|
+
client,
|
|
308
|
+
clientOverridden,
|
|
309
|
+
role,
|
|
310
|
+
additionalKnexConfig,
|
|
311
|
+
ensureExists,
|
|
312
|
+
ensureSchemaExists,
|
|
313
|
+
pluginDivisionMode,
|
|
314
|
+
connection,
|
|
315
|
+
databaseName,
|
|
316
|
+
databaseClientOverrides,
|
|
317
|
+
knexConfig
|
|
318
|
+
};
|
|
319
|
+
}
|
|
163
320
|
class PgConnector {
|
|
164
321
|
config;
|
|
165
322
|
prefix;
|
|
@@ -168,25 +325,24 @@ class PgConnector {
|
|
|
168
325
|
this.prefix = prefix;
|
|
169
326
|
}
|
|
170
327
|
async getClient(pluginId, _deps) {
|
|
171
|
-
const
|
|
172
|
-
this.
|
|
328
|
+
const pluginDbConfig = computePgPluginConfig(
|
|
329
|
+
this.config,
|
|
330
|
+
pluginId,
|
|
331
|
+
this.prefix
|
|
173
332
|
);
|
|
174
|
-
|
|
175
|
-
if (databaseName && this.getEnsureExistsConfig(pluginId)) {
|
|
333
|
+
if (pluginDbConfig.databaseName && pluginDbConfig.ensureExists) {
|
|
176
334
|
try {
|
|
177
|
-
await ensurePgDatabaseExists(
|
|
335
|
+
await ensurePgDatabaseExists(this.config, pluginDbConfig.databaseName);
|
|
178
336
|
} catch (error) {
|
|
179
337
|
throw new Error(
|
|
180
|
-
`Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`
|
|
338
|
+
`Failed to connect to the database to make sure that '${pluginDbConfig.databaseName}' exists, ${error}`
|
|
181
339
|
);
|
|
182
340
|
}
|
|
183
341
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
schemaOverrides = defaultSchemaOverride.default(pluginId);
|
|
187
|
-
if (this.getEnsureSchemaExistsConfig(pluginId) || this.getEnsureExistsConfig(pluginId)) {
|
|
342
|
+
if (pluginDbConfig.pluginDivisionMode === "schema") {
|
|
343
|
+
if (pluginDbConfig.ensureSchemaExists || pluginDbConfig.ensureExists) {
|
|
188
344
|
try {
|
|
189
|
-
await ensurePgSchemaExists(
|
|
345
|
+
await ensurePgSchemaExists(this.config, pluginId);
|
|
190
346
|
} catch (error) {
|
|
191
347
|
throw new Error(
|
|
192
348
|
`Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`
|
|
@@ -194,144 +350,22 @@ class PgConnector {
|
|
|
194
350
|
}
|
|
195
351
|
}
|
|
196
352
|
}
|
|
197
|
-
const databaseClientOverrides = mergeDatabaseConfig.mergeDatabaseConfig(
|
|
198
|
-
{},
|
|
199
|
-
this.getDatabaseOverrides(pluginId),
|
|
200
|
-
schemaOverrides
|
|
201
|
-
);
|
|
202
353
|
const client = createPgDatabaseClient(
|
|
203
|
-
|
|
204
|
-
|
|
354
|
+
this.config,
|
|
355
|
+
mergeDatabaseConfig.mergeDatabaseConfig(
|
|
356
|
+
pluginDbConfig.knexConfig,
|
|
357
|
+
pluginDbConfig.databaseClientOverrides
|
|
358
|
+
)
|
|
205
359
|
);
|
|
206
360
|
return client;
|
|
207
361
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Provides the canonical database name for a given plugin.
|
|
210
|
-
*
|
|
211
|
-
* This method provides the effective database name which is determined using global
|
|
212
|
-
* and plugin specific database config. If no explicit database name is configured
|
|
213
|
-
* and `pluginDivisionMode` is not `schema`, this method will provide a generated name
|
|
214
|
-
* which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is
|
|
215
|
-
* `schema`, it will fallback to using the default database for the knex instance.
|
|
216
|
-
*
|
|
217
|
-
* @param pluginId - Lookup the database name for given plugin
|
|
218
|
-
* @returns String representing the plugin's database name
|
|
219
|
-
*/
|
|
220
|
-
getDatabaseName(pluginId) {
|
|
221
|
-
const connection = this.getConnectionConfig(pluginId);
|
|
222
|
-
const databaseName = connection?.database;
|
|
223
|
-
if (this.getPluginDivisionModeConfig() === "schema") {
|
|
224
|
-
return databaseName;
|
|
225
|
-
}
|
|
226
|
-
return databaseName ?? `${this.prefix}${pluginId}`;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Provides the client type which should be used for a given plugin.
|
|
230
|
-
*
|
|
231
|
-
* The client type is determined by plugin specific config if present.
|
|
232
|
-
* Otherwise the base client is used as the fallback.
|
|
233
|
-
*
|
|
234
|
-
* @param pluginId - Plugin to get the client type for
|
|
235
|
-
* @returns Object with client type returned as `client` and boolean
|
|
236
|
-
* representing whether or not the client was overridden as
|
|
237
|
-
* `overridden`
|
|
238
|
-
*/
|
|
239
|
-
getClientType(pluginId) {
|
|
240
|
-
const pluginClient = this.config.getOptionalString(
|
|
241
|
-
`${pluginPath(pluginId)}.client`
|
|
242
|
-
);
|
|
243
|
-
const baseClient = this.config.getString("client");
|
|
244
|
-
const client = pluginClient ?? baseClient;
|
|
245
|
-
return {
|
|
246
|
-
client,
|
|
247
|
-
overridden: client !== baseClient
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
getRoleConfig(pluginId) {
|
|
251
|
-
return this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ?? this.config.getOptionalString("role");
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Provides the knexConfig which should be used for a given plugin.
|
|
255
|
-
*
|
|
256
|
-
* @param pluginId - Plugin to get the knexConfig for
|
|
257
|
-
* @returns The merged knexConfig value or undefined if it isn't specified
|
|
258
|
-
*/
|
|
259
|
-
getAdditionalKnexConfig(pluginId) {
|
|
260
|
-
const pluginConfig = this.config.getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)?.get();
|
|
261
|
-
const baseConfig = this.config.getOptionalConfig("knexConfig")?.get();
|
|
262
|
-
return lodash.merge(baseConfig, pluginConfig);
|
|
263
|
-
}
|
|
264
|
-
getEnsureExistsConfig(pluginId) {
|
|
265
|
-
const baseConfig = this.config.getOptionalBoolean("ensureExists") ?? true;
|
|
266
|
-
return this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ?? baseConfig;
|
|
267
|
-
}
|
|
268
|
-
getEnsureSchemaExistsConfig(pluginId) {
|
|
269
|
-
const baseConfig = this.config.getOptionalBoolean("ensureSchemaExists") ?? false;
|
|
270
|
-
return this.config.getOptionalBoolean(
|
|
271
|
-
`${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`
|
|
272
|
-
) ?? baseConfig;
|
|
273
|
-
}
|
|
274
|
-
getPluginDivisionModeConfig() {
|
|
275
|
-
return this.config.getOptionalString("pluginDivisionMode") ?? "database";
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Provides a Knex connection plugin config by combining base and plugin
|
|
279
|
-
* config.
|
|
280
|
-
*
|
|
281
|
-
* This method provides a baseConfig for a plugin database connector. If the
|
|
282
|
-
* client type has not been overridden, the global connection config will be
|
|
283
|
-
* included with plugin specific config as the base. Values from the plugin
|
|
284
|
-
* connection take precedence over the base. Base database name is omitted
|
|
285
|
-
* unless `pluginDivisionMode` is set to `schema`.
|
|
286
|
-
*/
|
|
287
|
-
getConnectionConfig(pluginId) {
|
|
288
|
-
const { overridden } = this.getClientType(pluginId);
|
|
289
|
-
let baseConnection = normalizeConnection(this.config.get("connection"));
|
|
290
|
-
if (this.getPluginDivisionModeConfig() !== "schema") {
|
|
291
|
-
baseConnection = lodash.omit(baseConnection, "database");
|
|
292
|
-
}
|
|
293
|
-
const connection = normalizeConnection(
|
|
294
|
-
this.config.getOptional(`${pluginPath(pluginId)}.connection`)
|
|
295
|
-
);
|
|
296
|
-
baseConnection.application_name ||= `backstage_plugin_${pluginId}`;
|
|
297
|
-
return {
|
|
298
|
-
// include base connection if client type has not been overridden
|
|
299
|
-
...overridden ? {} : baseConnection,
|
|
300
|
-
...connection
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Provides a Knex database config for a given plugin.
|
|
305
|
-
*
|
|
306
|
-
* This method provides a Knex configuration object along with the plugin's
|
|
307
|
-
* client type.
|
|
308
|
-
*
|
|
309
|
-
* @param pluginId - The plugin that the database config should correspond with
|
|
310
|
-
*/
|
|
311
|
-
getConfigForPlugin(pluginId) {
|
|
312
|
-
const { client } = this.getClientType(pluginId);
|
|
313
|
-
const role = this.getRoleConfig(pluginId);
|
|
314
|
-
return {
|
|
315
|
-
...this.getAdditionalKnexConfig(pluginId),
|
|
316
|
-
client,
|
|
317
|
-
connection: this.getConnectionConfig(pluginId),
|
|
318
|
-
...role && { role }
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Provides a partial `Knex.Config`• database name override for a given plugin.
|
|
323
|
-
*
|
|
324
|
-
* @param pluginId - Target plugin to get database name override
|
|
325
|
-
* @returns Partial `Knex.Config` with database name override
|
|
326
|
-
*/
|
|
327
|
-
getDatabaseOverrides(pluginId) {
|
|
328
|
-
const databaseName = this.getDatabaseName(pluginId);
|
|
329
|
-
return databaseName ? defaultNameOverride.default(databaseName) : {};
|
|
330
|
-
}
|
|
331
362
|
}
|
|
332
363
|
|
|
333
364
|
exports.PgConnector = PgConnector;
|
|
365
|
+
exports.buildAzurePgConfig = buildAzurePgConfig;
|
|
366
|
+
exports.buildCloudSqlConfig = buildCloudSqlConfig;
|
|
334
367
|
exports.buildPgDatabaseConfig = buildPgDatabaseConfig;
|
|
368
|
+
exports.computePgPluginConfig = computePgPluginConfig;
|
|
335
369
|
exports.createPgDatabaseClient = createPgDatabaseClient;
|
|
336
370
|
exports.ensurePgDatabaseExists = ensurePgDatabaseExists;
|
|
337
371
|
exports.ensurePgSchemaExists = ensurePgSchemaExists;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.cjs.js","sources":["../../../../src/entrypoints/database/connectors/postgres.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 */\n\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config, ConfigReader } from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport limiterFactory from 'p-limit';\nimport { Client } from 'pg';\nimport { Connector } from '../types';\nimport defaultNameOverride from './defaultNameOverride';\nimport defaultSchemaOverride from './defaultSchemaOverride';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\nimport format from 'pg-format';\n\n// Limits the number of concurrent DDL operations to 1\nconst ddlLimiter = limiterFactory(1);\n\n/**\n * Creates a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function createPgDatabaseClient(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);\n const database = knexFactory(knexConfig);\n\n const role = dbConfig.getOptionalString('role');\n\n if (role) {\n database.client.pool.on(\n 'createSuccess',\n async (_event: number, pgClient: Client) => {\n const query = format('SET ROLE %I', role);\n await pgClient.query(query);\n },\n );\n }\n return database;\n}\n\n/**\n * Builds a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function buildPgDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const config = mergeDatabaseConfig(\n dbConfig.get(),\n {\n connection: getPgConnectionConfig(dbConfig, !!overrides),\n useNullAsDefault: true,\n },\n overrides,\n );\n\n const sanitizedConfig = JSON.parse(JSON.stringify(config));\n\n // Trim additional properties from the connection object passed to knex\n delete sanitizedConfig.connection.type;\n delete sanitizedConfig.connection.instance;\n\n if (config.connection.type === 'default' || !config.connection.type) {\n return sanitizedConfig;\n }\n\n if (config.connection.type !== 'cloudsql') {\n throw new Error(`Unknown connection type: ${config.connection.type}`);\n }\n\n if (config.client !== 'pg') {\n throw new Error('Cloud SQL only supports the pg client');\n }\n\n if (!config.connection.instance) {\n throw new Error('Missing instance connection name for Cloud SQL');\n }\n\n const {\n Connector: CloudSqlConnector,\n IpAddressTypes,\n AuthTypes,\n } = require('@google-cloud/cloud-sql-connector') as typeof import('@google-cloud/cloud-sql-connector');\n const connector = new CloudSqlConnector();\n const clientOpts = await connector.getOptions({\n instanceConnectionName: config.connection.instance,\n ipType: config.connection.ipAddressType ?? IpAddressTypes.PUBLIC,\n authType: AuthTypes.IAM,\n });\n\n return {\n ...sanitizedConfig,\n client: 'pg',\n connection: {\n ...sanitizedConfig.connection,\n ...clientOpts,\n },\n };\n}\n\n/**\n * Gets the postgres connection config\n *\n * @param dbConfig - The database config\n * @param parseConnectionString - Flag to explicitly control connection string parsing\n */\nexport function getPgConnectionConfig(\n dbConfig: Config,\n parseConnectionString?: boolean,\n): Knex.PgConnectionConfig | string {\n const connection = dbConfig.get('connection') as any;\n const isConnectionString =\n typeof connection === 'string' || connection instanceof String;\n const autoParse = typeof parseConnectionString !== 'boolean';\n\n const shouldParseConnectionString = autoParse\n ? isConnectionString\n : parseConnectionString && isConnectionString;\n\n return shouldParseConnectionString\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * Parses a connection string using pg-connection-string\n *\n * @param connectionString - The postgres connection string\n */\nexport function parsePgConnectionString(connectionString: string) {\n const parse = requirePgConnectionString();\n return parse(connectionString);\n}\n\nfunction requirePgConnectionString() {\n try {\n return require('pg-connection-string').parse;\n } catch (e) {\n throw new ForwardedError(\"Postgres: Install 'pg-connection-string'\", e);\n }\n}\n\n/**\n * Creates the missing Postgres database if it does not exist\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to create\n */\nexport async function ensurePgDatabaseExists(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig, {\n connection: {\n database: 'postgres',\n },\n pool: {\n min: 0,\n acquireTimeoutMillis: 10000,\n },\n });\n\n try {\n const ensureDatabase = async (database: string) => {\n const result = await admin\n .from('pg_database')\n .where('datname', database)\n .count<Record<string, { count: string }>>();\n\n if (parseInt(result[0].count, 10) > 0) {\n return;\n }\n\n await admin.raw(`CREATE DATABASE ??`, [database]);\n };\n\n await Promise.all(\n databases.map(async database => {\n // For initial setup we use a smaller timeout but several retries. Given that this\n // is a separate connection pool we should never really run into issues with connection\n // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency.\n let lastErr: Error | undefined = undefined;\n for (let i = 0; i < 3; i++) {\n try {\n return await ddlLimiter(() => ensureDatabase(database));\n } catch (err) {\n lastErr = err;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n throw lastErr;\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Creates the missing Postgres schema if it does not exist\n *\n * @param dbConfig - The database config\n * @param schemas - The name of the schemas to create\n */\nexport async function ensurePgSchemaExists(\n dbConfig: Config,\n ...schemas: Array<string>\n): Promise<void> {\n const admin = await createPgDatabaseClient(dbConfig);\n const role = dbConfig.getOptionalString('role');\n\n try {\n const ensureSchema = async (database: string) => {\n if (role) {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [\n database,\n role,\n ]);\n } else {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);\n }\n };\n\n await Promise.all(\n schemas.map(database => ddlLimiter(() => ensureSchema(database))),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Drops the Postgres databases.\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to drop\n */\nexport async function dropPgDatabase(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig);\n try {\n await Promise.all(\n databases.map(async database => {\n await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database]));\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\nexport class PgConnector implements Connector {\n private readonly config: Config;\n private readonly prefix: string;\n\n constructor(config: Config, prefix: string) {\n this.config = config;\n this.prefix = prefix;\n }\n\n async getClient(\n pluginId: string,\n _deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginConfig = new ConfigReader(\n this.getConfigForPlugin(pluginId) as JsonObject,\n );\n\n const databaseName = this.getDatabaseName(pluginId);\n if (databaseName && this.getEnsureExistsConfig(pluginId)) {\n try {\n await ensurePgDatabaseExists(pluginConfig, databaseName);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,\n );\n }\n }\n\n let schemaOverrides;\n if (this.getPluginDivisionModeConfig() === 'schema') {\n schemaOverrides = defaultSchemaOverride(pluginId);\n if (\n this.getEnsureSchemaExistsConfig(pluginId) ||\n this.getEnsureExistsConfig(pluginId)\n ) {\n try {\n await ensurePgSchemaExists(pluginConfig, pluginId);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,\n );\n }\n }\n }\n\n const databaseClientOverrides = mergeDatabaseConfig(\n {},\n this.getDatabaseOverrides(pluginId),\n schemaOverrides,\n );\n\n const client = createPgDatabaseClient(\n pluginConfig,\n databaseClientOverrides,\n );\n\n return client;\n }\n\n /**\n * Provides the canonical database name for a given plugin.\n *\n * This method provides the effective database name which is determined using global\n * and plugin specific database config. If no explicit database name is configured\n * and `pluginDivisionMode` is not `schema`, this method will provide a generated name\n * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is\n * `schema`, it will fallback to using the default database for the knex instance.\n *\n * @param pluginId - Lookup the database name for given plugin\n * @returns String representing the plugin's database name\n */\n private getDatabaseName(pluginId: string): string | undefined {\n const connection = this.getConnectionConfig(pluginId);\n\n const databaseName = (connection as Knex.ConnectionConfig)?.database;\n\n // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied or fallback to default knex database\n if (this.getPluginDivisionModeConfig() === 'schema') {\n return databaseName;\n }\n\n // all other supported databases should fallback to an auto-prefixed name\n return databaseName ?? `${this.prefix}${pluginId}`;\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n private getRoleConfig(pluginId: string): string | undefined {\n return (\n this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n this.config.getOptionalString('role')\n );\n }\n\n /**\n * Provides the knexConfig which should be used for a given plugin.\n *\n * @param pluginId - Plugin to get the knexConfig for\n * @returns The merged knexConfig value or undefined if it isn't specified\n */\n private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {\n const pluginConfig = this.config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n\n const baseConfig = this.config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n\n return merge(baseConfig, pluginConfig);\n }\n\n private getEnsureExistsConfig(pluginId: string): boolean {\n const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true;\n return (\n this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ??\n baseConfig\n );\n }\n\n private getEnsureSchemaExistsConfig(pluginId: string): boolean {\n const baseConfig =\n this.config.getOptionalBoolean('ensureSchemaExists') ?? false;\n return (\n this.config.getOptionalBoolean(\n `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`,\n ) ?? baseConfig\n );\n }\n\n private getPluginDivisionModeConfig(): string {\n return this.config.getOptionalString('pluginDivisionMode') ?? 'database';\n }\n\n /**\n * Provides a Knex connection plugin config by combining base and plugin\n * config.\n *\n * This method provides a baseConfig for a plugin database connector. If the\n * client type has not been overridden, the global connection config will be\n * included with plugin specific config as the base. Values from the plugin\n * connection take precedence over the base. Base database name is omitted\n * unless `pluginDivisionMode` is set to `schema`.\n */\n private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig {\n const { overridden } = this.getClientType(pluginId);\n\n let baseConnection = normalizeConnection(this.config.get('connection'));\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The\n // `database` property from the base connection is omitted unless `pluginDivisionMode`\n // is set to `schema`.\n if (this.getPluginDivisionModeConfig() !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // get and normalize optional plugin specific database connection\n const connection = normalizeConnection(\n this.config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n (\n baseConnection as Knex.PgConnectionConfig\n ).application_name ||= `backstage_plugin_${pluginId}`;\n\n return {\n // include base connection if client type has not been overridden\n ...(overridden ? {} : baseConnection),\n ...connection,\n } as Knex.StaticConnectionConfig;\n }\n\n /**\n * Provides a Knex database config for a given plugin.\n *\n * This method provides a Knex configuration object along with the plugin's\n * client type.\n *\n * @param pluginId - The plugin that the database config should correspond with\n */\n private getConfigForPlugin(pluginId: string): Knex.Config {\n const { client } = this.getClientType(pluginId);\n const role = this.getRoleConfig(pluginId);\n\n return {\n ...this.getAdditionalKnexConfig(pluginId),\n client,\n connection: this.getConnectionConfig(pluginId),\n ...(role && { role }),\n };\n }\n\n /**\n * Provides a partial `Knex.Config`• database name override for a given plugin.\n *\n * @param pluginId - Target plugin to get database name override\n * @returns Partial `Knex.Config` with database name override\n */\n private getDatabaseOverrides(pluginId: string): Knex.Config {\n const databaseName = this.getDatabaseName(pluginId);\n return databaseName ? defaultNameOverride(databaseName) : {};\n }\n}\n"],"names":["limiterFactory","knexFactory","format","mergeDatabaseConfig","ForwardedError","ConfigReader","defaultSchemaOverride","merge","omit","defaultNameOverride"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"postgres.cjs.js","sources":["../../../../src/entrypoints/database/connectors/postgres.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 */\n\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport {\n Config,\n ConfigReader,\n readDurationFromConfig,\n} from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport {\n durationToMilliseconds,\n HumanDuration,\n JsonObject,\n} from '@backstage/types';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport limiterFactory from 'p-limit';\nimport { Client } from 'pg';\nimport { Connector } from '../types';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\nimport format from 'pg-format';\nimport { TokenCredential } from '@azure/identity';\n\n// Limits the number of concurrent DDL operations to 1\nconst ddlLimiter = limiterFactory(1);\n\n/**\n * Creates a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function createPgDatabaseClient(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);\n const database = knexFactory(knexConfig);\n\n const role = dbConfig.getOptionalString('role');\n\n if (role) {\n database.client.pool.on(\n 'createSuccess',\n async (_event: number, pgClient: Client) => {\n const query = format('SET ROLE %I', role);\n await pgClient.query(query);\n },\n );\n }\n return database;\n}\n\n/**\n * Builds a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function buildPgDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const config = mergeDatabaseConfig(\n dbConfig.get(),\n {\n connection: getPgConnectionConfig(dbConfig, !!overrides),\n useNullAsDefault: true,\n },\n overrides,\n );\n const mergedConfigReader = new ConfigReader(config);\n\n if (config.connection.type === 'default' || !config.connection.type) {\n const connectionValue = config.connection;\n const sanitizedConnection =\n typeof connectionValue === 'string' || connectionValue instanceof String\n ? connectionValue\n : // connection is an object, omit config-only props\n omit(connectionValue as Record<string, unknown>, [\n 'type',\n 'instance',\n 'tokenCredential',\n ]);\n\n return {\n ...config,\n connection: sanitizedConnection,\n };\n }\n\n switch (config.connection.type) {\n case 'azure':\n return buildAzurePgConfig(mergedConfigReader);\n case 'cloudsql':\n return buildCloudSqlConfig(mergedConfigReader);\n default:\n throw new Error(`Unknown connection type: ${config.connection.type}`);\n }\n}\n\n/* Note: the following type definition is intentionally duplicated in\n * /packages/backend-defaults/config.d.ts so the clientSecret property\n * can be annotated with \"@visibility secret\" there.\n */\nexport type AzureTokenCredentialConfig = {\n /**\n * How early before an access token expires to refresh it with a new one.\n * Defaults to 5 minutes\n * Supported formats:\n * - A string in the format of '1d', '2 seconds' etc. as supported by the `ms`\n * library.\n * - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'.\n * - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`.\n */\n tokenRenewableOffsetTime?: string | HumanDuration;\n /**\n * The client ID of a user-assigned managed identity.\n * If not provided, the system-assigned managed identity is used.\n */\n clientId?: string;\n clientSecret?: string;\n tenantId?: string;\n};\n\nexport async function buildAzurePgConfig(config: Config): Promise<Knex.Config> {\n const {\n DefaultAzureCredential,\n ManagedIdentityCredential,\n ClientSecretCredential,\n } = require('@azure/identity');\n\n const tokenConfig = config.getOptionalConfig('connection.tokenCredential');\n\n const tokenRenewableOffsetTime = durationToMilliseconds(\n tokenConfig?.has('tokenRenewableOffsetTime')\n ? readDurationFromConfig(tokenConfig, { key: 'tokenRenewableOffsetTime' })\n : { minutes: 5 },\n );\n\n const clientId = tokenConfig?.getOptionalString('clientId');\n const tenantId = tokenConfig?.getOptionalString('tenantId');\n const clientSecret = tokenConfig?.getOptionalString('clientSecret');\n let credential: TokenCredential;\n\n /**\n * Determine which TokenCredential to use based on provided config\n * 1. If clientId, tenantId and clientSecret are provided, use ClientSecretCredential\n * 2. If only clientId is provided, use ManagedIdentityCredential with user-assigned identity\n * 3. Otherwise, use DefaultAzureCredential (which may use system-assigned identity among other methods)\n */\n if (clientId && tenantId && clientSecret) {\n credential = new ClientSecretCredential(tenantId, clientId, clientSecret);\n } else if (clientId) {\n credential = new ManagedIdentityCredential(clientId);\n } else {\n credential = new DefaultAzureCredential();\n }\n\n const rawConfig = config.get() as Record<string, unknown>;\n\n const normalized = normalizeConnection(rawConfig.connection as any);\n const sanitizedConnection = omit(normalized, [\n 'type',\n 'instance',\n 'tokenCredential',\n ]) as Partial<Knex.StaticConnectionConfig>;\n\n async function getConnectionConfig() {\n const token = await credential.getToken(\n 'https://ossrdbms-aad.database.windows.net/.default',\n );\n\n if (!token) {\n throw new Error(\n 'Failed to acquire Azure access token for database authentication',\n );\n }\n\n const connectionConfig = {\n ...sanitizedConnection,\n password: token.token,\n expirationChecker: () =>\n /* return true if the token is within the renewable offset time */\n token.expiresOnTimestamp - tokenRenewableOffsetTime <= Date.now(),\n };\n\n return connectionConfig;\n }\n\n return {\n ...(rawConfig as Record<string, unknown>),\n connection: getConnectionConfig,\n };\n}\n\nexport async function buildCloudSqlConfig(\n config: Config,\n): Promise<Knex.Config> {\n const client = config.getOptionalString('client');\n\n if (client && client !== 'pg') {\n throw new Error('Cloud SQL only supports the pg client');\n }\n\n const instance = config.getOptionalString('connection.instance');\n if (!instance) {\n throw new Error('Missing instance connection name for Cloud SQL');\n }\n\n const {\n Connector: CloudSqlConnector,\n IpAddressTypes,\n AuthTypes,\n } = require('@google-cloud/cloud-sql-connector') as typeof import('@google-cloud/cloud-sql-connector');\n const connector = new CloudSqlConnector();\n\n type IpType = (typeof IpAddressTypes)[keyof typeof IpAddressTypes];\n const ipTypeRaw = config.getOptionalString('connection.ipAddressType');\n\n let ipType: IpType | undefined;\n if (ipTypeRaw !== undefined) {\n if (\n !(Object.values(IpAddressTypes) as Array<string | number>).includes(\n ipTypeRaw as any,\n )\n ) {\n throw new Error(\n `Invalid connection.ipAddressType: ${ipTypeRaw}; valid values: ${Object.values(\n IpAddressTypes,\n ).join(', ')}`,\n );\n }\n ipType = ipTypeRaw as unknown as IpType;\n }\n\n const clientOpts = await connector.getOptions({\n instanceConnectionName: instance,\n ipType: ipType ?? IpAddressTypes.PUBLIC,\n authType: AuthTypes.IAM,\n });\n\n const rawConfig = config.get() as Record<string, unknown>;\n const normalized = normalizeConnection(rawConfig.connection as any);\n const sanitizedConnection = omit(normalized, [\n 'type',\n 'instance',\n ]) as Partial<Knex.StaticConnectionConfig>;\n\n return {\n ...(rawConfig as Record<string, unknown>),\n client: 'pg',\n connection: {\n ...sanitizedConnection,\n ...clientOpts,\n },\n };\n}\n\n/**\n * Gets the postgres connection config\n *\n * @param dbConfig - The database config\n * @param parseConnectionString - Flag to explicitly control connection string parsing\n */\nexport function getPgConnectionConfig(\n dbConfig: Config,\n parseConnectionString?: boolean,\n): Knex.PgConnectionConfig | string {\n const connection = dbConfig.get('connection') as any;\n const isConnectionString =\n typeof connection === 'string' || connection instanceof String;\n const autoParse = typeof parseConnectionString !== 'boolean';\n\n const shouldParseConnectionString = autoParse\n ? isConnectionString\n : parseConnectionString && isConnectionString;\n\n return shouldParseConnectionString\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * Parses a connection string using pg-connection-string\n *\n * @param connectionString - The postgres connection string\n */\nexport function parsePgConnectionString(connectionString: string) {\n const parse = requirePgConnectionString();\n return parse(connectionString);\n}\n\nfunction requirePgConnectionString() {\n try {\n return require('pg-connection-string').parse;\n } catch (e) {\n throw new ForwardedError(\"Postgres: Install 'pg-connection-string'\", e);\n }\n}\n\n/**\n * Creates the missing Postgres database if it does not exist\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to create\n */\nexport async function ensurePgDatabaseExists(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig, {\n connection: {\n database: 'postgres',\n },\n pool: {\n min: 0,\n acquireTimeoutMillis: 10000,\n },\n });\n\n try {\n const ensureDatabase = async (database: string) => {\n const result = await admin\n .from('pg_database')\n .where('datname', database)\n .count<Record<string, { count: string }>>();\n\n if (parseInt(result[0].count, 10) > 0) {\n return;\n }\n\n await admin.raw(`CREATE DATABASE ??`, [database]);\n };\n\n await Promise.all(\n databases.map(async database => {\n // For initial setup we use a smaller timeout but several retries. Given that this\n // is a separate connection pool we should never really run into issues with connection\n // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency.\n let lastErr: Error | undefined = undefined;\n for (let i = 0; i < 3; i++) {\n try {\n return await ddlLimiter(() => ensureDatabase(database));\n } catch (err) {\n lastErr = err;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n throw lastErr;\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Creates the missing Postgres schema if it does not exist\n *\n * @param dbConfig - The database config\n * @param schemas - The name of the schemas to create\n */\nexport async function ensurePgSchemaExists(\n dbConfig: Config,\n ...schemas: Array<string>\n): Promise<void> {\n const admin = await createPgDatabaseClient(dbConfig);\n const role = dbConfig.getOptionalString('role');\n\n try {\n const ensureSchema = async (database: string) => {\n if (role) {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [\n database,\n role,\n ]);\n } else {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);\n }\n };\n\n await Promise.all(\n schemas.map(database => ddlLimiter(() => ensureSchema(database))),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Drops the Postgres databases.\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to drop\n */\nexport async function dropPgDatabase(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig);\n try {\n await Promise.all(\n databases.map(async database => {\n await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database]));\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * The computed configuration for a plugin's postgres database connection.\n */\nexport interface PgPluginDatabaseConfig {\n /** The database client type (e.g. 'pg') */\n client: string;\n /** Whether the client type was overridden at the plugin level */\n clientOverridden: boolean;\n /** The optional role to set on connections */\n role: string | undefined;\n /** Additional knex configuration merged from base and plugin config */\n additionalKnexConfig: JsonObject | undefined;\n /** Whether to ensure the database exists */\n ensureExists: boolean;\n /** Whether to ensure the schema exists */\n ensureSchemaExists: boolean;\n /** The plugin division mode ('database' or 'schema') */\n pluginDivisionMode: string;\n /** The connection configuration */\n connection: Knex.PgConnectionConfig;\n /** The database name, if any */\n databaseName: string | undefined;\n /** Database client overrides including schema overrides if applicable */\n databaseClientOverrides: Knex.Config;\n /** The full knex config for the plugin */\n knexConfig: Knex.Config;\n}\n\n/**\n * Computes all postgres database configuration for a plugin from the provided config.\n *\n * @param config - The database config object\n * @param pluginId - The plugin ID to compute config for\n * @param prefix - The database name prefix (e.g. 'backstage_plugin_')\n * @returns All computed configuration values for the plugin\n */\nexport function computePgPluginConfig(\n config: Config,\n pluginId: string,\n prefix: string,\n): PgPluginDatabaseConfig {\n // Client type\n const pluginClient = config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n const baseClient = config.getString('client');\n const client = pluginClient ?? baseClient;\n const clientOverridden = client !== baseClient;\n\n // Role\n const role =\n config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n config.getOptionalString('role');\n\n // Additional knex config\n const pluginKnexConfig = config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n const baseKnexConfig = config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n const additionalKnexConfig = merge(baseKnexConfig, pluginKnexConfig);\n\n // Ensure exists flags\n const baseEnsureExists = config.getOptionalBoolean('ensureExists') ?? true;\n const ensureExists =\n config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ??\n baseEnsureExists;\n\n const baseEnsureSchemaExists =\n config.getOptionalBoolean('ensureSchemaExists') ?? false;\n const ensureSchemaExists =\n config.getOptionalBoolean(\n `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`,\n ) ?? baseEnsureSchemaExists;\n\n // Plugin division mode\n const pluginDivisionMode =\n config.getOptionalString('pluginDivisionMode') ?? 'database';\n\n // Connection config\n let baseConnection = normalizeConnection(config.get('connection'));\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`.\n // The `database` property from the base connection is omitted unless\n // `pluginDivisionMode` is set to `schema`.\n if (pluginDivisionMode !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // Get and normalize optional plugin specific database connection\n const pluginConnection = normalizeConnection(\n config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n (\n baseConnection as Knex.PgConnectionConfig\n ).application_name ||= `backstage_plugin_${pluginId}`;\n\n const connection = {\n // Include base connection if client type has not been overridden\n ...(clientOverridden ? {} : baseConnection),\n ...pluginConnection,\n } as Knex.PgConnectionConfig;\n\n // Database name\n const connectionDatabaseName = (connection as Knex.ConnectionConfig)\n ?.database;\n let databaseName: string | undefined;\n\n if (pluginDivisionMode === 'schema') {\n // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied\n // or fallback to default knex database\n databaseName = connectionDatabaseName;\n } else {\n // All other supported databases should fallback to an auto-prefixed name\n databaseName = connectionDatabaseName ?? `${prefix}${pluginId}`;\n }\n\n // Database client overrides\n let databaseClientOverrides: Knex.Config = {};\n if (databaseName) {\n databaseClientOverrides = { connection: { database: databaseName } };\n }\n if (pluginDivisionMode === 'schema') {\n databaseClientOverrides = mergeDatabaseConfig({}, databaseClientOverrides, {\n searchPath: [pluginId],\n });\n }\n\n // Full knex config for plugin\n const knexConfig: Knex.Config = {\n ...additionalKnexConfig,\n client,\n connection,\n ...(role && { role }),\n };\n\n return {\n client,\n clientOverridden,\n role,\n additionalKnexConfig,\n ensureExists,\n ensureSchemaExists,\n pluginDivisionMode,\n connection,\n databaseName,\n databaseClientOverrides,\n knexConfig,\n };\n}\n\nexport class PgConnector implements Connector {\n private readonly config: Config;\n private readonly prefix: string;\n\n constructor(config: Config, prefix: string) {\n this.config = config;\n this.prefix = prefix;\n }\n\n async getClient(\n pluginId: string,\n _deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginDbConfig = computePgPluginConfig(\n this.config,\n pluginId,\n this.prefix,\n );\n\n if (pluginDbConfig.databaseName && pluginDbConfig.ensureExists) {\n try {\n await ensurePgDatabaseExists(this.config, pluginDbConfig.databaseName);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that '${pluginDbConfig.databaseName}' exists, ${error}`,\n );\n }\n }\n\n if (pluginDbConfig.pluginDivisionMode === 'schema') {\n if (pluginDbConfig.ensureSchemaExists || pluginDbConfig.ensureExists) {\n try {\n await ensurePgSchemaExists(this.config, pluginId);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,\n );\n }\n }\n }\n\n const client = createPgDatabaseClient(\n this.config,\n mergeDatabaseConfig(\n pluginDbConfig.knexConfig,\n pluginDbConfig.databaseClientOverrides,\n ),\n );\n\n return client;\n }\n}\n"],"names":["limiterFactory","knexFactory","format","config","mergeDatabaseConfig","ConfigReader","omit","durationToMilliseconds","readDurationFromConfig","ForwardedError","merge"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ var config = require('@backstage/config');
|
|
|
5
5
|
var fs = require('fs-extra');
|
|
6
6
|
var knexFactory = require('knex');
|
|
7
7
|
var lodash = require('lodash');
|
|
8
|
-
var platformPath = require('path');
|
|
8
|
+
var platformPath = require('node:path');
|
|
9
9
|
var mergeDatabaseConfig = require('./mergeDatabaseConfig.cjs.js');
|
|
10
10
|
|
|
11
11
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|