-
-
Save jakobo/b3203b832c28f6cac8c28225615752f7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable n/no-process-env, unicorn/no-process-exit */ | |
import process from "node:process"; | |
import * as url from "node:url"; | |
import * as pulumi from "@pulumi/pulumi"; | |
import { local } from "@pulumi/command"; | |
import { acquireToken, fromEnv, fromState, toState } from "./helpers.js"; | |
const __filename = url.fileURLToPath(import.meta.url); | |
// an internal mapping of cloud provider & region to mongo location arguments | |
const regionToLocationMap: Record<string, Record<string, string>> = { | |
aws: { | |
"us-west-2": "US-OR", | |
}, | |
}; | |
type MongoAPIResponse = { | |
name: string; | |
provider_region: string; | |
location: string; | |
deployment_model: string; | |
environment: string; | |
_id: string; | |
client_app_id: string; | |
domain_id: string; | |
group_id: string; | |
last_used: number; | |
last_modified: number; | |
product: string; | |
}; | |
type CLIEnv = SaveEnv & { | |
MONGO_TOKEN?: string; | |
}; | |
type SaveEnv = { | |
MONGO_CLOUD: string; | |
MONGO_DEPLOYMENT_MODEL: string; | |
MONGO_ENVIRONMENT: string; | |
MONGO_NAME: string; | |
MONGO_PRODUCT: string; | |
MONGO_PROJECT_ID: string; | |
MONGO_REGION: string; | |
}; | |
if (process.env.PULUMI_RUN === "create") { | |
const { | |
MONGO_CLOUD, | |
MONGO_DEPLOYMENT_MODEL, | |
MONGO_ENVIRONMENT, | |
MONGO_NAME, | |
MONGO_PRODUCT, | |
MONGO_PROJECT_ID, | |
MONGO_REGION, | |
MONGO_TOKEN, | |
} = fromEnv({ | |
MONGO_CLOUD: true, | |
MONGO_DEPLOYMENT_MODEL: true, | |
MONGO_ENVIRONMENT: true, | |
MONGO_NAME: true, | |
MONGO_PRODUCT: true, | |
MONGO_PROJECT_ID: true, | |
MONGO_REGION: true, | |
MONGO_TOKEN: true, | |
}); | |
const url = `https://realm.mongodb.com/api/admin/v3.0/groups/${MONGO_PROJECT_ID}/apps?product=${ | |
MONGO_PRODUCT ?? "data-api" | |
}`; | |
const saveEnv: SaveEnv = { | |
MONGO_CLOUD, | |
MONGO_DEPLOYMENT_MODEL, | |
MONGO_ENVIRONMENT, | |
MONGO_NAME, | |
MONGO_PRODUCT, | |
MONGO_PROJECT_ID, | |
MONGO_REGION, | |
}; | |
// check before creating | |
const checkResponse = await fetch(url, { | |
method: "GET", | |
headers: { | |
"Content-Type": "application/json", | |
Accept: "application/json", | |
Authorization: `Bearer ${MONGO_TOKEN}`, | |
}, | |
}); | |
const checkResult = (await checkResponse.json()) as MongoAPIResponse[]; | |
if (checkResult?.[0]) { | |
// return existing instead of creating | |
process.stdout.write(toState(checkResult[0], saveEnv)); | |
process.exit(0); | |
} | |
const location = | |
regionToLocationMap?.[MONGO_CLOUD ?? ""]?.[MONGO_REGION ?? ""]; | |
if (!location && MONGO_DEPLOYMENT_MODEL === "LOCAL") | |
throw new TypeError("Invalid cloud or region"); | |
const response = await fetch(url, { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
Accept: "application/json", | |
Authorization: `Bearer ${MONGO_TOKEN}`, | |
}, | |
body: JSON.stringify({ | |
name: MONGO_NAME, | |
provider_region: | |
location && MONGO_CLOUD && MONGO_REGION | |
? `${MONGO_CLOUD}-${MONGO_REGION}` | |
: "", | |
location: MONGO_DEPLOYMENT_MODEL === "LOCAL" ? location : "", | |
deployment_model: MONGO_DEPLOYMENT_MODEL, | |
environment: MONGO_ENVIRONMENT, | |
}), | |
}); | |
const result = (await response.json()) as MongoAPIResponse; | |
// output on stdout | |
process.stdout.write(toState(result, saveEnv)); | |
process.exit(0); | |
} | |
if (process.env.PULUMI_RUN === "update") { | |
throw new Error("Update is not implemented for pulumi command.local"); | |
} | |
if (process.env.PULUMI_RUN === "delete") { | |
// delete flow | |
const { PULUMI_COMMAND_STDOUT, MONGO_TOKEN } = fromEnv({ | |
PULUMI_COMMAND_STDOUT: true, | |
MONGO_TOKEN: true, | |
}); | |
const last = fromState<MongoAPIResponse, SaveEnv>(PULUMI_COMMAND_STDOUT); | |
const url = `https://realm.mongodb.com/api/admin/v3.0/groups/${last.env.MONGO_PROJECT_ID}/apps/${last.response._id}`; | |
const response = await fetch(url, { | |
method: "DELETE", | |
headers: { | |
"Content-Type": "application/json", | |
Accept: "application/json", | |
Authorization: `Bearer ${MONGO_TOKEN}`, | |
}, | |
}); | |
if (response.status !== 204) { | |
throw new Error("Unable to delete application"); | |
} | |
process.stdout.write(PULUMI_COMMAND_STDOUT ?? "{}"); | |
process.exit(0); | |
} | |
if (process.env.PULUMI_RUN === "read") { | |
// Read flow | |
throw new Error("Read is not implemented for pulumi command.local"); | |
} | |
// resource using pulumi local command | |
type MongoAppArgs = { | |
projectId: pulumi.Input<string>; | |
product?: pulumi.Input<"data-api">; | |
cloud?: pulumi.Input<"aws">; | |
region?: pulumi.Input<string>; | |
deploymentModel?: pulumi.Input<"GLOBAL" | "LOCAL">; | |
environment?: pulumi.Input< | |
"" | "development" | "testing" | "qa" | "production" | |
>; | |
}; | |
export class MongoRealmApp extends pulumi.ComponentResource { | |
// inputs | |
public readonly name!: pulumi.Output<string>; | |
public readonly projectId!: pulumi.Output<string>; | |
public readonly product!: pulumi.Output<string>; | |
public readonly cloud!: pulumi.Output<string>; | |
public readonly region!: pulumi.Output<string>; | |
public readonly deploymentModel!: pulumi.Output<string>; | |
public readonly environment!: pulumi.Output<string>; | |
// outputs | |
public readonly id!: pulumi.Output<string>; | |
public readonly appId!: pulumi.Output<string>; | |
public readonly clientAppId!: pulumi.Output<string>; | |
constructor( | |
name: string, | |
args: MongoAppArgs, | |
options?: pulumi.ComponentResourceOptions | |
) { | |
super( | |
"taskless:mongo:realm:application", | |
name, | |
{ | |
// | |
...args, | |
id: undefined /* out */, | |
appId: undefined /* out */, | |
clientAppId: undefined /* out */, | |
}, | |
options | |
); | |
const env: Record<keyof CLIEnv, string | pulumi.Input<string>> = pulumi | |
.all([ | |
args.cloud, | |
args.deploymentModel, | |
args.environment, | |
name, | |
args.product, | |
args.projectId, | |
args.region, | |
acquireToken(), | |
]) | |
.apply( | |
([ | |
cloud, | |
deploymentModel, | |
environment, | |
n, | |
product, | |
projectId, | |
region, | |
token, | |
]) => ({ | |
MONGO_CLOUD: cloud ?? "aws", | |
MONGO_DEPLOYMENT_MODEL: deploymentModel ?? "GLOBAL", | |
MONGO_ENVIRONMENT: environment ?? "development", | |
MONGO_NAME: n, | |
MONGO_PRODUCT: product ?? "data-api", | |
MONGO_PROJECT_ID: projectId, | |
MONGO_REGION: region ?? "", | |
MONGO_TOKEN: token, | |
}) | |
); | |
const app = new local.Command( | |
`${name}-cmd`, | |
{ | |
create: `PULUMI_RUN=create pnpm exec ts-node ${__filename}`, | |
delete: `PULUMI_RUN=delete pnpm exec ts-node ${__filename}`, | |
environment: env, | |
}, | |
{ parent: this } | |
); | |
const response = app.stdout.apply((s) => JSON.parse(s) as MongoAPIResponse); | |
// inputs | |
this.name = pulumi.output(name); | |
this.projectId = pulumi.output(args.projectId); | |
this.product = pulumi.output(args.product ?? "data-api"); | |
this.cloud = pulumi.output(args.cloud ?? "aws"); | |
this.region = response.apply((r) => r.provider_region); | |
this.deploymentModel = response.apply((r) => r.deployment_model); | |
this.environment = response.apply((r) => r.environment); | |
// outputs | |
this.id = response.apply((r) => r._id); | |
this.appId = response.apply((r) => r._id); | |
this.clientAppId = response.apply((r) => r.client_app_id); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable n/no-process-env, unicorn/no-process-exit */ | |
import process from "node:process"; | |
import * as url from "node:url"; | |
import * as pulumi from "@pulumi/pulumi"; | |
import { local } from "@pulumi/command"; | |
import { | |
acquireToken, | |
fromEnv, | |
fromState, | |
toState, | |
logger, | |
} from "./helpers.js"; | |
const __filename = url.fileURLToPath(import.meta.url); | |
const log = logger(__filename); | |
type MongoAPIResponse = { | |
_id: string; | |
name: string; | |
type: string; | |
disabled: true; | |
}; | |
type CLIEnv = SavedEnv & { | |
/* ENV vars here */ | |
MONGO_TOKEN: string; | |
}; | |
type SavedEnv = { | |
/* ENV vars here */ | |
MONGO_PROJECT_ID: string; | |
MONGO_APP_ID: string; | |
MONGO_TYPE: string; | |
}; | |
if (process.env.PULUMI_RUN === "create") { | |
log(process.env); | |
const { MONGO_PROJECT_ID, MONGO_APP_ID, MONGO_TOKEN, MONGO_TYPE } = fromEnv({ | |
MONGO_PROJECT_ID: true, | |
MONGO_APP_ID: true, | |
MONGO_TOKEN: true, | |
MONGO_TYPE: true, | |
}); | |
const saveEnv = { | |
MONGO_PROJECT_ID, | |
MONGO_APP_ID, | |
MONGO_TYPE, | |
}; | |
// Do code | |
const url = `https://realm.mongodb.com/api/admin/v3.0/groups/${MONGO_PROJECT_ID}/apps/${MONGO_APP_ID}/auth_providers`; | |
// check if exists | |
const checkResponse = await fetch(url, { | |
method: "GET", | |
headers: { | |
"Content-Type": "application/json", | |
Accept: "application/json", | |
Authorization: `Bearer ${MONGO_TOKEN}`, | |
}, | |
}); | |
const checkResult = (await checkResponse.json()) as MongoAPIResponse[]; | |
const exists = checkResult.find((r) => r.type === MONGO_TYPE); | |
if (exists) { | |
// output on stdout | |
process.stdout.write(toState<MongoAPIResponse>(exists, saveEnv)); | |
process.exit(0); | |
} | |
const response = await fetch(url, { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
Accept: "application/json", | |
Authorization: `Bearer ${MONGO_TOKEN}`, | |
}, | |
body: JSON.stringify({ | |
name: MONGO_TYPE, | |
type: MONGO_TYPE, | |
disabled: false, | |
}), | |
}); | |
const result = (await response.json()) as MongoAPIResponse; | |
// output on stdout | |
process.stdout.write(toState<MongoAPIResponse>(result, saveEnv)); | |
process.exit(0); | |
} | |
if (process.env.PULUMI_RUN === "update") { | |
throw new Error("Update is not implemented for pulumi command.local"); | |
} | |
if (process.env.PULUMI_RUN === "delete") { | |
// delete flow | |
const { PULUMI_COMMAND_STDOUT, MONGO_TOKEN } = fromEnv({ | |
PULUMI_COMMAND_STDOUT: true, | |
MONGO_TOKEN: true, | |
}); | |
const last = fromState<MongoAPIResponse, SavedEnv>(PULUMI_COMMAND_STDOUT); | |
// Do code | |
const url = `https://realm.mongodb.com/api/admin/v3.0/groups/${last.env.MONGO_PROJECT_ID}/apps/${last.env.MONGO_APP_ID}/auth_providers/${last.response._id}`; | |
await fetch(url, { | |
method: "DELETE", | |
headers: { | |
"Content-Type": "application/json", | |
Accept: "application/json", | |
Authorization: `Bearer ${MONGO_TOKEN}`, | |
}, | |
}); | |
process.stdout.write(PULUMI_COMMAND_STDOUT ?? "{}"); | |
process.exit(0); | |
} | |
if (process.env.PULUMI_RUN === "read") { | |
// Read flow | |
throw new Error("Read is not implemented for pulumi command.local"); | |
} | |
// resource using pulumi local command | |
type MongoRealmAuthProviderArgs = { | |
projectId: pulumi.Input<string>; | |
applicationId: pulumi.Input<string>; | |
type: pulumi.Input<"anon-user" | "api-key">; | |
}; | |
export class MongoRealmAuthProvider extends pulumi.ComponentResource { | |
// inputs (copy from args) | |
public readonly projectId!: pulumi.Output<string>; | |
public readonly applicationId!: pulumi.Output<string>; | |
public readonly type!: pulumi.Output<string>; | |
// outputs | |
public readonly id!: pulumi.Output<string>; | |
// public readonly clientAppId!: pulumi.Output<string>; | |
constructor( | |
name: string, | |
args: MongoRealmAuthProviderArgs, | |
options?: pulumi.ComponentResourceOptions | |
) { | |
super( | |
"taskless:mongo:realm:authProvider", | |
name, | |
{ | |
// | |
...args, | |
id: undefined /* out */, | |
}, | |
options | |
); | |
const env: Record<keyof CLIEnv, string | pulumi.Input<string>> = pulumi | |
.all([acquireToken(), args.projectId, args.applicationId, args.type]) | |
.apply(([token, projectId, appId, type]) => ({ | |
MONGO_TOKEN: token, | |
MONGO_PROJECT_ID: projectId, | |
MONGO_APP_ID: appId, | |
MONGO_TYPE: type, | |
})); | |
const app = new local.Command( | |
`${name}-cmd`, | |
{ | |
create: `PULUMI_RUN=create pnpm exec ts-node ${__filename}`, | |
delete: `PULUMI_RUN=delete pnpm exec ts-node ${__filename}`, | |
environment: env, | |
}, | |
{ parent: this } | |
); | |
const response = app.stdout.apply((s) => JSON.parse(s) as MongoAPIResponse); | |
// inputs | |
this.projectId = pulumi.output(args.projectId); | |
this.applicationId = pulumi.output(args.applicationId); | |
this.type = pulumi.output(args.type); | |
// outputs | |
this.id = response.apply((r) => r._id); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as pulumi from "@pulumi/pulumi"; | |
import { MongoRealmApp } from "./modules/application.js"; | |
import { MongoRealmDataAPIConfig } from "./modules/dataApiConfig.js"; | |
import { MongoRealmAuthProvider } from "./modules/authProvider.js"; | |
import { MongoRealmDataSource } from "./modules/dataSource.js"; | |
import { MongoRealmDefaultRule } from "./modules/defaultRule.js"; | |
type MongoRealmDataAPIArgs = { | |
/** The Mongo project ID. Also somtimes called the Group ID or Project ID */ | |
projectId: pulumi.Input<string>; | |
/** The name of the Mongo Cluster to attach the Data API to */ | |
clusterName: pulumi.Input<string>; | |
/** An environment for this mongo cluster. One of "", "development", "testing", "qa", "production" */ | |
environment?: pulumi.Input< | |
"" | "development" | "testing" | "qa" | "production" | |
>; | |
/** The deployment model for the Data API */ | |
deploymentModel?: pulumi.Input<"GLOBAL" | "LOCAL">; | |
/** The cloud provider. One of "aws" */ | |
cloud: pulumi.Input<string>; | |
/** The region within the cloud provider. Varies by cloud provider */ | |
region: pulumi.Input<string>; | |
}; | |
/** | |
* Create a MongoDB Data API via App Services, and attach the necessary | |
* pemissions for it to function. | |
* Built similar to the AWS Crosswalk pattern | |
* See: https://www.mongodb.com/docs/atlas/app-services/admin/api/v3 | |
*/ | |
export class MongoRealmDataAPI extends pulumi.ComponentResource { | |
// inputs | |
/** The Mongo Organization ID. Also called a Group ID or Project ID */ | |
public readonly projectId!: pulumi.Output<string>; | |
/** The ID of the Mongo Cluster this Data API was attached to */ | |
public readonly clusterName!: pulumi.Output<string>; | |
/** The environment this Data API was configured with */ | |
public readonly environment!: pulumi.Output<string>; | |
/** The cloud provider for this Data API gateway */ | |
public readonly cloud!: pulumi.Output<string>; | |
/** The cloud provider region for this Data API gateway */ | |
public readonly region!: pulumi.Output<string>; | |
// outputs | |
/** The internal ID of the Data API application */ | |
public readonly appId!: pulumi.Output<string>; | |
/** The friendly name of the Data API application */ | |
public readonly appName!: pulumi.Output<string>; | |
/** The client's app ID. Used for HTTPS requests and mongo client connections */ | |
public readonly clientAppId!: pulumi.Output<string>; | |
/** An Atlas URL for environments that cannot use mongo connection strings */ | |
public readonly httpEndpoint!: pulumi.Output<string>; | |
/** The Atlas Data Source name for connecting */ | |
public readonly dataSource!: pulumi.Output<string>; | |
constructor( | |
name: string, | |
args: MongoRealmDataAPIArgs, | |
options?: pulumi.ComponentResourceOptions | |
) { | |
// checks and defaults | |
if (!args.projectId) throw new Error("projectId is required"); | |
if (!args.clusterName) throw new Error("clusterName is required"); | |
args.deploymentModel = args.deploymentModel ?? "GLOBAL"; | |
args.cloud = args.cloud ?? "aws"; | |
args.region = args.region ?? "us-west-2"; | |
super( | |
"taskless:mongo:realm:dataAPI:pkg", | |
name, | |
{ | |
...args, | |
appId: undefined /* out */, | |
appName: undefined /* out */, | |
clientAppId: undefined /* out */, | |
apiKey: undefined /* out */, | |
connectionString: undefined /* out */, | |
httpEndpoint: undefined /* out */, | |
}, | |
options | |
); | |
// the mongo app | |
const app = new MongoRealmApp( | |
`${name}-application`, | |
{ | |
projectId: args.projectId, | |
product: "data-api", | |
cloud: "aws", | |
region: args.region, | |
}, | |
{ parent: this } | |
); | |
// the data api config for the mongo app | |
const dataApiConfig = new MongoRealmDataAPIConfig( | |
`${name}-config`, | |
{ | |
projectId: args.projectId, | |
applicationId: app.appId, | |
version: "v1", | |
format: "EJSON", | |
}, | |
{ parent: this } | |
); | |
// an auth provider for the mongo app | |
const authProvider = new MongoRealmAuthProvider( | |
`${name}-auth-provider`, | |
{ | |
projectId: args.projectId, | |
applicationId: app.appId, | |
type: "api-key", | |
}, | |
{ parent: this } | |
); | |
// a data source that connects the mongo app to a cluster | |
const dataSource = new MongoRealmDataSource( | |
`${name}-data-source`, | |
{ | |
projectId: args.projectId, | |
applicationId: app.appId, | |
name: args.clusterName, | |
type: "mongodb-atlas", | |
config: { | |
clusterName: args.clusterName, | |
}, | |
}, | |
{ parent: this } | |
); | |
// default rules for the data source | |
const defaultRule = new MongoRealmDefaultRule( | |
`${name}-default-rule`, | |
{ | |
projectId: args.projectId, | |
applicationId: app.appId, | |
serviceId: dataSource.id, | |
}, | |
{ parent: this } | |
); | |
const httpEndpoint = pulumi | |
.all([ | |
args.region, | |
args.cloud, | |
args.deploymentModel, | |
app.clientAppId, | |
dataApiConfig.version, | |
]) | |
.apply(([region, cloud, deploymentModel, clientAppId, version]) => { | |
const domainPrefix = | |
deploymentModel === "GLOBAL" ? "" : `${region}.${cloud}.`; | |
return `https://${domainPrefix}data.mongodb-api.com/app/${clientAppId}/endpoint/data/${version}`; | |
}); | |
// inputs | |
this.projectId = pulumi.output(args.projectId); | |
this.clusterName = pulumi.output(args.clusterName); | |
// outputs and derrived inputs | |
this.environment = app.environment; | |
this.cloud = app.cloud; | |
this.region = app.region; | |
this.appId = app.appId; | |
this.appName = app.name; | |
this.clientAppId = app.clientAppId; | |
this.httpEndpoint = httpEndpoint; | |
this.dataSource = dataSource.name; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment