Last active
October 28, 2023 13:08
-
-
Save lukeplausin/aa64b48d7d4c373e26c1c9eddc81d914 to your computer and use it in GitHub Desktop.
Export terraform cloud state files with history to a GCS bucket
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
# This example shows how you can export your Hashicorp Terraform Cloud state files out of | |
# Terraform Cloud and into a bucket storage provider, with the full history. | |
# This example assumes that you have object versioning enabled on your bucket storage. | |
# The example is written for using Google Cloud Storage, but can be adapted for any storage provider. | |
# Before you run the code, you need to generate an API token in Terraform Cloud, and export it as "TFE_TOKEN" in your shell. | |
# pip install terrasnek google-cloud-storage ipython | |
from terrasnek.api import TFC | |
import os | |
import json | |
TFE_ORG = "name-of-your-terraform-cloud-org" | |
destination_bucket = "name-of-your-destination-terraform-statefile-bucket" | |
TFC_TOKEN = os.getenv("TFE_TOKEN", None) | |
TFC_URL = os.getenv("TFC_URL", "https://app.terraform.io") # ex: https://app.terraform.io | |
# set to True if you want to use HTTP or insecure HTTPS | |
SSL_VERIFY = os.getenv("SSL_VERIFY", True) | |
# if __name__ == "__main__": | |
api = TFC(TFC_TOKEN, url=TFC_URL, verify=SSL_VERIFY) | |
api.set_org(TFE_ORG) | |
from google.cloud import storage | |
storage_client = storage.Client() | |
bucket = storage_client.bucket(destination_bucket) | |
destinations = { | |
# You can set the locations within the bucket where you want to store your statefiles, per workspace name. | |
# If the value is set to "none" the statefile will not be exported. | |
"my-workspace-1": "terraform/state/my-workspace-1", | |
"my-workspace-2": "terraform/state/my-workspace-2", | |
"my-workspace-3": "terraform/state/my-workspace-3", | |
"my-workspace-that-doesnt-need-exporting": None, | |
} | |
for ws in api.workspaces.list_all()['data']: | |
# print(ws) | |
wsid = ws['id'] | |
wsname = ws['attributes']['name'] | |
print(f"{wsid} - {wsname}") | |
dest_path = destinations.get(wsname, None) | |
if not dest_path: | |
print(f"Workspace {wsname} no destination path set, skipping...") | |
continue | |
statefile_versions = api.state_versions.list_all([ | |
{ | |
"keys": ["workspace", "name"], # ends up as ["workspace"]["name"] | |
"value": wsname | |
}, | |
{ | |
"keys": ["organization", "name"], # ends up as ["organization"]["name"] | |
"value": TFE_ORG | |
} | |
] | |
) | |
for statefile in statefile_versions['data'][::-1]: | |
# They come in reverse order... | |
statefile_serial = statefile['attributes']['serial'] | |
print(f"Get statefile version {statefile_serial}...") | |
# statefile['attributes']['hosted-state-download-url'] | |
content = api._get(statefile['attributes']['hosted-state-download-url']) | |
gcs_path = dest_path + "/default.tfstate" | |
blob = bucket.blob(gcs_path) | |
print(f"Upload to gs://{destination_bucket}/{gcs_path}") | |
with blob.open('w') as f: | |
json.dump(content, f, indent=2) | |
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
terrasnek | |
ipython | |
google-cloud-storage |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment