Skip to content

Instantly share code, notes, and snippets.

@htnosm
Last active July 18, 2024 21:53
Show Gist options
  • Save htnosm/6e718be98f0aac153d4ca06a11cc0ffd to your computer and use it in GitHub Desktop.
Save htnosm/6e718be98f0aac153d4ca06a11cc0ffd to your computer and use it in GitHub Desktop.
Fetch resource counts of HPC Terraform
/**
* 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