trustgraph/ai-context/workbench-ui/pulumi/index.ts

348 lines
6.7 KiB
TypeScript

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import { local } from "@pulumi/command";
//import * as fs from 'fs';
const cfg = new pulumi.Config();
function get(tag : string) {
const val = cfg.get(tag);
if (!val) {
console.log("ERROR: The '" + tag + "' config is mandatory");
throw "The '" + tag + "' config is mandatory";
}
return val;
}
const imageVersion = process.env.IMAGE_VERSION;
if (!imageVersion)
throw Error("IMAGE_VERSION not defined");
const repo = get("artifact-repo");
const artifactRepoRegion = get("artifact-repo-region");
const artifactName = get("artifact-name");
const hostname = get("hostname");
const managedZone = get("managed-zone");
const project = get("gcp-project");
const region = get("gcp-region");
const cloudRunRegion = get("cloud-run-region");
const environment = get("environment");
//const domain = get("domain");
const minScale = get("min-scale");
const maxScale = get("max-scale");
const provider = new gcp.Provider(
"gcp",
{
project: project,
region: region,
}
);
const artifactRepo = new gcp.artifactregistry.Repository(
"artifact-repo",
{
description: "repository for " + environment,
format: "DOCKER",
location: artifactRepoRegion,
repositoryId: artifactName,
cleanupPolicies: [
{
id: "keep-minimum-versions",
action: "KEEP",
mostRecentVersions: {
keepCount: 5,
},
}
],
},
{
provider: provider,
}
);
const localImageName = "localhost/config-ui:" + imageVersion;
const imageName = repo + "/config-ui:" + imageVersion;
const taggedImage = new local.Command(
"podman-tag-command",
{
create: "podman tag " + localImageName + " " + imageName,
}
);
const image = new local.Command(
"podman-push-command",
{
create: "podman push " + imageName,
},
{
dependsOn: [taggedImage, artifactRepo],
}
);
const svcAccount = new gcp.serviceaccount.Account(
"service-account",
{
accountId: "config-ui-" + environment,
displayName: "Config UI",
description: "Config UI",
},
{
provider: provider,
}
);
/*
const vertexAiUserMember = new gcp.projects.IAMMember(
"vertexai-user-role",
{
member: svcAccount.email.apply(x => "serviceAccount:" + x),
project: project,
role: "roles/aiplatform.admin",
},
{
provider: provider,
}
);
*/
const service = new gcp.cloudrun.Service(
"service",
{
name: "config-ui-" + environment,
location: cloudRunRegion,
template: {
metadata: {
labels: {
version: "v" + imageVersion.replace(/\./g, "-"),
},
annotations: {
// Scale attributes
"autoscaling.knative.dev/minScale": minScale,
"autoscaling.knative.dev/maxScale": maxScale,
// 2nd generation. Need to specify at least 512MB RAM.
// Going back to gen1 because faster cold starts
"run.googleapis.com/execution-environment": "gen1",
}
},
spec: {
containerConcurrency: 100,
timeoutSeconds: 300,
serviceAccountName: svcAccount.email,
containers: [
{
image: imageName,
// commands: [
// "config-ui"
// ],
ports: [
{
"name": "http1", // Must be http1 or h2c.
"containerPort": 8080,
}
],
resources: {
limits: {
cpu: "1000m",
memory: "512Mi",
}
},
}
],
},
},
},
{
provider: provider,
dependsOn: [image],
}
);
const allUsersPolicy = gcp.organizations.getIAMPolicy(
{
bindings: [{
role: "roles/run.invoker",
members: ["allUsers"],
}],
},
{
provider: provider,
}
);
/*const _noAuthPolicy =*/ new gcp.cloudrun.IamPolicy(
"no-auth-policy",
{
location: service.location,
project: service.project,
service: service.name,
policyData: allUsersPolicy.then(pol => pol.policyData),
},
{
provider: provider,
}
);
////////////////////////////////////////////////////////////////////////////
const domainMapping = new gcp.cloudrun.DomainMapping(
"domain-mapping",
{
name: hostname,
location: cloudRunRegion,
metadata: {
namespace: project,
},
spec: {
routeName: service.name,
}
},
{
provider: provider
}
);
const zone = gcp.dns.getManagedZoneOutput(
{
name: managedZone,
},
{
provider: provider,
}
);
////////////////////////////////////////////////////////////////////////////
domainMapping.statuses.apply(
ss => ss[0].resourceRecords
).apply(
rrs => {
if (rrs) {
let mapping : { [k : string] : string[] } = {};
for(let i = 0; i < rrs.length; i++) {
if (rrs[i].rrdata) {
const rr = rrs[i].rrdata;
const tp = rrs[i].type;
if (!rr || !tp) continue;
if (mapping[tp])
mapping = {
...mapping,
[tp]: [...mapping[tp], rr],
};
else
mapping = {
...mapping,
[tp]: [rr],
};
}
}
for (const tp in mapping) {
new gcp.dns.RecordSet(
"resource-record-" + tp,
{
name: hostname + ".",
managedZone: zone.name,
type: tp,
ttl: 300,
rrdatas: mapping[tp],
},
{
provider: provider,
}
);
}
}
}
);
////////////////////////////////////////////////////////////////////////////
const serviceMon = new gcp.monitoring.GenericService(
"service-monitoring",
{
basicService: {
serviceLabels: {
service_name: service.name,
location: cloudRunRegion,
},
serviceType: "CLOUD_RUN",
},
displayName: "Config UI service (" + environment + ")",
serviceId: "config-ui-service-" + environment + "-mon",
userLabels: {
"service": service.name,
"application": "config-ui",
"environment": environment,
},
},
{
provider: provider,
}
);
new gcp.monitoring.Slo(
"latency-slo",
{
service: serviceMon.serviceId,
sloId: "config-ui-service-" + environment + "-latency-slo",
displayName: "Config UI latency (" + environment + ")",
goal: 0.95,
rollingPeriodDays: 5,
basicSli: {
latency: {
threshold: "2s"
}
},
},
{
provider: provider,
}
);
new gcp.monitoring.Slo(
"availability-slo",
{
service: serviceMon.serviceId,
sloId: "config-ui-service-" + environment + "-availability-slo",
displayName: "Config UI availability (" + environment + ")",
goal: 0.95,
rollingPeriodDays: 5,
windowsBasedSli: {
windowPeriod: "3600s",
goodTotalRatioThreshold: {
basicSliPerformance: {
availability: {
}
},
threshold: 0.9,
}
}
},
{
provider: provider,
}
);