parser-service/routes.js (89 lines of code) (raw):

/** * Copyright 2019 Google LLC * * 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 * * https://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. */ /** * Routes.js orchestrates the calling of the various helper function when an * http service is invoked. */ import * as recommender from './recommender.js'; import * as terraform from './terraform.js'; import * as sourceControl from './sourcecontrol.js'; import * as github from './github.js'; import * as db from './db.js'; const BASE_REPO = process.env.GITHUB_ACCOUNT; /** * This function fetches recommendations from the Recommender API. It invokes * supporting methods to filter and parse these recommendations, download * supporting files, committing to Git, generating a pull request and updating * the Recommender API to mark recommendation status as Claimed. * * @param req is the request object * @param res is the response object */ const applyRecommendations = async (req, res) => { try { const { body, params } = req; const { repo: repoName, projects: projectIDs, location, stub } = body; const type = params.type.toUpperCase(); let listRecommendationsFn, applyRecommendationsFn; switch (type) { case 'VM': listRecommendationsFn = recommender.listVMResizeRecommendations; applyRecommendationsFn = terraform.applyVMResizeRecommendations; break; case 'IAM': listRecommendationsFn = recommender.listIAMRecommendations; applyRecommendationsFn = terraform.applyIAMRecommendations; break; default: return res.status(500).send('Unknown operation'); } const recommendations = await listRecommendationsFn(projectIDs, Boolean(stub), location); if (recommendations.length === 0) { return res.end('Nothing to apply'); } await sourceControl.cloneRepository(`git@${BASE_REPO}/${repoName}.git`, repoName); const recommendationsToClaim = await applyRecommendationsFn(repoName, recommendations, Boolean(stub)); if (recommendationsToClaim.length > 0) { const commitMessage = type === 'VM' ? `Recommended VM Rightsizing as on ${new Date().toLocaleString()}` : `Recommended IAM Updates as on ${new Date().toLocaleString()}`; const commit = await sourceControl.commitChanges(commitMessage, repoName); await github.createPullRequest(`git@${BASE_REPO}/${repoName}.git`, commit.branch, commitMessage); await db.createCommit(repoName, commit.commit, recommendationsToClaim, Boolean(stub)); if (!stub) { await recommender.setRecommendationStatus(recommendationsToClaim, 'markClaimed'); } } res.sendStatus(201).end(); } catch (e) { console.error(e); res.sendStatus(500).end(e.toString()); } }; /** * This handles the route called by the Pub/Sub subscription after the Cloud * Build (CI / CD) job completes. If the job has run successfully, the * service updates the recommendations state by invoking the Recommender API. * * @param req is the request object * @param res is the response object */ const ci = async (req, res) => { const data = req.body.message.data const payload = JSON.parse(Buffer.from(data, 'base64').toString()) try { if (payload.status == 'SUCCESS' && payload.substitutions) { const commitID = payload.substitutions.COMMIT_SHA const repoName = payload.substitutions.REPO_NAME const fullRepoName = `${BASE_REPO}/${repoName}` // Get parent commits console.log('/ci starting step Get Parent Commits') const parentCommits = await github.getParentCommits(fullRepoName, commitID) console.log('/ci end step Get Parent Commits', JSON.stringify(parentCommits)) // Get Recommendation IDs from DB for each parent commit console.log('/ci starting step Get Recommendation IDs from DB') const dbLookUpPromises = parentCommits.map(c => db.getCommit(repoName, c)) const dbLookUpPromisesResult = await Promise.all(dbLookUpPromises) // Flatten recommendations const recommendationIDs = dbLookUpPromisesResult.reduce((acc, result) => { return [...acc, ...result] }, []) console.log('/ci recommendationIDs are', recommendationIDs) // Get etags for recommendations console.log('/ci starting step Get etags for recommendation') const recommendationsResult = await recommender.getRecommendations(recommendationIDs) console.log('/ci recommendations are', recommendationsResult) const recommendations = recommendationsResult.map(reco => ({ id: reco.name, etag: reco.etag })) // Mark Recommendations as succeeded console.log('/ci starting step Mark Recommendations as succeeded') await recommender.setRecommendationStatus( recommendations, 'markSucceeded') res.sendStatus(201) } else { res.sendStatus(200) } } catch (e) { console.log('ERROR: ', e.toString()) res.status(500).send(e.toString()) } } export { applyRecommendations, ci };