A Terraform provider for managing Synology NAS servers through the Synology DSM API. Built with Terraform Plugin Framework and the go-synology API client.
For usage documentation, see the Terraform Registry documentation or browse examples/.
- Core Management: Package installation, package feeds, task scheduler, events
- Container Management: Docker Compose projects with full service configuration
- File Station: File operations and cloud-init ISO generation
- Virtualization: Virtual machine lifecycle management
- Generic API: Direct access to any Synology DSM API endpoint
graph TB
A[Terraform Provider] --> B[Plugin Framework]
A --> C[go-synology Client]
B --> B1[Resources]
B --> B2[Data Sources]
B --> B3[Functions]
C --> C1[Core API]
C --> C2[Docker API]
C --> C3[FileStation API]
C --> C4[Virtualization API]
C1 --> D[Synology DSM]
C2 --> D
C3 --> D
C4 --> D
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
See the Provider Documentation for usage examples and configuration.
Quick Example:
terraform {
required_providers {
synology = {
source = "synology-community/synology"
version = "~> 1.0"
}
}
}
provider "synology" {
host = "your-synology.local:5001"
user = "admin"
password = var.synology_password
}
resource "synology_container_project" "app" {
name = "my-app"
services = {
web = {
image = "nginx:latest"
ports = [{ target = 80, published = "8080" }]
}
}
}- Go 1.21+
- Terraform 1.5+
- Docker Desktop (for acceptance tests)
- Make (optional, for convenience commands)
# Clone the repository
git clone https://github.com/synology-community/terraform-provider-synology.git
cd terraform-provider-synology
# Build the provider
go build .
# Install locally for testing
make installUnit Tests:
go test ./synology/...Acceptance Tests:
The provider uses testcontainers-go to run acceptance tests against a virtualized Synology DSM instance. This avoids the need to test against real infrastructure.
# Run all acceptance tests
TF_ACC=1 go test ./synology/provider/... -v -timeout 30m
# Run specific test
TF_ACC=1 go test ./synology/provider/... -v -run TestAccResource_ContainerProject
# Show DSM container output
TF_ACC=1 DSM_STDOUT=1 go test ./synology/provider/... -vHow Acceptance Tests Work:
- Test runner starts a Docker Compose stack with a virtual DSM instance (using
vdsm/virtual-dsm) - Container runs in software emulation mode (TCG) - no KVM required, works on all platforms
- Tests wait for DSM API to become available (2-5 minutes on first run)
- Tests execute against the virtual DSM
- Container is cleaned up automatically
Cross-Platform Compatibility:
- ✅ macOS (Intel and Apple Silicon)
- ✅ Linux (with or without KVM)
- ✅ Windows (with Docker Desktop)
Troubleshooting Tests:
# Increase timeout for slow machines
TF_ACC=1 go test ./synology/provider/... -v -timeout 60m
# Check Docker logs
docker logs dsm-test
# Clean up test volumes
docker volume prunePerformance Notes:
- First test run downloads ~2GB DSM image
- DSM initialization takes 2-5 minutes on first start
- Subsequent runs are faster (cached state)
- TCG emulation is slower than KVM but works everywhere
terraform-provider-synology/
├── synology/
│ ├── provider/ # Provider implementation
│ │ ├── provider.go # Main provider
│ │ ├── container/ # Container resources
│ │ ├── core/ # Core system resources
│ │ ├── filestation/ # File Station resources
│ │ └── virtualization/ # VM resources
│ ├── models/ # Data models
│ ├── util/ # Shared utilities
│ └── acctest/ # Acceptance test helpers
├── examples/ # Usage examples
├── docs/ # Generated documentation
├── docker-compose.yaml # Test infrastructure
└── .github/
└── instructions/ # Copilot development guides
-
Create the resource file in the appropriate package (e.g.,
synology/provider/core/my_resource.go) -
Implement the resource interface:
package core
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)
type MyResource struct {
client core.Api
}
func NewMyResource() resource.Resource {
return &MyResource{}
}
func (r *MyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = buildName(req.ProviderTypeName, "my_resource")
}
func (r *MyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Resource description with examples...",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
// Add your attributes...
},
}
}
// Implement Create, Read, Update, Delete, Configure methods...- Register the resource in
synology/provider/provider.go:
func (p *synologyProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
// ... existing resources
core.NewMyResource,
}
}-
Add tests in
synology/provider/core/my_resource_test.go -
Add examples in
examples/resources/synology_my_resource/ -
Generate documentation:
go generate ./...- Follow the style guide
- Use
gofmtfor formatting - Run linters:
golangci-lint run - Write acceptance tests for all resources
See testing guide for detailed testing patterns.
Key Testing Principles:
- All resources must have acceptance tests
- Use testcontainers for infrastructure
- Mock external dependencies in unit tests
- Test both success and failure paths
- Verify state after operations
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make your changes following the code style
- Add tests for new functionality
- Run tests:
TF_ACC=1 go test ./synology/provider/... -v - Commit with conventional commits (
feat:,fix:,docs:, etc.) - Push and create a pull request
<type>(<scope>): <description>
[optional body]
[optional footer]
Types: feat, fix, docs, style, refactor, test, chore
Examples:
feat(container): add network_mode support to project resource
fix(virtualization): handle missing storage_id gracefully
docs(readme): update testing instructions
test(core): add acceptance tests for package resource
- Provider Documentation - Complete usage guide
- Resource Examples - Example configurations for each resource
- Data Source Examples - Example data source usage
- Synology API Documentation - Official API docs
- Terraform Plugin Framework - Framework documentation
- go-synology Client - API client library
- Member of Administrators group (Container Manager has no RBAC)
- Read/Write access on target shares
- Applications granted:
- DSM
- File Station
- Virtual Machine Manager permissions
- Storage access permissions
Authentication failures:
- Verify host, username, and password are correct
- Check if 2FA is enabled (provide
otp_secretif using TOTP) - Ensure account has necessary permissions for the operations
Connection errors:
- Verify DSM is accessible at the configured host
- Check SSL certificate validation (
skip_cert_check = truefor self-signed certs) - Confirm firewall rules allow connections on the specified port
Tests timeout:
- Increase timeout:
-timeout 60m - Check Docker has sufficient resources (CPU/RAM)
- Verify Docker is running:
docker ps
Container fails to start:
- Check Docker logs:
docker logs dsm-test - Ensure sufficient disk space available
- Remove old volumes:
docker volume prune
API connection failures:
- Wait longer for DSM initialization (can take 5+ minutes)
- Check if container is healthy:
docker ps(should show "healthy") - Verify container networking:
docker exec dsm-test curl localhost:5000
- Update
CHANGELOG.mdwith changes - Create release branch:
git checkout -b release/v1.x.x - Update version in relevant files
- Tag release:
git tag v1.x.x - Push tag:
git push origin v1.x.x - GitHub Actions will build and publish to Terraform Registry
Mozilla Public License 2.0 - see LICENSE for details.
- Built with Terraform Plugin Framework
- API client: go-synology
- Token caching: 99designs/keyring
- Testing: testcontainers-go
- Virtual DSM: vdsm/virtual-dsm
Made with ❤️ by the Synology Community