From 63392f840c9729f4a177ef751533fc76b6783d11 Mon Sep 17 00:00:00 2001 From: "s.marjanovic" Date: Fri, 10 Nov 2023 17:23:53 +0100 Subject: [PATCH 1/4] add reset budget feature, each first of the month --- client/src/containers/AccountsView.js | 4 ++-- server/serverless-gcp-account-crud.yml | 10 ++++++++++ server/src/handler/gcp-account-handler.js | 15 ++++++++++++++- server/src/service/gcp-account-sync-service.js | 18 +++++++++++++++++- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/client/src/containers/AccountsView.js b/client/src/containers/AccountsView.js index 4006440..68167ae 100644 --- a/client/src/containers/AccountsView.js +++ b/client/src/containers/AccountsView.js @@ -128,7 +128,7 @@ const AccountsView = () => { account={account} refreshList={refreshList} apiFunction={ - show === 'Create new AWS account' || 'Create new GCP account' ? + show === 'Create new AWS account' ? serviceHandler.createAccount : serviceHandler.updateAccount } handleViewChange={handleViewChange} /> @@ -160,7 +160,7 @@ const AccountsView = () => { account={account} refreshList={refreshList} apiFunction={ - show === 'Create new AWS account' || 'Create new GCP account' ? + show === 'Create new GCP account' ? serviceHandler.createAccount : serviceHandler.updateAccount } handleViewChange={handleViewChange} /> diff --git a/server/serverless-gcp-account-crud.yml b/server/serverless-gcp-account-crud.yml index ec15722..c5325d7 100644 --- a/server/serverless-gcp-account-crud.yml +++ b/server/serverless-gcp-account-crud.yml @@ -55,3 +55,13 @@ functions: cors: true authorizer: ${self:custom.authorizer} - schedule: cron(2,32 8-18 * * ? *) + gcpResetBudgets: + handler: src/handler/gcp-account-handler.resetBudgets + timeout: 900 # TODO: It's succeeded but warning is detected (WARNING: Function gcpSyncBudgets has timeout of 900 seconds, however, it's attached to API Gateway so it's automatically limited to 30 seconds.) + events: + - http: + path: gcp/reset-budgets + method: post # TODO: use node v15.14.0 (otherwise post api does not work) + cors: true + authorizer: ${self:custom.authorizer} + - schedule: cron(0 6 1 * ? *) # Run at 6:00 am (UTC+0) every 1st day of the month diff --git a/server/src/handler/gcp-account-handler.js b/server/src/handler/gcp-account-handler.js index 22c5547..cd2ab8b 100644 --- a/server/src/handler/gcp-account-handler.js +++ b/server/src/handler/gcp-account-handler.js @@ -80,6 +80,18 @@ const syncBudgets = async () => { } }; + +const resetBudgets = async () => { + try { + await accountSyncService.resetBudget(); + return okResponse({ success: true, message: 'Budget reset is done' }); + } catch (error) { + console.log('Budget sync failed', error); + return errorResponse({ statusCode: 500, message: 'Budget reset failed'}); + } +}; + + const syncOwners = async () => { try { const result = await accountSyncService.syncOwners(); @@ -107,5 +119,6 @@ module.exports = { updateAccount, syncBudgets, syncOwners, - syncAccounts + syncAccounts, + resetBudgets }; diff --git a/server/src/service/gcp-account-sync-service.js b/server/src/service/gcp-account-sync-service.js index bb78fbf..df61177 100644 --- a/server/src/service/gcp-account-sync-service.js +++ b/server/src/service/gcp-account-sync-service.js @@ -108,9 +108,25 @@ const syncBudgets = async () => { return { success: true, message: 'Budget sync is done' }; } + +const resetBudget = async () => { + + // get existing accounts from dynamodb + const accounts = await accountService.getAccounts(tableName); + + // update budgets to 0 + for (const account of accounts) { + await accountService.updateAccount({ id: account.id, actualSpend: `0` }, tableName); + console.log(`Account with id ${account.id} has reset budget`) + } + + return { success: true, message: 'Budget reset is done' }; +} + module.exports = { syncAccounts, syncAccountsMembers, syncOwners, - syncBudgets + syncBudgets, + resetBudget }; From 4aa49f7a81db5fc1c8562bbbe5233b293b72fa95 Mon Sep 17 00:00:00 2001 From: "s.marjanovic" Date: Fri, 10 Nov 2023 17:26:12 +0100 Subject: [PATCH 2/4] remove comment --- server/serverless-gcp-account-crud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/serverless-gcp-account-crud.yml b/server/serverless-gcp-account-crud.yml index c5325d7..fa04ddc 100644 --- a/server/serverless-gcp-account-crud.yml +++ b/server/serverless-gcp-account-crud.yml @@ -57,7 +57,7 @@ functions: - schedule: cron(2,32 8-18 * * ? *) gcpResetBudgets: handler: src/handler/gcp-account-handler.resetBudgets - timeout: 900 # TODO: It's succeeded but warning is detected (WARNING: Function gcpSyncBudgets has timeout of 900 seconds, however, it's attached to API Gateway so it's automatically limited to 30 seconds.) + timeout: 900 events: - http: path: gcp/reset-budgets From 4cb140ece56580c8ee17fb4929ec065df081c425 Mon Sep 17 00:00:00 2001 From: "s.marjanovic" Date: Sat, 11 Nov 2023 17:00:57 +0100 Subject: [PATCH 3/4] update budget api update and update FE call --- client/src/config.js | 2 +- client/src/containers/AccountsView.js | 4 ++-- server/src/handler/gcp-account-handler.js | 3 +-- server/src/service/gcp-auth-client-service.js | 2 +- server/src/service/gcp-budget-service.js | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/client/src/config.js b/client/src/config.js index d5b4be1..006204b 100644 --- a/client/src/config.js +++ b/client/src/config.js @@ -87,7 +87,7 @@ const recruitment = { organization: 'AWS-SRB-Recruitment' }; -const stage = process.env.NODE_ENV === 'production' ? recruitment : recruitment; +const stage = process.env.NODE_ENV === 'production' ? serbia : serbia; export default { ...stage diff --git a/client/src/containers/AccountsView.js b/client/src/containers/AccountsView.js index 68167ae..051b7db 100644 --- a/client/src/containers/AccountsView.js +++ b/client/src/containers/AccountsView.js @@ -129,7 +129,7 @@ const AccountsView = () => { refreshList={refreshList} apiFunction={ show === 'Create new AWS account' ? - serviceHandler.createAccount : serviceHandler.updateAccount + awsServices.createAccount : awsServices.updateAccount } handleViewChange={handleViewChange} /> @@ -161,7 +161,7 @@ const AccountsView = () => { refreshList={refreshList} apiFunction={ show === 'Create new GCP account' ? - serviceHandler.createAccount : serviceHandler.updateAccount + gcpServices.createAccount : gcpServices.updateAccount } handleViewChange={handleViewChange} /> diff --git a/server/src/handler/gcp-account-handler.js b/server/src/handler/gcp-account-handler.js index cd2ab8b..870d89b 100644 --- a/server/src/handler/gcp-account-handler.js +++ b/server/src/handler/gcp-account-handler.js @@ -38,14 +38,13 @@ const updateAccount = async (event) => { if (oldStateAccount.budget != account.budget) { const budgets = await getBudgetList(); const budgetsForUpdate = budgets.filter(budget => budget.displayName === `${account.name}${budgetNameSuffix.EMAIL}` || budget.displayName === `${account.name}${budgetNameSuffix.PUBSUB}`); - await Promise.all(budgetsForUpdate.map(async (budget) => { await updateBudget(budget, account.budget); })); } // update account project in dynamodb - const updatedAccount = await accountService.updateAccount(account, tableName); + const updatedAccount = await accountService.updateAccount(account, tableName); return okResponse(updatedAccount); } catch (error) { diff --git a/server/src/service/gcp-auth-client-service.js b/server/src/service/gcp-auth-client-service.js index db83bf1..3a4688b 100644 --- a/server/src/service/gcp-auth-client-service.js +++ b/server/src/service/gcp-auth-client-service.js @@ -24,7 +24,7 @@ const getGcpAuthClient = async () => { key: gcpAccountKeys.private_key, scopes: ['https://www.googleapis.com/auth/cloud-platform'], }); - return client; + return client; } else { return client; } diff --git a/server/src/service/gcp-budget-service.js b/server/src/service/gcp-budget-service.js index 34c2e58..ddcee82 100644 --- a/server/src/service/gcp-budget-service.js +++ b/server/src/service/gcp-budget-service.js @@ -114,7 +114,7 @@ const getBudgetList = async () => { // use next token to get all pages/budgets do { response = await gcpClient.request({ method: 'GET', url: !nextToken ? url : `${url}?pageToken=${nextToken}` }); - budgets.push(response.budgets); + budgets = budgets.concat(response.data.budgets); nextToken = response.nextPageToken ? response.nextPageToken : null; } while (nextToken); @@ -129,7 +129,7 @@ const updateBudget = async (budget, newAmount) => { console.log(`Updating GCP project budget amount, new amount: ${newAmount}, budget: ${JSON.stringify(budget)}`); try { const gcpClient = await getGcpAuthClient(); - const url = `https://billingbudgets.googleapis.com/v1/billingAccounts/${process.env.GCP_BILLING_ACCOUNT_ID}/budgets/${budget.name}`; + const url = `https://billingbudgets.googleapis.com/v1/${budget.name}`; const body = { amount: budget.amount }; From f7d029153fe1f143f4feec0de22f49ebfa4f3189 Mon Sep 17 00:00:00 2001 From: "s.marjanovic" Date: Sat, 11 Nov 2023 17:03:13 +0100 Subject: [PATCH 4/4] wrong indentation --- server/src/handler/gcp-account-handler.js | 2 +- server/src/service/gcp-auth-client-service.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/handler/gcp-account-handler.js b/server/src/handler/gcp-account-handler.js index 870d89b..5ee72d1 100644 --- a/server/src/handler/gcp-account-handler.js +++ b/server/src/handler/gcp-account-handler.js @@ -44,7 +44,7 @@ const updateAccount = async (event) => { } // update account project in dynamodb - const updatedAccount = await accountService.updateAccount(account, tableName); + const updatedAccount = await accountService.updateAccount(account, tableName); return okResponse(updatedAccount); } catch (error) { diff --git a/server/src/service/gcp-auth-client-service.js b/server/src/service/gcp-auth-client-service.js index 3a4688b..db83bf1 100644 --- a/server/src/service/gcp-auth-client-service.js +++ b/server/src/service/gcp-auth-client-service.js @@ -24,7 +24,7 @@ const getGcpAuthClient = async () => { key: gcpAccountKeys.private_key, scopes: ['https://www.googleapis.com/auth/cloud-platform'], }); - return client; + return client; } else { return client; }