Last active
July 18, 2024 21:53
-
-
Save htnosm/6e718be98f0aac153d4ca06a11cc0ffd to your computer and use it in GitHub Desktop.
Fetch resource counts of HPC Terraform
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Fetch resource counts of HPC Terraform | |
* | |
* Usage: | |
* - Run the `setUserPreference` function to register your API_TOKEN and ORGANIZATION in the script's properties. | |
* - You can verify the stored properties using the log output of the `getUserPreference` function. | |
* - Set a periodic trigger to execute the "getTerraformData" function. | |
*/ | |
const BASE_URL = "https://app.terraform.io/api/v2"; | |
function setUserPreference() { | |
const ui = SpreadsheetApp.getUi(); | |
const responseApiToken = ui.prompt( | |
'Settings: API Token', | |
'Please enter your API Token:', | |
ui.ButtonSet.OK_CANCEL); | |
if (responseApiToken.getSelectedButton() == ui.Button.CANCEL) { | |
return; | |
} | |
const responseOrganization = ui.prompt( | |
'Settings: Organization', | |
'Please enter your Organization:', | |
ui.ButtonSet.OK_CANCEL); | |
if (responseOrganization.getSelectedButton() == ui.Button.CANCEL) { | |
return; | |
} | |
var userProperties = PropertiesService.getUserProperties(); | |
userProperties.setProperty('API_TOKEN', responseApiToken.getResponseText()); | |
userProperties.setProperty('ORGANIZATION', responseOrganization.getResponseText()); | |
ui.alert('Settings have been saved.'); | |
} | |
function getUserPreference() { | |
var userProperties = PropertiesService.getUserProperties(); | |
var apiToken = userProperties.getProperty('API_TOKEN'); | |
var organization = userProperties.getProperty('ORGANIZATION'); | |
Logger.log('ORGANIZATION: "' + organization + '"'); | |
Logger.log('API_TOKEN: "' + apiToken + '"'); | |
} | |
// Retrieve from user properties | |
function getToken() { | |
return PropertiesService.getUserProperties().getProperty('API_TOKEN'); | |
} | |
function getOrganization() { | |
return PropertiesService.getUserProperties().getProperty('ORGANIZATION'); | |
} | |
// Format the date and time into 'YYYY/MM/DD' and 'HH:MM:SS' | |
function formatDate(date) { | |
const year = date.getFullYear(); | |
const month = ('0' + (date.getMonth() + 1)).slice(-2); | |
const day = ('0' + date.getDate()).slice(-2); | |
const hours = ('0' + date.getHours()).slice(-2); | |
const minutes = ('0' + date.getMinutes()).slice(-2); | |
const seconds = ('0' + date.getSeconds()).slice(-2); | |
return { | |
date: `${year}/${month}/${day}`, | |
time: `${hours}:${minutes}:${seconds}` | |
}; | |
} | |
function getTerraformData() { | |
const workspaces = listWorkspaces(); | |
const sheet = createOrGetSheet("Data"); | |
const currentDate = formatDate(new Date()); | |
// Set headers | |
const headers = [ | |
"Date", "Time", "WorkspaceName", "WorkspaceID", | |
"ResourceCount", "BillableResourceCount", | |
"TerraformVersion", "StateVersion", "Serial" | |
]; | |
if (sheet.getLastRow() === 0) { | |
sheet.appendRow(headers); | |
} | |
let data = []; | |
workspaces.forEach(workspace => { | |
const workspaceName = workspace.attributes.name; | |
Logger.log(`Workspaces[${workspaceName}]: WorkspaceID: ${workspace.id}`); | |
const currentState = getCurrentStateVersion(workspaceName, workspace.id); | |
let terraformVersion = "-"; | |
let stateVersion = "-"; | |
let serial = "-"; | |
if (currentState) { | |
terraformVersion = currentState.attributes["terraform-version"]; | |
stateVersion = currentState.attributes["state-version"]; | |
serial = currentState.attributes["serial"]; | |
} | |
const resourceCounts = calResourceCounts(currentState); | |
Logger.log(`Workspaces[${workspaceName}]: ${JSON.stringify(resourceCounts)}`); | |
data.push([ | |
currentDate.date, currentDate.time, workspaceName, workspace.id, | |
resourceCounts.resourceCount, resourceCounts.billableResourceCount, | |
terraformVersion, stateVersion, serial | |
]); | |
}); | |
// Append data | |
sheet.getRange(sheet.getLastRow() + 1, 1, data.length, headers.length).setValues(data); | |
} | |
// [List workspaces](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#list-workspaces) | |
function listWorkspaces() { | |
const token = getToken(); | |
const organization = getOrganization(); | |
try { | |
const response = UrlFetchApp.fetch(`${BASE_URL}/organizations/${organization}/workspaces`, { | |
"headers": { | |
"Authorization": `Bearer ${token}`, | |
"Content-Type": "application/vnd.api+json" | |
}, | |
"method": "get", | |
"muteHttpExceptions": true | |
}); | |
const workspaces = JSON.parse(response.getContentText()).data; | |
Logger.log(`Workspaces: ${workspaces.length}`); | |
return workspaces; | |
} catch(e) { | |
Logger.log(`Error listWorkspaces: ${e}`); | |
} | |
} | |
// [Fetch the Current State Version for a Workspace](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions#fetch-the-current-state-version-for-a-workspace) | |
function getCurrentStateVersion(workspaceName, workspaceId) { | |
const token = getToken(); | |
try { | |
const response = UrlFetchApp.fetch(`${BASE_URL}/workspaces/${workspaceId}/current-state-version`, { | |
"headers": { | |
"Authorization": `Bearer ${token}`, | |
"Content-Type": "application/vnd.api+json" | |
}, | |
"method": "get", | |
"muteHttpExceptions": true | |
}); | |
currentStateVersion = JSON.parse(response.getContentText()).data; | |
return currentStateVersion; | |
} catch(e) { | |
Logger.log(`Error getCurrentStateVersion: ${e}`); | |
} | |
} | |
function calResourceCounts(currentState) { | |
let resourceCount = 0; | |
let billableResourceCount = 0; | |
if (currentState && currentState.attributes && currentState.attributes.resources) { | |
currentState.attributes.resources.forEach(resource => { | |
resourceCount += resource.count; | |
// [What is a Managed Resource?](https://developer.hashicorp.com/terraform/cloud-docs/overview/estimate-hcp-terraform-cost#what-is-a-managed-resource) | |
if (!resource.type.startsWith('data.') | |
&& resource.type !== 'null_resource' | |
&& resource.type !== 'terraform_data' | |
) { | |
billableResourceCount += resource.count; | |
} | |
}); | |
} | |
return { | |
resourceCount: resourceCount, | |
billableResourceCount: billableResourceCount | |
}; | |
} | |
function createOrGetSheet(sheetName) { | |
const ss = SpreadsheetApp.getActiveSpreadsheet(); | |
let sheet = ss.getSheetByName(sheetName); | |
if (!sheet) { | |
sheet = ss.insertSheet(sheetName); | |
} | |
return sheet; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment