
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/.
Features
- 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
Architecture
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
Quick Start
For Users
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" }]
}
}
}
For Developers
Prerequisites
Building
# 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 install
Running Tests
Unit 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/... -v
How 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 prune
Performance 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
Development
Project Structure
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
Adding a New Resource
-
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 ./...
Code Style
- Follow the style guide
- Use
gofmt for formatting
- Run linters:
golangci-lint run
- Write acceptance tests for all resources
Testing Guidelines
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
Contributing
- 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
Documentation
For Users
For Developers
API Reference Links
Required Permissions
Container Manager
- Member of Administrators group (Container Manager has no RBAC)
- Read/Write access on target shares
- Applications granted:
Virtual Machine Manager
- Virtual Machine Manager permissions
- Storage access permissions
Troubleshooting
Provider Issues
Authentication failures:
- Verify host, username, and password are correct
- Check if 2FA is enabled (provide
otp_secret if 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 = true for self-signed certs)
- Confirm firewall rules allow connections on the specified port
Test Issues
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
Release Process
- Update
CHANGELOG.md with 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
License
Mozilla Public License 2.0 - see LICENSE for details.
Support
Acknowledgments
Made with ❤️ by the Synology Community