Goal
Production changes go through code review and a pipeline, and the code matches what's deployed. You adopt existing resources rather than recreating them.
1. Generate Terraform from a compartment
Resource Manager → Create stack → Existing compartment runs Resource Discovery and produces a stack with Terraform config and state for the resources it finds. The same is available from the provider's discovery mode:
terraform-provider-oci -command=export -compartment_id=<comp-ocid> \
-output_path=./export -services=core,load_balancer,database,object_storage
Check the supported resource list — not every resource type is discoverable; note gaps to import manually.
2. Clean the output
The generated code is literal and flat. Refactor:
- Variables for compartment OCIDs, CIDRs, shapes, names.
- References instead of hard-coded OCIDs (
oci_core_subnet.app.id). - Modules per layer (network, compute, database).
- Use
movedblocks while refactoring so state follows without destroy/create.
3. Import what discovery missed
import {
to = oci_identity_policy.app_team
id = "ocid1.policy.oc1..aaaa..."
}
terraform plan -generate-config-out=extra.tf
terraform apply
terraform plan # goal: No changes.
Caution
A plan that says
must be replacedon a database, boot volume or bucket means your code differs on an immutable attribute. Fix the code. Addlifecycle { prevent_destroy = true }to data resources.
4. Where Terraform runs
| Option | Notes |
|---|---|
| OCI Resource Manager | Managed state, jobs, drift detection built in, runs as the user or with private access to VCNs |
| Pipeline (OCI DevOps, GitHub Actions, GitLab) | State in an Object Storage bucket (S3-compatible backend or the OCI backend), auth with instance/resource principals or OIDC where available |
Resource Manager stacks can be linked to a Git repository through a configuration source provider, so a merge updates the stack's code before plan/apply jobs.
oci resource-manager job create-plan-job --stack-id <stack-ocid>
oci resource-manager job create-apply-job --stack-id <stack-ocid> --execution-plan-strategy FROM_PLAN_JOB_ID --execution-plan-job-id <plan-job-ocid>
5. Drift
oci resource-manager stack detect-drift --stack-id <stack-ocid>
oci resource-manager stack list-resource-drift-details --stack-id <stack-ocid> --query 'data.items[?"resource-drift-status"!=`IN_SYNC`]'
Schedule drift detection and alert on differences. Then narrow console write access in production compartments: operators get read/use, the pipeline identity gets manage.
Checklist
- Compartment discovered; gaps imported
- Code refactored into modules with variables; no-change plan
- Data resources protected from destroy
- Stack in Resource Manager or pipeline with secured state
- Drift detection scheduled; console write access reduced