# Terraform Provider Overview

The official DanubeData Terraform provider allows you to manage your cloud infrastructure using Infrastructure as Code (IaC). Deploy VPS instances, databases, caches, storage buckets, and more with version-controlled, reproducible configurations.

## Why Use Terraform?

- **Version Control**: Track infrastructure changes in Git alongside your application code
- **Reproducible Deployments**: Deploy identical environments across dev, staging, and production
- **Team Collaboration**: Share configurations and collaborate with pull requests
- **Drift Detection**: Detect and fix configuration drift automatically
- **Cost Visibility**: Preview costs before deployment with `terraform plan`

## Quick Start

### 1. Install Terraform

Download and install Terraform from [terraform.io](https://www.terraform.io/downloads):

```bash
# macOS with Homebrew
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

# Ubuntu/Debian
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

# Verify installation
terraform version
```

### 2. Get Your API Token

1. Log in to your DanubeData dashboard
2. Navigate to **Settings > API Tokens**
3. Click **Create New Token**
4. Select the permissions you need (at minimum: read/write for resources you want to manage)
5. Copy the token - it's shown only once!

### 3. Configure the Provider

Create a new directory for your Terraform configuration:

```bash
mkdir my-infrastructure
cd my-infrastructure
```

Create a `main.tf` file:

```hcl
terraform {
  required_providers {
    danubedata = {
      source  = "AdrianSilaghi/danubedata"
      version = "~> 0.1"
    }
  }
}

provider "danubedata" {
  # API token is read from DANUBEDATA_API_TOKEN environment variable
}
```

Set your API token as an environment variable:

```bash
export DANUBEDATA_API_TOKEN="your-api-token-here"
```

### 4. Initialize and Apply

```bash
# Initialize the provider
terraform init

# Preview changes
terraform plan

# Apply changes
terraform apply
```

## Provider Configuration

The provider supports the following configuration options:

| Attribute | Type | Required | Description |
|-----------|------|----------|-------------|
| `api_token` | string | Yes | Your DanubeData API token. Can also be set via `DANUBEDATA_API_TOKEN` environment variable. |
| `base_url` | string | No | API endpoint URL. Defaults to `https://danubedata.ro/api/v1`. Can be set via `DANUBEDATA_BASE_URL` environment variable. |

### Authentication Methods

**Recommended: Environment Variable**

```bash
export DANUBEDATA_API_TOKEN="your-api-token"
```

```hcl
provider "danubedata" {}
```

**Alternative: Direct Configuration** (not recommended for production)

```hcl
provider "danubedata" {
  api_token = "your-api-token"  # Don't commit this to version control!
}
```

**Using Terraform Variables**

```hcl
variable "danubedata_token" {
  type      = string
  sensitive = true
}

provider "danubedata" {
  api_token = var.danubedata_token
}
```

Then set the variable:
```bash
export TF_VAR_danubedata_token="your-api-token"
```

## Available Resources

The provider includes the following resource types:

| Resource | Description |
|----------|-------------|
| `danubedata_vps` | Virtual machines with shared or dedicated CPU |
| `danubedata_database` | Managed MySQL, PostgreSQL, and MariaDB databases |
| `danubedata_database_replica` | Read replicas for a managed database |
| `danubedata_cache` | Redis, Valkey, and Dragonfly cache instances |
| `danubedata_parameter_group` | Reusable database/cache configuration presets |
| `danubedata_serverless` | Scale-to-zero serverless containers |
| `danubedata_static_site` | Static site hosting |
| `danubedata_static_site_domain` | Custom domain for a static site |
| `danubedata_storage_bucket` | S3-compatible object storage buckets |
| `danubedata_storage_access_key` | Access keys for object storage |
| `danubedata_ssh_key` | SSH keys for VPS authentication |
| `danubedata_firewall` | Network security rules |
| `danubedata_vps_snapshot` | Point-in-time VPS backups |
| `danubedata_database_snapshot` | Point-in-time database backups |
| `danubedata_cache_snapshot` | Point-in-time cache backups |

See [Terraform Resources](https://docs.danubedata.ro/terraform-resources) for detailed documentation.

## Available Data Sources

The provider includes these data sources for querying existing resources:

| Data Source | Description |
|-------------|-------------|
| `danubedata_vpss` | List existing VPS instances |
| `danubedata_vps_images` | List available OS images |
| `danubedata_databases` | List existing databases |
| `danubedata_database_providers` | List available database engines |
| `danubedata_database_snapshots` | List database snapshots |
| `danubedata_caches` | List existing cache instances |
| `danubedata_cache_providers` | List available cache providers |
| `danubedata_cache_snapshots` | List cache snapshots |
| `danubedata_parameter_groups` | List parameter groups |
| `danubedata_serverless_containers` | List serverless containers |
| `danubedata_static_sites` | List static sites |
| `danubedata_storage_buckets` | List storage buckets |
| `danubedata_storage_access_keys` | List storage access keys |
| `danubedata_ssh_keys` | List existing SSH keys |
| `danubedata_firewalls` | List firewalls |
| `danubedata_vps_snapshots` | List VPS snapshots |

See [Terraform Data Sources](https://docs.danubedata.ro/terraform-data-sources) for detailed documentation.

## Supported Datacenters

All resources are deployed to our single datacenter:

| Code | Location | Country |
|------|----------|---------|
| `fsn1` | Falkenstein | Germany |

## State Management

Terraform tracks your infrastructure state in a state file. The state — not your API token — records which resources Terraform already manages, so it is what decides whether a plan creates, changes or destroys something. For team collaboration, use a remote backend.

### Using DanubeData Object Storage as Backend

```hcl
terraform {
  backend "s3" {
    bucket = "terraform-state"
    key    = "my-project/terraform.tfstate"
    region = "fsn1"

    endpoints = { s3 = "https://s3.danubedata.ro" }

    use_path_style              = true
    use_lockfile                = true
    skip_credentials_validation = true
    skip_requesting_account_id  = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    skip_s3_checksum            = true
  }
}
```

The `skip_*` flags are required: our object storage is S3-compatible but is not AWS, so the AWS-specific credential, account-ID and metadata lookups have to be turned off. `use_lockfile = true` enables state locking against the bucket itself, with no DynamoDB table, so two CI runs cannot write the state at once — it needs Terraform 1.10 or later.

Set S3 credentials from a storage access key:
```bash
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
```

## Importing Existing Resources

You can import existing DanubeData resources into Terraform management:

```bash
# Import a VPS instance
terraform import danubedata_vps.my_server 12345

# Import a database
terraform import danubedata_database.my_db 67890

# Import a storage bucket
terraform import danubedata_storage_bucket.my_bucket abc123
```

Find resource IDs in the DanubeData dashboard or via the API.

## Best Practices

### Give Each Environment Its Own State

Separate environments need separate state. An API token decides which project a call goes to, but it does not change what Terraform already believes it manages — that comes from the state file.

> **Do not point one root module at several environments by changing a variable.** If your state already holds a `production` resource and you re-run it with `environment = "test"`, Terraform does not create something new: it compares the config against the resource it already tracks and plans to replace it. Attributes such as `name`, `engine` and `database_name` cannot be changed on a running instance, so the plan comes back as `1 to add, 1 to destroy` — and the resource it destroys is the live production one.

Give each environment its own root module, its own state key and its own token:

```
modules/stack/       shared resource definitions, taking env as a variable
envs/prod/           key prod/terraform.tfstate,  production token
envs/test/           key test/terraform.tfstate,  test token
```

Each environment directory holds only a backend block, a provider block and a call to the shared module:

```hcl
# envs/test/main.tf
terraform {
  backend "s3" {
    bucket = "my-tfstate"
    key    = "test/terraform.tfstate"
    # ...remaining backend settings as above
  }
}

provider "danubedata" {}   # token from DANUBEDATA_API_TOKEN

module "stack" {
  source = "../../modules/stack"
  env    = "test"
}
```

Now `terraform apply` in `envs/test/` starts from an empty state and creates the test resources, while production is untouched — because a different state file describes it.

Resource names are unique per project rather than globally, so the same name can be used in every environment and only values that must differ, such as a database's initial database name, need to include `var.env`.

Terraform workspaces are an alternative, but the API token still has to change per environment through the shell environment, so separate root modules are harder to get wrong.

### Use One Project per Environment

Create a separate project (team) for each environment and issue each one its own API token, scoped to that project. Projects are the isolation boundary on our side: separate Kubernetes namespace, separate quotas and separate billing lines.

### Mark Sensitive Outputs

```hcl
output "database_password" {
  value     = danubedata_database.main.password
  sensitive = true
}
```

### Use Terraform Cloud for Team Collaboration

For larger teams, consider using Terraform Cloud for:
- Remote state management
- Policy enforcement
- VCS integration
- Cost estimation

## Troubleshooting

### Authentication Errors

If you see "401 Unauthorized":
1. Verify your API token is correct
2. Check the token has the required permissions
3. Ensure the `DANUBEDATA_API_TOKEN` environment variable is set

### Provider Not Found

If Terraform can't find the provider:
```bash
terraform init -upgrade
```

### Resource Timeouts

For long-running operations, configure timeouts:

```hcl
resource "danubedata_vps" "app" {
  # ...

  timeouts {
    create = "10m"
    update = "10m"
    delete = "5m"
  }
}
```

## Next Steps

- [Terraform Resources](https://docs.danubedata.ro/terraform-resources) - Detailed resource documentation
- [Terraform Data Sources](https://docs.danubedata.ro/terraform-data-sources) - Query existing resources
- [Terraform Examples](https://docs.danubedata.ro/terraform-examples) - Real-world configuration examples
- [Terraform Registry](https://registry.terraform.io/providers/AdrianSilaghi/danubedata/latest) - Official provider documentation

## Support

- **Documentation**: [registry.terraform.io/providers/AdrianSilaghi/danubedata](https://registry.terraform.io/providers/AdrianSilaghi/danubedata/latest/docs)
- **GitHub Issues**: Report bugs and request features
- **Contact Support**: Reach out to our support team for help
