Skip to content

Added Terraform backend implementation for OCI Object Storage #36872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 22, 2025

Conversation

ravinitp
Copy link
Contributor

@ravinitp ravinitp commented Apr 10, 2025

Terraform backend implementation for OCI Object Storage

A new Terraform backend utilising Oracle Cloud Infrastructure (OCI) Object Storage as the storage backend. Leveraging OCI Object Storage provides a scalable and cost-effective alternative to traditional backends, offering a robust solution for state file storage and management.
RFC#34465
RFC#32634

Added

Terraform backend implementation for OCI Object Storage

Target Release

1.12.x

CHANGELOG entry

  • This change is user-facing and I added a changelog entry.
  • This change is not user-facing.

@ravinitp ravinitp requested a review from a team as a code owner April 10, 2025 10:08
@ravinitp ravinitp marked this pull request as draft April 10, 2025 10:46
@ravinitp
Copy link
Contributor Author

ravinitp commented Apr 10, 2025

Test Case Code comand Result comment
only required attribute                 terraform {
backend "oci" {
bucket = "state-file-bucket"
namespace = "my-namespace"
} }
./terraform apply ✅ Success
Missing required field terraform {
backend "oci" {
namespace = "my-namespace"
region = "us-ashburn-1"
} }
./terraform init Prompt Enter the value of bucket
lock test with deferent machine with same state file in same bucket                  - ./terraform apply on both machine ❌ One machine acquired the lock, another failed Error: Error acquiring the state lock Lock Info:
ID: 1fc42ad8-a338-906c-8781-c71b9eaf3c8f
Path: tf-state-env/prod/etf.json
Operation: OperationTypeApply
Who: ravbhart@ravbhart-mac
Version: 1.13.0
Created: 2025-04-10 15:35:23.842504 +0000 UTC Info:
lock test with deferent machine with different state file in the same bucket                  terraform {
backend "oci" {
key= state1.json
bucket = "state-file-bucket"
namespace = "my-namespace"
} }
------------------
terraform {
backend "oci" {
key= state2.json
bucket = "state-file-bucket"
namespace = "my-namespace"
} }
./terraform apply on both machine at same time ✅ Both operation succeeded
optional attribute with basic auth                  terraform { backend "oci" { bucket = "terraform-state"
key = "etf.json"
namespace = "namespace"
tenancy_ocid = "ocid1.tenancy.oc1..xxxxx"
user_ocid = "ocid1.user.oc1..xxxxx"
fingerprint = "bd:9e:49:9c:39:1e:40:73:0c:91"
private_key_path = "~/ssh/private_key_25-04-08T10_29_58.508Z.pem"
region = "us-ashburn-1"
} }
./terraform apply ✅ success
State Consistency Check Scenario
Start a terraform apply operation from Machine A and keep it pending for approval.
From Machine B, forcefully unlock the state file lock and initiate another terraform apply (this will overwrite the state).
Go back to Machine A and approve the original pending operation.
- - ❌ Unable to persist state file ETag mismatch due to overwritten state
Corrupted state file scenario
1. Create a corrupted state file in the bucket.
2. Run terraform init and terraform apply.
3. Observe the error message.
- ❌ Unable to persist state file │ Error: Unsupported state file format The state file could not be parsed as JSON: syntax error at byte offset 1.
new workspace env                  - ./terraform workspace new dev
./terraform apply
✅ Success After successful command able to see file tf-state-env/dev/terraform.tfstate and .md file
list workspace env                  - ./terraform workspace list ✅ Success Able to see list of workspace env default *dev
delete workspace                  - ./terraform workspace select default
./terraform workspace delete dev
✅ Success state file in dev env got deleted
Multipart Upload with Custom Part Size(not updatable for customers)
Modified the DefaultFilePartSize to 1 KB (1024 bytes) to validate multipart upload functionality with small part sizes. This helps ensure that multipart logic triggers and functions correctly, even for small files.
- ./terraform apply ✅ Success state file got uploaded using multipart approach
Note: By default statefile > 128mb will use multipart upload.

@ravinitp ravinitp changed the title [Draft]Added Terraform backend implementation for OCI Object Storage Added Terraform backend implementation for OCI Object Storage Apr 10, 2025
@ravinitp ravinitp force-pushed the ravi/oci_backend branch 2 times, most recently from 4557056 to ed9e8dc Compare April 10, 2025 17:09
@ravinitp ravinitp marked this pull request as ready for review April 11, 2025 05:18
Copy link

@pvkrishnachaitanya pvkrishnachaitanya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed & Approved

@ravinitp ravinitp requested a review from a team as a code owner April 11, 2025 13:02
@ravinitp ravinitp force-pushed the ravi/oci_backend branch 5 times, most recently from 2dfb97c to 388404f Compare April 11, 2025 13:16
@SarahFrench
Copy link
Member

Hi @ravinitp, thanks for your PR!

Could you please let us know when this PR is ready for review, and mark the PR as draft until then? Force pushes to this branch make it hard for us to identify what code has changed since the last time we took a look.

@radeksimko
Copy link
Member

@ravinitp Can you please run make syncdeps?

Co-authored-by: Radek Simko <radeksimko@users.noreply.github.com>
@ravinitp
Copy link
Contributor Author

@radeksimko
Screenshot 2025-04-17 at 6 55 09 PM

@SarahFrench This is Instanceprincipal auth log
Uploading instancePrincipalAuth.log…

@ravinitp
Copy link
Contributor Author

@radeksimko ,
I have addressed feedback from today's call

ravbhart-mac:oci ravbhart$ go test -v ./
=== RUN   TestBackendBasic
    backend_test.go:29: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68010b5b"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
