Skip to content

Commit

Permalink
feat(system-server): add remote deploy routes;
Browse files Browse the repository at this point in the history
  • Loading branch information
maslow committed Sep 6, 2021
1 parent 4f33276 commit 7fbb75e
Show file tree
Hide file tree
Showing 6 changed files with 328 additions and 96 deletions.
75 changes: 0 additions & 75 deletions packages/system-server/src/router/deploy/apply.ts

This file was deleted.

16 changes: 7 additions & 9 deletions packages/system-server/src/router/deploy/create-token.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-08-30 16:34:45
* @LastEditTime: 2021-08-30 16:35:57
* @LastEditTime: 2021-09-06 16:08:37
* @Description:
*/

import { Request, Response } from 'express'
import { checkPermission } from '../../api/permission'
import { getToken } from '../../utils/token'
import { Constants } from '../../constants'
import { getApplicationByAppid } from '../../api/application'
import { ApplicationStruct } from '../../api/application'


const { DEPLOY_TOKEN_CREATE } = Constants.permissions
/**
* Create a deployment token
*/
Expand All @@ -22,21 +23,18 @@ export async function handleCreateDeployToken(req: Request, res: Response) {
if (!source) return res.status(422).send('invalid source')

const uid = req['auth']?.uid
const appid = req.params.appid
const app = await getApplicationByAppid(appid)
if (!app) return res.status(422).send('app not found')
const app: ApplicationStruct = req['parsed-app']

// check permission
const PN_TOKEN_CREATE = Constants.permissions.DEPLOY_TOKEN_CREATE.name
const code = await checkPermission(uid, PN_TOKEN_CREATE, app)
const code = await checkPermission(uid, DEPLOY_TOKEN_CREATE.name, app)
if (code) {
return res.status(code).send()
}

try {
const expired_at = Math.floor(Date.now() / 1000 + expire * 3600)
const payload = { type: "deploy", pns: permissions, exp: expired_at, src: source, appid }
const token = getToken(payload)
const payload = { type: "deploy", pns: permissions, exp: expired_at, src: source, appid: app.appid }
const token = getToken(payload, app.config.server_secret_salt)

return res.send({
code: 0,
Expand Down
13 changes: 5 additions & 8 deletions packages/system-server/src/router/deploy/incoming.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-08-30 16:34:45
* @LastEditTime: 2021-08-30 16:46:28
* @LastEditTime: 2021-09-06 16:12:33
* @Description:
*/

import { Request, Response } from 'express'
import { Constants } from '../../constants'
import { getApplicationByAppid } from '../../api/application'
import { ApplicationStruct } from '../../api/application'
import { DatabaseAgent } from '../../lib/db-agent'
import { logger } from '../../lib/logger'
import { parseToken } from '../../utils/token'
Expand All @@ -17,28 +17,25 @@ import { parseToken } from '../../utils/token'
* Accept the deployment requests from remote environment
*/
export async function handleDeployRequestIncoming(req: Request, res: Response) {
const app: ApplicationStruct = req['parsed-app']
const appid = app.appid

const { policies, functions, comment, triggers } = req.body
if (!policies && !functions) return res.status(422).send('not found functions and policies')

// verify deploy token
const token = req.body?.deploy_token
const auth = parseToken(token)
const auth = parseToken(token, app.config.server_secret_salt)

if (!auth)
return res.status(401).send('Unauthorized')

if (auth.type !== 'deploy')
return res.status(403).send('Permission Denied')

const appid = req.params.appid
if (appid !== auth.appid)
return res.status(403).send('forbidden operation: token is not matching the appid')

const app = await getApplicationByAppid(appid)
if (!app)
return res.status(422).send('app not found')

// verify deploy token permissions
const permissions = auth.pns ?? []
const can_deploy_function = permissions.includes('function')
Expand Down
40 changes: 36 additions & 4 deletions packages/system-server/src/router/deploy/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-08-07 01:14:33
* @LastEditTime: 2021-08-30 16:40:14
* @LastEditTime: 2021-09-06 16:28:25
* @Description:
*/

import * as express from 'express'
import { handleCreateDeployToken } from './create-token'
import { handleApplyDeployRequest } from './apply'
import { handleDeployRequestIncoming } from './incoming'
import { handleApplyDeployRequest, handleGetDeployRequests, handleRemoveDeployRequest } from './request'
import { handleCreateDeployTarget, handleGetDeployTargets, handleRemoveDeployTarget, handleUpdateDeployTarget } from './target'

export const DeployRouter = express.Router()


/**
* Create a deploy target
*/
DeployRouter.post('/targets/create', handleCreateDeployTarget)

/**
* Get deploy targets
*/
DeployRouter.get('/targets', handleGetDeployTargets)

/**
* Update a deploy target
*/
DeployRouter.post('/targets/:target_id', handleUpdateDeployTarget)

/**
* Remove a deploy target
*/
DeployRouter.delete('/targets/:target_id', handleRemoveDeployTarget)

/**
* Create a deployment token
*/
Expand All @@ -20,9 +42,19 @@ DeployRouter.post('/create-token', handleCreateDeployToken)
/**
* Accept the deployment requests from remote environment
*/
DeployRouter.post('/in', handleDeployRequestIncoming)
DeployRouter.post('/incoming', handleDeployRequestIncoming)

/**
* Get deployment requests which accept from remote environment
*/
DeployRouter.get('/requests', handleGetDeployRequests)

/**
* Remove a deployment requests which accept from remote environment
*/
DeployRouter.delete('/requests/:req_id', handleRemoveDeployRequest)

/**
* Apply the deployment requests which accept from remote environment
*/
DeployRouter.post('/apply', handleApplyDeployRequest)
DeployRouter.post('/requests/:req_id/apply', handleApplyDeployRequest)
151 changes: 151 additions & 0 deletions packages/system-server/src/router/deploy/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-09-06 15:47:57
* @LastEditTime: 2021-09-06 16:22:13
* @Description:
*/

import { Request, Response } from 'express'
import { checkPermission } from '../../api/permission'
import { Constants } from '../../constants'
import { ApplicationStruct } from '../../api/application'
import { DatabaseAgent } from '../../lib/db-agent'
import * as assert from 'assert'
import { deployFunctions, publishFunctions } from '../../api/function'
import { publishTriggers } from '../../api/trigger'
import { deployPolicies, publishAccessPolicy } from '../../api/policy'


const { DEPLOY_REQUEST_REMOVE, DEPLOY_REQUEST_READ, DEPLOY_REQUEST_APPLY } = Constants.permissions

/**
* Get deploy requests
*/
export async function handleGetDeployRequests(req: Request, res: Response) {
const uid = req['auth']?.uid
const app: ApplicationStruct = req['parsed-app']
const db = DatabaseAgent.sys_db

// check permission
const code = await checkPermission(uid, DEPLOY_REQUEST_READ.name, app)
if (code) {
return res.status(code).send()
}

// build query object
const { keyword } = req.query
const limit = Number(req.query?.limit || 10)
const page = Number(req.query?.page || 1)

const query = {
appid: app.appid
}
if (keyword) {
query['$or'] = [
{ source: db.RegExp({ regexp: `.*${keyword}.*` }) },
{ comment: db.RegExp({ regexp: `.*${keyword}.*` }) }
]
}

const coll = db.collection(Constants.cn.deploy_requests)

// do db query
const r = await coll
.where(query)
.limit(limit)
.skip((page - 1) * limit)
.orderBy('created_at', 'desc')
.get()

// get the count
const { total } = await coll
.where(query)
.count()

if (r.error) {
return res.status(400).send({ error: r.error })
}

return res.send({
data: r.data,
total: total,
limit: limit,
page
})
}

/**
* Remove a deploy request
*/
export async function handleRemoveDeployRequest(req: Request, res: Response) {
const uid = req['auth']?.uid
const app: ApplicationStruct = req['parsed-app']
const db = DatabaseAgent.sys_db
const req_id = req.params.req_id

// check permission
const code = await checkPermission(uid, DEPLOY_REQUEST_REMOVE.name, app)
if (code) {
return res.status(code).send()
}

const r = await db.collection(Constants.cn.deploy_requests)
.where({ appid: app.appid, _id: req_id })
.remove()

return res.send({ data: r })
}

/**
* Apply the deployment requests which accept from remote environment
*/
export async function handleApplyDeployRequest(req: Request, res: Response) {
const uid = req['auth']?.uid
const app: ApplicationStruct = req['parsed-app']
const req_id = req.params.req_id

// check permission
const code = await checkPermission(uid, DEPLOY_REQUEST_APPLY.name, app)
if (code) {
return res.status(code).send()
}


const db = DatabaseAgent.sys_db
const { data: deploy_request } = await db.collection(Constants.cn.deploy_requests)
.where({ _id: req_id, appid: app.appid })
.getOne()

if (!deploy_request)
return res.status(404).send('deploy request not found')

if (deploy_request.status !== 'pending') {
return res.status(422).send('the status of deploy request should be `pending`')
}

const type = deploy_request.type
assert.ok(['function', 'policy'].includes(type))

// deploy functions
if (type === 'function') {
await deployFunctions(deploy_request.data)
await publishFunctions(app)
await publishTriggers(app)
}

// deploy policies
if (type === 'policy') {
await deployPolicies(deploy_request.data)
await publishAccessPolicy(app)
}

// update deploy request status to 'deployed'
await db.collection(Constants.cn.deploy_requests)
.where({ _id: req_id, appid: app.appid })
.update({ status: 'deployed' })

return res.send({
code: 0,
data: 'deployed'
})
}
Loading

0 comments on commit 7fbb75e

Please sign in to comment.