deploy(
"update_cron",
async (req, res, ctx) => {
try {
const serviceAccount = JSON.parse(
ctx.secrets["endpointservices_secretadmin_service_account_key"]
);
const token = await getAccessTokenFromServiceAccount(serviceAccount);
await signinWithAccessToken(token);
const { subdomain, notebook, expected } = JSON.parse(req.body);
const fullname = `${subdomain}_${notebook}_${expected.name}`;
const actualResponse = await fetchWithTimeout(
`https://webcode.run/observablehq.com/@${subdomain}/${notebook};public%20cron%20config%20${expected.name}`
);
if (actualResponse.status !== 200) {
return res.status(404).json({
message: "Cannot read cron config, did you forget to publish?"
});
}
const actual = await actualResponse.json();
if (!_.isEqual(actual, expected)) {
return res.status(400).json({
message: `You need to publish the latest changes first`
});
}
const gapi = await createGapi({
apiKey: "AIzaSyCclj9WTy8ZAPxOBQeLyt_JS8zVF93wVnI",
discoveryDocs: [
"https://cloudscheduler.googleapis.com/$discovery/rest?version=v1"
],
access_token: token
});
if (actual.enabled) {
const job = {
name: `projects/endpointservice/locations/${actual.location}/jobs/${fullname}`,
schedule: actual.schedule,
timeZone: actual.timezone,
httpTarget: {
uri: actual.url,
httpMethod: actual.method,
body: btoa(actual.body)
}
};
try {
await gapi.cloudscheduler.projects.locations.jobs.patch({
name: job.name,
resource: job
});
} catch (err) {
// If we are creating a new cron we need to do a limit check
const numCrons = (
await firebase
.firestore()
.collectionGroup("crons")
.where("subdomain", "==", subdomain)
.where("enabled", "==", true)
.get()
).size;
console.log("Crons: " + numCrons);
if (numCrons > 1) throw new Error("Max 2 crons per subdomain ATM");
await gapi.cloudscheduler.projects.locations.jobs.create({
parent: `projects/endpointservice/locations/${actual.location}`,
resource: job
});
}
} else {
await gapi.cloudscheduler.projects.locations.jobs.delete({
name: `projects/endpointservice/locations/${actual.location}/jobs/${fullname}`
});
}
const path = configPath(subdomain, notebook, expected.name);
console.log(`${path} to ${JSON.stringify(actual)}`);
await firebase
.firestore()
.doc(path)
.set({ ...actual, subdomain });
res.json({});
} catch (err) {
console.log(JSON.stringify(req.body));
console.log(err.message);
res.status(500).json({
message: err.message || err.body
});
}
},
{
modifiers: ["orchestrator"],
secrets: ["endpointservices_secretadmin_service_account_key"]
}
)