Skip to content

Instantly share code, notes, and snippets.

@jakobo
Last active April 22, 2023 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakobo/bda66c77da6f9bfd4c0cdd50392f9ce4 to your computer and use it in GitHub Desktop.
Save jakobo/bda66c77da6f9bfd4c0cdd50392f9ce4 to your computer and use it in GitHub Desktop.
import * as pulumi from "@pulumi/pulumi";
import { getToken } from "./helpers.js";
import got from "got";
interface MongoApplicationArgs {
publicKey: pulumi.Input<string>;
privateKey: pulumi.Input<string>;
projectId: pulumi.Input<string>;
product: pulumi.Input<"data-api" | "standard">;
providerRegion?: pulumi.Input<string>;
location?: pulumi.Input<string>;
deploymentModel?: pulumi.Input<string>;
environment?: pulumi.Input<string>;
}
export class MongoApplication extends pulumi.dynamic.Resource {
// pass through inputs
public readonly publicKey!: pulumi.Output<string>;
public readonly privateKey!: pulumi.Output<string>;
public readonly projectId!: pulumi.Output<string>;
public readonly product!: pulumi.Output<string>;
public readonly providerRegion!: pulumi.Output<string>;
public readonly location!: pulumi.Output<string>;
public readonly deploymentModel!: pulumi.Output<string>;
public readonly environment!: pulumi.Output<string>;
// new outputs
public readonly clientAppId!: pulumi.Output<string>;
constructor(
name: string,
args: MongoApplicationArgs,
opts?: pulumi.CustomResourceOptions
) {
// localized config
// https://github.com/pulumi/pulumi/issues/4512
// const config = new pulumi.Config("mongodbatlas");
// const publicKey = config.getSecret("publicKey");
// const privateKey = config.getSecret("privateKey");
// required args
if (!args.publicKey) throw new Error("publicKey is required");
if (!args.privateKey) throw new Error("privateKey is required");
// defaults
args.product = args.product ?? "standard";
args.providerRegion = args.providerRegion ?? "aws-us-west-2";
args.location = args.location ?? "US-OR";
args.deploymentModel = args.deploymentModel ?? "LOCAL";
args.environment = args.environment ?? "";
// register
super(
new MongoApplicationProvider(),
name,
{
...args,
},
opts
);
}
}
interface MongoApplicationProviderArgs {
projectId: string;
product: string;
providerRegion: string;
location: string;
deploymentModel: string;
environment: string;
// added by resource
publicKey: string;
privateKey: string;
}
interface MongoApplicationProviderResult extends MongoApplicationProviderArgs {
// added by provider
clientAppId: string;
}
interface MongoApplicationAPIResponse {
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;
}
class MongoApplicationProvider implements pulumi.dynamic.ResourceProvider {
async create(
inputs: MongoApplicationProviderArgs
): Promise<pulumi.dynamic.CreateResult<MongoApplicationProviderResult>> {
const accessToken = await getToken(inputs.publicKey, inputs.privateKey);
const response = await got
.post(
`https://realm.mongodb.com/api/admin/v3.0/groups/${inputs.projectId}/apps?product=${inputs.product}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
json: {
provider_region: inputs.providerRegion,
location: inputs.location,
deployment_model: inputs.deploymentModel,
environment: inputs.environment,
},
}
)
.json<MongoApplicationAPIResponse>();
return {
id: response._id,
outs: {
...inputs,
clientAppId: response.client_app_id,
},
};
}
async delete(
id: pulumi.ID,
props: MongoApplicationProviderResult
): Promise<void> {
await got.delete(
`https://realm.mongodb.com/api/admin/v3.0/groups/${props.projectId}/apps/${id}`
);
}
}
import got from "got";
interface GetTokenResponse {
access_token: string;
refresh_token: string;
user_id: string;
device_id: string;
}
/** Get mongo credentials */
export const getToken = async (publicKey: string, privateKey: string) => {
const result = await got
.post(
"https://realm.mongodb.com/api/admin/v3.0/auth/providers/mongodb-cloud/login",
{
json: {
username: publicKey,
apiKey: privateKey,
},
}
)
.json<GetTokenResponse>();
return result.access_token;
};
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as mongodbatlas from "@pulumi/mongodbatlas";
import * as random from "@pulumi/random";
import * as mongoappservices from "../external/mongo.js";
// ...
const mc = new pulumi.Config("mongodbatlas");
const publicKey = mc.getSecret("publicKey") as pulumi.OutputInstance<string>; // cannot be Output<string>
const privateKey = mc.getSecret("privateKey") as pulumi.OutputInstance<string>; // cannot be Output<string>
const project = new mongodbatlas.Project(IDENTIFIER, {
orgId: "[reacted]",
isDataExplorerEnabled: true,
isPerformanceAdvisorEnabled: true,
isRealtimePerformancePanelEnabled: true,
isSchemaAdvisorEnabled: true,
});
// ...
// Atlas Services App
const application = new mongoappservices.MongoApplication(IDENTIFIER, {
publicKey,
privateKey,
projectId: project.id,
product: "data-api",
});
name: infra
description: Infastructure
runtime:
name: nodejs
options:
# See https://github.com/TypeStrong/ts-node/issues/1007
# Add experimental-fetch node 18+
nodeargs: "--loader ts-node/esm --no-warnings --experimental-fetch"
{
"compilerOptions": {
"outDir": "bin",
"module": "ES2020",
"moduleResolution": "Node16",
"target": "ES2020",
"strict": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"alwaysStrict": false,
"declaration": false,
"downlevelIteration": true,
"importHelpers": true,
"inlineSources": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,
"pretty": true,
// https://github.com/microsoft/TypeScript/issues/50175#issuecomment-1204986989
// "skipLibCheck": true,
"sourceMap": true,
"strictBindCallApply": false,
"types": ["node"]
},
"exclude": ["node_modules", "dist"],
// ts-node common settings
"ts-node": {
"esm": true
}
}
$pulumi preview -v=3 2> out.txt
Previewing update ([redacted]/dev)
View in Browser (Ctrl+O): https://app.pulumi.com/[redacted]/infra/dev/previews/[redacted]
Type Name Plan Info
pulumi:pulumi:Stack infra-dev 1 error
Diagnostics:
pulumi:pulumi:Stack (infra-dev):
error: Error serializing '() => provider': index.js(39,42)
'() => provider': index.js(39,42): captured
variable 'provider' which indirectly referenced
function 'MongoApplicationProvider': application.ts(29,0): which referenced
function 'create': application.ts(30,16): which referenced
'async (publicKey, privateKey) => { / ...': helpers.ts(3,24): which referenced
'(url, options, defaultOptions = defa ...': create.js(30,17): which captured
variable 'defaults' which indirectly referenced
function 'parse': which could not be serialized because
it was a native code function.
Function code:
function parse() { [native code] }
warning: A new version of Pulumi is available. To upgrade from version '3.63.0' to '3.64.0', visit https://pulumi.com/docs/reference/install/ for manual instructions and release notes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment