From e30c4da402af8f03a4e7e53df268c4af160aebeb Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Thu, 21 May 2020 22:30:51 +0200 Subject: [PATCH 1/2] Add identity backend skeleton --- packages/backend/package.json | 3 +- packages/backend/src/index.ts | 2 + packages/backend/src/plugins/identity.ts | 22 ++++++++ plugins/identity-backend/.eslintrc.js | 3 ++ plugins/identity-backend/README.md | 11 ++++ plugins/identity-backend/package.json | 40 ++++++++++++++ plugins/identity-backend/src/index.test.ts | 21 ++++++++ plugins/identity-backend/src/index.ts | 17 ++++++ plugins/identity-backend/src/run.ts | 33 ++++++++++++ .../identity-backend/src/service/router.ts | 37 +++++++++++++ .../src/service/standaloneApplication.ts | 52 +++++++++++++++++++ .../src/service/standaloneServer.ts | 50 ++++++++++++++++++ plugins/identity-backend/src/setupTests.ts | 17 ++++++ plugins/identity-backend/tsconfig.json | 15 ++++++ yarn.lock | 4 +- 15 files changed, 324 insertions(+), 3 deletions(-) create mode 100644 packages/backend/src/plugins/identity.ts create mode 100644 plugins/identity-backend/.eslintrc.js create mode 100644 plugins/identity-backend/README.md create mode 100644 plugins/identity-backend/package.json create mode 100644 plugins/identity-backend/src/index.test.ts create mode 100644 plugins/identity-backend/src/index.ts create mode 100644 plugins/identity-backend/src/run.ts create mode 100644 plugins/identity-backend/src/service/router.ts create mode 100644 plugins/identity-backend/src/service/standaloneApplication.ts create mode 100644 plugins/identity-backend/src/service/standaloneServer.ts create mode 100644 plugins/identity-backend/src/setupTests.ts create mode 100644 plugins/identity-backend/tsconfig.json diff --git a/packages/backend/package.json b/packages/backend/package.json index b1a0a68f15..2c7b48f65f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -20,8 +20,9 @@ "@backstage/backend-common": "^0.1.1-alpha.6", "@backstage/plugin-auth-backend": "^0.1.1-alpha.6", "@backstage/plugin-catalog-backend": "^0.1.1-alpha.6", - "@backstage/plugin-sentry-backend": "0.1.1-alpha.6", + "@backstage/plugin-sentry-backend": "^0.1.1-alpha.6", "@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.6", + "@backstage/plugin-identity-backend": "^0.1.1-alpha.6", "compression": "^1.7.4", "cors": "^2.8.5", "express": "^4.17.1", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index bb37adbae9..7af6e631a8 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -37,6 +37,7 @@ import catalog from './plugins/catalog'; import scaffolder from './plugins/scaffolder'; import sentry from './plugins/sentry'; import auth from './plugins/auth'; +import identity from './plugins/identity'; import { PluginEnvironment } from './types'; const DEFAULT_PORT = 7000; @@ -70,6 +71,7 @@ async function main() { await sentry(getRootLogger().child({ type: 'plugin', plugin: 'sentry' })), ); app.use('/auth', await auth(createEnv('auth'))); + app.use('/identity', await identity(createEnv('identity'))); app.use(notFoundHandler()); app.use(errorHandler()); diff --git a/packages/backend/src/plugins/identity.ts b/packages/backend/src/plugins/identity.ts new file mode 100644 index 0000000000..26276afd01 --- /dev/null +++ b/packages/backend/src/plugins/identity.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createRouter } from '@backstage/plugin-identity-backend'; +import { PluginEnvironment } from '../types'; + +export default async function ({ logger }: PluginEnvironment) { + return await createRouter({ logger }); +} diff --git a/plugins/identity-backend/.eslintrc.js b/plugins/identity-backend/.eslintrc.js new file mode 100644 index 0000000000..16a033dbc6 --- /dev/null +++ b/plugins/identity-backend/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint.backend')], +}; diff --git a/plugins/identity-backend/README.md b/plugins/identity-backend/README.md new file mode 100644 index 0000000000..7d97bb5f6b --- /dev/null +++ b/plugins/identity-backend/README.md @@ -0,0 +1,11 @@ +# Identity Backend + +WORK IN PROGRESS + +This is the backend part of the identity plugin. + +It responds to identity requests from the frontend. + +## Links + +- (The Backstage homepage)[https://backstage.io] diff --git a/plugins/identity-backend/package.json b/plugins/identity-backend/package.json new file mode 100644 index 0000000000..30512ee658 --- /dev/null +++ b/plugins/identity-backend/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-identity-backend", + "version": "0.1.1-alpha.6", + "main": "dist", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": true, + "scripts": { + "start": "tsc-watch --onFirstSuccess \"cross-env NODE_ENV=development nodemon dist/run.js\"", + "build": "tsc", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/backend-common": "^0.1.1-alpha.6", + "compression": "^1.7.4", + "cors": "^2.8.5", + "express": "^4.17.1", + "express-promise-router": "^3.0.3", + "fs-extra": "^9.0.0", + "helmet": "^3.22.0", + "morgan": "^1.10.0", + "winston": "^3.2.1", + "yn": "^4.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.6", + "jest-fetch-mock": "^3.0.3", + "tsc-watch": "^4.2.3" + }, + "files": [ + "dist" + ], + "nodemonConfig": { + "watch": "./dist" + } +} diff --git a/plugins/identity-backend/src/index.test.ts b/plugins/identity-backend/src/index.test.ts new file mode 100644 index 0000000000..b3e2f19771 --- /dev/null +++ b/plugins/identity-backend/src/index.test.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('test', () => { + it('unbreaks the test runner', () => { + expect(true).toBeTruthy(); + }); +}); diff --git a/plugins/identity-backend/src/index.ts b/plugins/identity-backend/src/index.ts new file mode 100644 index 0000000000..7612c392a2 --- /dev/null +++ b/plugins/identity-backend/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './service/router'; diff --git a/plugins/identity-backend/src/run.ts b/plugins/identity-backend/src/run.ts new file mode 100644 index 0000000000..0a684c379e --- /dev/null +++ b/plugins/identity-backend/src/run.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import yn from 'yn'; +import { getRootLogger } from '@backstage/backend-common'; +import { startStandaloneServer } from './service/standaloneServer'; + +const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 3003; +const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); +const logger = getRootLogger(); + +startStandaloneServer({ port, enableCors, logger }).catch((err) => { + logger.error(err); + process.exit(1); +}); + +process.on('SIGINT', () => { + logger.info('CTRL+C pressed; exiting.'); + process.exit(0); +}); diff --git a/plugins/identity-backend/src/service/router.ts b/plugins/identity-backend/src/service/router.ts new file mode 100644 index 0000000000..9cd79f142b --- /dev/null +++ b/plugins/identity-backend/src/service/router.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import express from 'express'; +import Router from 'express-promise-router'; +import { Logger } from 'winston'; + +export interface RouterOptions { + logger: Logger; +} + +export async function createRouter( + options: RouterOptions, +): Promise { + const router = Router(); + const logger = options.logger.child({ plugin: 'identity' }); + + router.use('/ping', (_, res) => { + logger.info('heartbeat for identity service'); + res.send('pong'); + }); + + return router; +} diff --git a/plugins/identity-backend/src/service/standaloneApplication.ts b/plugins/identity-backend/src/service/standaloneApplication.ts new file mode 100644 index 0000000000..5eea4fb8f5 --- /dev/null +++ b/plugins/identity-backend/src/service/standaloneApplication.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + errorHandler, + notFoundHandler, + requestLoggingHandler, +} from '@backstage/backend-common'; +import compression from 'compression'; +import cors from 'cors'; +import express from 'express'; +import helmet from 'helmet'; +import { Logger } from 'winston'; +import { createRouter } from './router'; + +export interface ApplicationOptions { + enableCors: boolean; + logger: Logger; +} + +export async function createStandaloneApplication( + options: ApplicationOptions, +): Promise { + const { enableCors, logger } = options; + const app = express(); + + app.use(helmet()); + if (enableCors) { + app.use(cors()); + } + app.use(compression()); + app.use(express.json()); + app.use(requestLoggingHandler()); + app.use('/', await createRouter({ logger })); + app.use(notFoundHandler()); + app.use(errorHandler()); + + return app; +} diff --git a/plugins/identity-backend/src/service/standaloneServer.ts b/plugins/identity-backend/src/service/standaloneServer.ts new file mode 100644 index 0000000000..42231b45a9 --- /dev/null +++ b/plugins/identity-backend/src/service/standaloneServer.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Server } from 'http'; +import { Logger } from 'winston'; +import { createStandaloneApplication } from './standaloneApplication'; + +export interface ServerOptions { + port: number; + enableCors: boolean; + logger: Logger; +} + +export async function startStandaloneServer( + options: ServerOptions, +): Promise { + const logger = options.logger.child({ service: 'identity-backend' }); + + logger.debug('Creating application...'); + const app = await createStandaloneApplication({ + enableCors: options.enableCors, + logger, + }); + + logger.debug('Starting application server...'); + return await new Promise((resolve, reject) => { + const server = app.listen(options.port, (err?: Error) => { + if (err) { + reject(err); + return; + } + + logger.info(`Listening on port ${options.port}`); + resolve(server); + }); + }); +} diff --git a/plugins/identity-backend/src/setupTests.ts b/plugins/identity-backend/src/setupTests.ts new file mode 100644 index 0000000000..3fa7cb04b4 --- /dev/null +++ b/plugins/identity-backend/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +require('jest-fetch-mock').enableMocks(); diff --git a/plugins/identity-backend/tsconfig.json b/plugins/identity-backend/tsconfig.json new file mode 100644 index 0000000000..015a967f76 --- /dev/null +++ b/plugins/identity-backend/tsconfig.json @@ -0,0 +1,15 @@ +{ + "include": ["src"], + "compilerOptions": { + "outDir": "dist", + "incremental": true, + "sourceMap": true, + "declaration": true, + "strict": true, + "target": "es2019", + "module": "commonjs", + "esModuleInterop": true, + "lib": ["es2019"], + "types": ["node", "jest"] + } +} diff --git a/yarn.lock b/yarn.lock index b6ae6d25ac..7fa63c13b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4031,7 +4031,7 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" -"@types/jest@^25.2.1", "@types/jest@^25.2.2": +"@types/jest@^25.2.2": version "25.2.3" resolved "https://registry.npmjs.org/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf" integrity sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw== @@ -5370,7 +5370,7 @@ aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== -axios@^0.19.0, axios@^0.19.2: +axios@^0.19.0: version "0.19.2" resolved "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== From 298dc4a44d82589d6f2bd3fb6f3df2b91ff5cbbd Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Fri, 22 May 2020 11:33:04 +0200 Subject: [PATCH 2/2] dont create a namespaced logger again --- plugins/identity-backend/src/service/router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/identity-backend/src/service/router.ts b/plugins/identity-backend/src/service/router.ts index 9cd79f142b..52e73db0fb 100644 --- a/plugins/identity-backend/src/service/router.ts +++ b/plugins/identity-backend/src/service/router.ts @@ -26,7 +26,7 @@ export async function createRouter( options: RouterOptions, ): Promise { const router = Router(); - const logger = options.logger.child({ plugin: 'identity' }); + const logger = options.logger; router.use('/ping', (_, res) => { logger.info('heartbeat for identity service');