--- PASS: TestBackendBasic (16.90s)
=== RUN   TestBackendLocked_ForceUnlock
    backend_test.go:47: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68010b6c"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
    backend_test.go:52: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68010b6c"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
    testing.go:303: TestBackend: testing state locking for *oci.Backend
    backend_test.go:61: TestBackend: testing state locking for *oci.Backend
    testing.go:303: TestBackend: testing state locking for *oci.Backend
    backend_test.go:63: TestBackend: testing state locking for *oci.Backend
--- PASS: TestBackendLocked_ForceUnlock (30.42s)
=== RUN   TestBackendBasic_multipart_Upload
    backend_test.go:75: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68010b8a"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
--- PASS: TestBackendBasic_multipart_Upload (19.35s)
=== RUN   TestOCIBackendConfig_PrepareConfigValidation
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/null_bucket
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/key_with_trailing_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/key_with_double_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/workspace_key_prefix_with_leading_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/encryption_key_conflict
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/invalid_auth_method
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/empty_bucket
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/null_namespace
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/empty_namespace
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/key_with_leading_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/Invalid_encryption_key_combination
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/private_key_and_private_key_path_conflict
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/missing_region_for_InstancePrinciple_auth
--- PASS: TestOCIBackendConfig_PrepareConfigValidation (0.01s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/null_bucket (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/key_with_trailing_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/key_with_double_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/workspace_key_prefix_with_leading_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/encryption_key_conflict (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/invalid_auth_method (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/empty_bucket (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/null_namespace (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/empty_namespace (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/key_with_leading_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/Invalid_encryption_key_combination (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/private_key_and_private_key_path_conflict (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/missing_region_for_InstancePrinciple_auth (0.00s)
PASS
ok  	github.com/hashicorp/terraform/internal/backend/remote-state/oci	70.510s
ravbhart-mac:oci ravbhart$ 

@radeksimko
Copy link
Member

@ravinitp I originally thought the dependency change in the consul backend was unrelated to this PR but it is. I assume the objx library is a shared transitive dependency and as a result of OCI being added, it impacts consul's go.sum.

With that in mind, can you please run make syncdeps and commit and push that change to the consul backend?

@radeksimko
Copy link
Member

@ravinitp As per CI failure - Can you also run the following command and commit & push the outcome, please?

go tool golang.org/x/tools/cmd/goimports -w ./internal/backend/remote-state/oci

@ravinitp
Copy link
Contributor Author

Done goimports and sync deps

ravbhart-mac:oci ravbhart$ go test -v ./
=== RUN   TestBackendBasic
    backend_test.go:30: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68012121"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
--- PASS: TestBackendBasic (15.57s)
=== RUN   TestBackendLocked_ForceUnlock
    backend_test.go:48: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68012131"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
    backend_test.go:53: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-68012131"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
    testing.go:303: TestBackend: testing state locking for *oci.Backend
    backend_test.go:62: TestBackend: testing state locking for *oci.Backend
    testing.go:303: TestBackend: testing state locking for *oci.Backend
    backend_test.go:64: TestBackend: testing state locking for *oci.Backend
--- PASS: TestBackendLocked_ForceUnlock (29.58s)
=== RUN   TestBackendBasic_multipart_Upload
    backend_test.go:76: TestBackendConfig on *oci.Backend with configtesting.synthBody{Filename:"<TestWrapConfig>", Values:map[string]cty.Value{"bucket":cty.StringVal("terraform-remote-oci-test-6801214e"), "key":cty.StringVal("testState.json"), "namespace":cty.StringVal("idxvx0yktto5")}}
--- PASS: TestBackendBasic_multipart_Upload (19.15s)
=== RUN   TestOCIBackendConfig_PrepareConfigValidation
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/null_bucket
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/null_namespace
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/key_with_double_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/workspace_key_prefix_with_leading_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/encryption_key_conflict
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/Invalid_encryption_key_combination
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/private_key_and_private_key_path_conflict
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/invalid_auth_method
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/empty_bucket
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/empty_namespace
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/key_with_leading_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/key_with_trailing_slash
=== RUN   TestOCIBackendConfig_PrepareConfigValidation/missing_region_for_InstancePrinciple_auth
--- PASS: TestOCIBackendConfig_PrepareConfigValidation (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/null_bucket (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/null_namespace (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/key_with_double_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/workspace_key_prefix_with_leading_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/encryption_key_conflict (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/Invalid_encryption_key_combination (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/private_key_and_private_key_path_conflict (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/invalid_auth_method (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/empty_bucket (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/empty_namespace (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/key_with_leading_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/key_with_trailing_slash (0.00s)
    --- PASS: TestOCIBackendConfig_PrepareConfigValidation/missing_region_for_InstancePrinciple_auth (0.00s)
PASS
ok  	github.com/hashicorp/terraform/internal/backend/remote-state/oci	65.652s
ravbhart-mac:oci ravbhart$ 

Co-authored-by: Radek Simko <radeksimko@users.noreply.github.com>
@crw
Copy link
Contributor

crw commented Apr 17, 2025

IMO, the term oci should be reserved for future support of the Open Container Initiative, since that’s what OCI commonly refers to for most people outside the Oracle Cloud ecosystem.

Thanks for raising this! Given that the provider is already named oci (https://registry.terraform.io/providers/oracle/oci/latest/docs), we will continue to use the un-prefixed nomenclature for this backend. Thanks again for bringing this to our attention.

@radeksimko radeksimko merged commit 804e970 into hashicorp:main Apr 22, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.12-backport If you add this label to a PR before merging, backport-assistant will open a new PR once merged enhancement new-backend
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants