# Deployments

Source: https://docs.ops0.com/docs/iac/deployments

Deploy Terraform code to create, update, or destroy infrastructure. View real-time plan output, cost estimates, and resource outputs.

## Deployment Flow

### Validate
Check syntax errors before deployment

### Push
Sync code to GitHub for version control

### Plan
Preview what will be created, updated, or destroyed

### Review
Check plan output, cost estimate, and policy compliance

### Apply
Create or update resources in AWS

## Deployment Actions

- **Plan**: Preview changes without applying

- **Apply**: Execute the planned changes

- **Destroy**: Delete all managed resources

- **Targeted Deploy**: Deploy specific resources only using -target

---

## Plan Output

The plan shows exactly what will change before you apply:

| Symbol | Color | Meaning |
|--------|-------|---------|
| `+` | Green | Resource will be created |
| `~` | Yellow | Resource will be updated in-place |
| `-/+` | Yellow | Resource will be replaced (destroy then create) |
| `-` | Red | Resource will be destroyed |

### Example Plan Output

```diff
Terraform will perform the following actions:

+ aws_instance.web
    ami:           "ami-0c55b159cbfafe1f0"
    instance_type: "t3.medium"
    tags.Name:     "production-web"

~ aws_security_group.web
    ingress.0.cidr_blocks: ["10.0.0.0/16"] => ["10.0.0.0/8"]

- aws_s3_bucket.old_logs

Plan: 1 to add, 1 to change, 1 to destroy.
```

---

## Gating Requirements

Deployment requires these checks to pass:

| Requirement | Why |
|-------------|-----|
| Files exist | Nothing to deploy without Terraform code |
| Validation passed | Catch syntax errors before running plan |
| Pushed to GitHub | Version control changes before deployment |
| AWS integration | Valid credentials to access AWS APIs |

---

## Deployment Features

ops0 provides comprehensive deployment capabilities to safely manage infrastructure changes:

- [Validation](https://docs.ops0.com/docs/iac/deployments/validation): Validate Terraform syntax and configuration before deployment

- [Policy Checking](https://docs.ops0.com/docs/iac/deployments/policies): Enforce security, compliance, and cost policies

- [Cost Estimation](https://docs.ops0.com/docs/iac/deployments/cost): Estimate monthly costs and set budget limits

---

## Terraform Outputs

After a successful apply, view output values defined in your code.

### Defining Outputs

```hcl
output "api_endpoint" {
  description = "API Gateway endpoint URL"
  value       = aws_apigatewayv2_api.main.api_endpoint
}

output "database_endpoint" {
  description = "RDS cluster endpoint"
  value       = aws_rds_cluster.main.endpoint
  sensitive   = true
}

output "bucket_name" {
  description = "S3 bucket for uploads"
  value       = aws_s3_bucket.uploads.id
}
```

### Viewing Outputs

Click **Outputs** in the toolbar to see all output values:

| Output | Value |
|--------|-------|
| `api_endpoint` | `https://abc123.execute-api.us-east-1.amazonaws.com` |
| `database_endpoint` | `••••••••` (sensitive) |
| `bucket_name` | `myapp-uploads-prod` |

### Output Actions

| Action | Description |
|--------|-------------|
| **Copy** | Copy value to clipboard |
| **Reveal** | Show sensitive values (requires permission) |
| **Refresh** | Re-fetch outputs from state |

---

## Targeted Deployments

Deploy only specific resources instead of the entire project. Useful when you need to fix a single resource without touching the rest of your infrastructure.

### How to Target Resources

When clicking **Deploy**, expand **Advanced Options** and enter the resource address in the **Target Resources** field:

```
aws_instance.web
module.vpc.aws_subnet.public[0]
aws_security_group.db
```

Multiple targets can be specified — each on its own line.

### When to Use Targeted Deployments

| Scenario | Example Target |
|----------|---------------|
| Fix a broken security group | `aws_security_group.web` |
| Recreate a single instance | `aws_instance.app` |
| Update one subnet | `module.vpc.aws_subnet.private[0]` |
| Rebuild a module | `module.database` |

**Use Sparingly**

Targeted deployments can leave your state inconsistent with your code. After a targeted apply, run a full plan to verify the overall state matches your configuration.

---

## Approval Workflow

Deployments can require manual approval before the apply stage executes. Approvals are configured at the policy level and applied per project.

### Configuring Approvals

Attach a policy with approval requirements to your project via **IaC → Project Settings → Policies**. Once attached, all deployments for that project will require approval.

### Approval Flow

### Plan Runs
After clicking Deploy, the plan stage executes automatically.

### Awaiting Approval
Apply is held. Designated approvers are notified via configured alert channels (email, Slack).

### Approver Reviews
The approver opens the deployment and reviews:
- Plan output (resources to add, change, destroy)
- Cost estimate (previous vs. new monthly cost)
- Policy check results (any warnings or advisories)

### Decision
Approver clicks **Approve** to proceed or **Reject** to cancel. A rejection reason can be provided.

### Apply Executes
After approval, the apply stage runs immediately.

### Approval States

| State | Meaning |
|-------|---------|
| **Awaiting Approval** | Plan complete, waiting for approver |
| **Approved** | Approver approved — apply will run |
| **Rejected** | Approver rejected — deployment cancelled |

### Who Can Approve

Users with the `iac:approve` permission on the project can approve deployments. Org admins can always approve.

---

## Deployment Logs

View real-time Terraform output during deployment:

```
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.31.0...

aws_vpc.main: Creating...
aws_vpc.main: Creation complete after 2s [id=vpc-0abc123def456]

aws_subnet.public[0]: Creating...
aws_subnet.public[1]: Creating...
aws_subnet.public[0]: Creation complete after 1s
aws_subnet.public[1]: Creation complete after 1s

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
```

### Log Actions

| Action | Description |
|--------|-------------|
| **Download** | Save logs as text file |
| **Search** | Filter log output |
| **Auto-scroll** | Follow new output in real-time |

---

## Cancel Deployment

If a deployment is in progress, click **Cancel** to interrupt.

**Partial State**

Canceling mid-apply may leave resources partially created. The state file will reflect what was actually created. Run plan again to see current status.

---

## Destroy Resources

Click **Destroy** to delete all resources managed by the project.

**Destroy Warning**

Destroy permanently deletes all resources in the state file. This cannot be undone. You must type the project name to confirm destruction.

### Destroy Checklist

Before destroying:
- Download any data from S3 buckets
- Export RDS snapshots if needed
- Verify no other systems depend on these resources
- Confirm with team members

---

## Example: Deploying an Application Stack

### Initial Deployment

**main.tf**
```hcl
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "production"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
}

resource "aws_instance" "app" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.medium"
  subnet_id     = module.vpc.private_subnets[0]

  tags = {
    Name = "production-app"
  }
}

resource "aws_db_instance" "main" {
  identifier     = "production-db"
  engine         = "postgres"
  engine_version = "15.4"
  instance_class = "db.t3.medium"

  allocated_storage = 20
  storage_encrypted = true

  db_subnet_group_name   = module.vpc.database_subnet_group_name
  vpc_security_group_ids = [aws_security_group.db.id]

  skip_final_snapshot = false
  final_snapshot_identifier = "production-db-final"
}
```

**outputs.tf**
```hcl
output "vpc_id" {
  description = "VPC ID"
  value       = module.vpc.vpc_id
}

output "app_private_ip" {
  description = "Application server private IP"
  value       = aws_instance.app.private_ip
}

output "database_endpoint" {
  description = "Database connection endpoint"
  value       = aws_db_instance.main.endpoint
  sensitive   = true
}
```

### Deployment Result

**Plan:**
```diff
+ module.vpc.aws_vpc.this
+ module.vpc.aws_subnet.private[0]
+ module.vpc.aws_subnet.private[1]
+ module.vpc.aws_subnet.public[0]
+ module.vpc.aws_subnet.public[1]
+ module.vpc.aws_nat_gateway.this
+ aws_instance.app
+ aws_db_instance.main
+ aws_security_group.db

Plan: 9 to add, 0 to change, 0 to destroy.
```

**Cost Estimate:**
```
Monthly Cost Estimate
─────────────────────────────────────
NAT Gateway              $32.00/mo
EC2 t3.medium            $30.00/mo
RDS db.t3.medium         $49.00/mo
RDS Storage (20GB)        $2.30/mo
─────────────────────────────────────
Total:                  $113.30/mo
```

**Outputs After Apply:**
```
vpc_id         = "vpc-0abc123def456"
app_private_ip = "10.0.1.47"
database_endpoint = (sensitive value)
```

---

## Deployment States

Every deployment progresses through a series of states from creation to completion.

### State Flow

### Pending
Deployment created but not yet started. Queued for execution.

### Planning
Running `terraform plan` to preview changes.

### Planned
Plan completed successfully. Ready for apply or awaiting approval.

### Awaiting Approval
Deployment requires manual approval before applying changes. Approvers review the plan, cost estimate, and policy results.

### Applying
Running `terraform apply` to create/update/destroy resources.

### Completed
All changes successfully applied. Infrastructure is updated.

### Error States

| State | Meaning |
|-------|---------|
| **Failed** | Plan or apply stage encountered an error |
| **Policy Blocked** | Changes violate a blocking policy |
| **Cancelled** | User cancelled the deployment mid-execution |

### Checking Deployment Status

View the current state in the deployment panel:
- **Status badge** - Color-coded indicator (green = running, blue = completed, red = failed)
- **Progress indicators** - Visual progress for plan and apply stages
- **Duration** - Time elapsed since deployment started
- **Error messages** - Detailed error information if deployment failed

---

## Deployment History

View all past deployments for a project, including successful applies, failed attempts, and destroy operations.

### Accessing History

### Open your project
Navigate to the IaC project.

### Click deployment dropdown
Find the deployment selector in the project toolbar.

### View past deployments
All deployments are listed chronologically with status indicators.

### Deployment Information
Each deployment in history shows:

| Field | Description |
|-------|-------------|
| **Deployment #** | Sequential numbering (#1, #2, #3...) |
| **Type** | Deploy or Destroy |
| **Status** | Completed, Failed, or Cancelled |
| **Timestamp** | When the deployment was created |
| **Duration** | Total execution time |
| **User** | Who triggered the deployment |
| **Summary** | Resources added, changed, destroyed |

### Viewing Deployment Details

Click any deployment to see:

- **Plan Summary**: Detailed breakdown of additions, changes, and destructions (+3, ~2, -1)

- **Cost Impact**: Previous: $200.00 → New: $262.50 (+31.2%)

- **Resource Changes**: Full list of resources created, updated, or destroyed with plan output

- **Metadata**: Cloud provider, region, integration used, and error messages

### Comparing Deployments

Use deployment history to:

### Track Evolution
See how your infrastructure changed over time.

### Debug Issues
Compare a failed deployment to the last successful one.

### Audit Changes
Review who deployed what and when.

### Cost Tracking
Monitor cost changes across deployments.

---

## Real-Time Deployment Logs

Watch Terraform execution in real-time with live-streamed logs during plan and apply stages.

### Log Display Features

**Auto-Scroll**
- Logs automatically scroll to show the latest output
- Disable auto-scroll to review earlier output without jumping

**Collapsible Stages**
- Plan and Apply outputs are shown in separate, expandable sections
- Collapse completed stages to focus on active work

**Duration Tracking**
- Each stage shows elapsed time
- Total deployment duration displayed at completion

**Status Indicators**
- Running stages pulse with progress animation
- Completed stages show checkmark or error icon
- Failed stages highlight error messages in red

### Log Streaming

Logs stream in real-time using Server-Sent Events (SSE):
- Updates every ~500ms during active execution
- Shows `terraform init`, `terraform plan`, and `terraform apply` output
- Displays provider downloads and plugin initialization
- Shows resource creation/update/destroy progress

### Log Output Example

```log
[Plan Stage - Running]
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.31.0...

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
  - destroy

Terraform will perform the following actions:

  # aws_instance.web will be created
  + resource "aws_instance" "web" {
      + ami                          = "ami-0c55b159cbfafe1f0"
      + instance_type                = "t3.medium"
      ...
    }

Plan: 1 to add, 0 to change, 0 to destroy.
[Plan Stage - Completed in 8.2s]

[Apply Stage - Running]
aws_instance.web: Creating...
aws_instance.web: Still creating... [10s elapsed]
aws_instance.web: Still creating... [20s elapsed]
aws_instance.web: Creation complete after 24s [id=i-0abc123def456]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[Apply Stage - Completed in 25.1s]
```

**Log Limitations**

Currently, log search and filtering are not available. To find specific output, use your browser's find function (Ctrl+F or Cmd+F).

---

## Troubleshooting Deployments

### Plan fails immediately

**Common causes:**
- **Invalid syntax** - Check Terraform validate output for errors
- **Missing provider** - Ensure provider block is configured
- **Invalid credentials** - Verify cloud integration is connected
- **State lock** - Another deployment may be running

**Solution:** Review the plan output error message for specific line numbers and error details.

### Apply fails mid-execution

**Symptoms:** Some resources created, then deployment fails.

**What happens:**
- State file reflects resources that were successfully created
- Partially created resources remain in your cloud account
- You can re-run the deployment to continue where it left off

**Recovery steps:**
1. Review apply output to see which resource failed
2. Fix the error in your Terraform code (or cloud provider)
3. Re-deploy - Terraform will skip successfully created resources

### Deployment stuck in "Planning" state

**Check:**
- Deployment logs for hung operations
- Cloud provider API status (AWS, GCP, Azure)
- Network connectivity from ops0 to cloud provider APIs

**Solution:** Wait 5-10 minutes. If still stuck, contact support to investigate.

### Cost estimate shows $0

**Possible causes:**
- Resources don't have pricing data (new/preview services)
- Resources are free tier eligible
- Cost estimation service temporarily unavailable

**Note:** Cost estimates are best-effort. Always verify costs in your cloud provider's billing console.
