~ekez/negativefour

1e3d846bcbadba5b3f7e9b492156f490d3b1b865 — Zeke Medley 2 years ago b9e2585
Send discord alerts on new webpage deploys.
4 files changed, 91 insertions(+), 4 deletions(-)

M docs/hosting-design.md
M serve/app.js
M serve/package-lock.json
M serve/package.json
M docs/hosting-design.md => docs/hosting-design.md +0 -1
@@ 4,4 4,3 @@ For the near term storing webpages on the disk of the machine that is
serving them is a fine approach. Long term we'll want to move towards
storing things inside of s3 buckets but the host machine has a 40gb
SSD which should last for a while.


M serve/app.js => serve/app.js +49 -3
@@ 1,6 1,7 @@
const express = require('express')
const jwt = require('jsonwebtoken')
const { execFile } = require('child_process')
const axios = require('axios')

require('dotenv').config()



@@ 11,6 12,18 @@ const jobStatusMap = new Map()

app.use(express.json())

// Sends a message to the zekebots discord channel. Doesn't wait for
// the message to send and logs an error / success message as needed.
const sendDiscordAlert = message => {
    axios.post(process.env.WEBHOOOK_URL, {
	content: message
    }).then(function (response) {
	console.log(`=> discord: (${message})`)
    }).catch(function (error) {
	console.log(`=/> discord. error: (${error})`)
    });
}

// Posting to deploy starts a build and returns a unique ID for that
// build. The status of the build can then be queried by making a get
// request to deploy with that ID as a URL param.


@@ 67,6 80,8 @@ app.post('/deploy', function(req, res) {
	jobStatusMap.get(childProcessID).serverError = err.message
    })

    sendDiscordAlert(`deploying (${name}) for (${user})`)

    res.status(200).json({
	jobID: childProcessID
    })


@@ 123,11 138,42 @@ app.post('/delete', function(req, res) {
	})
    }

    // TODO(zeke) - run undeploy script
    const child = execFile('./undeploy.sh', [name])
    const childProcessID = jobStatusMap.size.toString()
    jobStatusMap.set(childProcessID, {
	stdout: '',
	stderr: '',
	exitCode: undefined,
	serverError: ''
    })

    child.stdout.on('data', data => {
	jobStatusMap.get(childProcessID).stdout += data
    })

    child.stderr.on('data', data => {
	jobStatusMap.get(childProcessID).stderr += data
    })

    child.on('exit', code => {
	jobStatusMap.get(childProcessID).exitCode = code
    })

    child.on('error', err => {
	// This firing indicates that:
	//
	// 1. The process could not be spawned, or
	// 2. The process could not be killed, or
	// 3. Sending a message to the child process failed.
	//
	// source: https://nodejs.org/api/child_process.html#child_process_event_error
	jobStatusMap.get(childProcessID).serverError = err.message
    })

    sendDiscordAlert(`undeploying (${name}) for (${user})`)

    res.status(200).json({
	name: name,
	user: user,
	jobID: childProcessID
    })
})


M serve/package-lock.json => serve/package-lock.json +41 -0
@@ 8,6 8,7 @@
      "name": "serve",
      "version": "0.0.1",
      "dependencies": {
        "axios": "^0.21.4",
        "dotenv": "^10.0.0",
        "express": "^4.17.1",
        "jsonwebtoken": "^8.5.1"


@@ 30,6 31,14 @@
      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
    },
    "node_modules/axios": {
      "version": "0.21.4",
      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
      "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
      "dependencies": {
        "follow-redirects": "^1.14.0"
      }
    },
    "node_modules/body-parser": {
      "version": "1.19.0",
      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",


@@ 215,6 224,25 @@
        "node": ">= 0.8"
      }
    },
    "node_modules/follow-redirects": {
      "version": "1.14.4",
      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
      "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
      "funding": [
        {
          "type": "individual",
          "url": "https://github.com/sponsors/RubenVerborgh"
        }
      ],
      "engines": {
        "node": ">=4.0"
      },
      "peerDependenciesMeta": {
        "debug": {
          "optional": true
        }
      }
    },
    "node_modules/forwarded": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",


@@ 613,6 641,14 @@
      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
    },
    "axios": {
      "version": "0.21.4",
      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
      "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
      "requires": {
        "follow-redirects": "^1.14.0"
      }
    },
    "body-parser": {
      "version": "1.19.0",
      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",


@@ 765,6 801,11 @@
        "unpipe": "~1.0.0"
      }
    },
    "follow-redirects": {
      "version": "1.14.4",
      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
      "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g=="
    },
    "forwarded": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",

M serve/package.json => serve/package.json +1 -0
@@ 8,6 8,7 @@
  },
  "author": "Zeke Medley",
  "dependencies": {
    "axios": "^0.21.4",
    "dotenv": "^10.0.0",
    "express": "^4.17.1",
    "jsonwebtoken": "^8.5.1"