2021-03-18 03:30:54 -04:00
package provider
2018-05-16 12:00:04 -04:00
import (
2020-12-02 06:06:39 -05:00
"context"
2018-05-16 12:00:04 -04:00
"fmt"
2021-05-31 03:11:49 -04:00
"os"
2018-05-16 12:00:04 -04:00
"regexp"
2019-05-26 05:42:53 -04:00
"strconv"
"strings"
2018-05-16 12:00:04 -04:00
"testing"
2019-05-26 05:42:53 -04:00
"time"
2018-05-16 12:00:04 -04:00
2018-07-03 11:30:53 -04:00
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
2021-05-31 03:11:49 -04:00
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/swarm"
2021-03-18 03:30:54 -04:00
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
2018-05-16 12:00:04 -04:00
)
// ----------------------------------------
// ----------- UNIT TESTS -----------
// ----------------------------------------
2021-03-18 03:30:54 -04:00
func TestMigrateServiceV1ToV2_empty_restart_policy_and_auth ( t * testing . T ) {
v1State := map [ string ] interface { } {
"name" : "volume-name" ,
"task_spec" : [ ] interface { } {
map [ string ] interface { } {
"container_spec" : [ ] interface { } {
map [ string ] interface { } {
"image" : "repo:tag" ,
"stop_grace_period" : "10s" ,
} ,
} ,
} ,
} ,
}
// first validate that we build that correctly
v1Config := terraform . NewResourceConfigRaw ( v1State )
diags := resourceDockerServiceV1 ( ) . Validate ( v1Config )
if diags . HasError ( ) {
t . Error ( "test precondition failed - attempt to migrate an invalid v1 config" )
return
}
ctx := context . Background ( )
v2State , _ := resourceDockerServiceStateUpgradeV2 ( ctx , v1State , nil )
v2Config := terraform . NewResourceConfigRaw ( v2State )
diags = resourceDockerService ( ) . Validate ( v2Config )
if diags . HasError ( ) {
fmt . Println ( diags )
t . Error ( "migrated service config is invalid" )
return
}
}
func TestMigrateServiceV1ToV2_with_restart_policy ( t * testing . T ) {
v1State := map [ string ] interface { } {
"name" : "volume-name" ,
"task_spec" : [ ] interface { } {
map [ string ] interface { } {
"container_spec" : [ ] interface { } {
map [ string ] interface { } {
"image" : "repo:tag" ,
"stop_grace_period" : "10s" ,
} ,
} ,
"restart_policy" : map [ string ] interface { } {
"condition" : "on-failure" ,
"delay" : "3s" ,
"max_attempts" : 4 ,
"window" : "10s" ,
} ,
} ,
} ,
}
// first validate that we build that correctly
v1Config := terraform . NewResourceConfigRaw ( v1State )
diags := resourceDockerServiceV1 ( ) . Validate ( v1Config )
if diags . HasError ( ) {
t . Error ( "test precondition failed - attempt to migrate an invalid v1 config" )
return
}
ctx := context . Background ( )
v2State , _ := resourceDockerServiceStateUpgradeV2 ( ctx , v1State , nil )
v2Config := terraform . NewResourceConfigRaw ( v2State )
diags = resourceDockerService ( ) . Validate ( v2Config )
if diags . HasError ( ) {
fmt . Println ( diags )
t . Error ( "migrated service config is invalid" )
return
}
}
func TestMigrateServiceV1ToV2_with_auth ( t * testing . T ) {
v1State := map [ string ] interface { } {
"auth" : map [ string ] interface { } {
"server_address" : "docker-reg.acme.com" ,
"username" : "user" ,
"password" : "pass" ,
} ,
"name" : "volume-name" ,
"task_spec" : [ ] interface { } {
map [ string ] interface { } {
"container_spec" : [ ] interface { } {
map [ string ] interface { } {
"image" : "repo:tag" ,
"stop_grace_period" : "10s" ,
} ,
} ,
} ,
} ,
}
// first validate that we build that correctly
v1Config := terraform . NewResourceConfigRaw ( v1State )
diags := resourceDockerServiceV1 ( ) . Validate ( v1Config )
if diags . HasError ( ) {
t . Error ( "test precondition failed - attempt to migrate an invalid v1 config" )
return
}
ctx := context . Background ( )
v2State , _ := resourceDockerServiceStateUpgradeV2 ( ctx , v1State , nil )
v2Config := terraform . NewResourceConfigRaw ( v2State )
diags = resourceDockerService ( ) . Validate ( v2Config )
if diags . HasError ( ) {
fmt . Println ( diags )
2021-04-19 09:33:13 -04:00
t . Error ( "migrated service config is invalid" )
return
}
}
func TestMigrateServiceLabelState_empty_labels ( t * testing . T ) {
v0State := map [ string ] interface { } {
"name" : "volume-name" ,
"task_spec" : [ ] interface { } {
map [ string ] interface { } {
"container_spec" : [ ] interface { } {
map [ string ] interface { } {
"image" : "repo:tag" ,
"mounts" : [ ] interface { } {
map [ string ] interface { } {
"target" : "path/to/target" ,
"type" : "bind" ,
"volume_options" : [ ] interface { } {
map [ string ] interface { } { } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
}
// first validate that we build that correctly
v0Config := terraform . NewResourceConfigRaw ( v0State )
diags := resourceDockerServiceV0 ( ) . Validate ( v0Config )
if diags . HasError ( ) {
t . Error ( "test precondition failed - attempt to migrate an invalid v0 config" )
return
}
v1State := migrateServiceLabels ( v0State )
v1Config := terraform . NewResourceConfigRaw ( v1State )
diags = resourceDockerService ( ) . Validate ( v1Config )
if diags . HasError ( ) {
fmt . Println ( diags )
t . Error ( "migrated service config is invalid" )
return
}
}
func TestMigrateServiceLabelState_with_labels ( t * testing . T ) {
v0State := map [ string ] interface { } {
"name" : "volume-name" ,
"task_spec" : [ ] interface { } {
map [ string ] interface { } {
"container_spec" : [ ] interface { } {
map [ string ] interface { } {
"image" : "repo:tag" ,
"labels" : map [ string ] interface { } {
"type" : "container" ,
"env" : "dev" ,
} ,
"mounts" : [ ] interface { } {
map [ string ] interface { } {
"target" : "path/to/target" ,
"type" : "bind" ,
"volume_options" : [ ] interface { } {
map [ string ] interface { } {
"labels" : map [ string ] interface { } {
"type" : "mount" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
"labels" : map [ string ] interface { } {
"foo" : "bar" ,
"env" : "dev" ,
} ,
}
// first validate that we build that correctly
v0Config := terraform . NewResourceConfigRaw ( v0State )
diags := resourceDockerServiceV0 ( ) . Validate ( v0Config )
if diags . HasError ( ) {
t . Error ( "test precondition failed - attempt to migrate an invalid v0 config" )
return
}
v1State := migrateServiceLabels ( v0State )
v1Config := terraform . NewResourceConfigRaw ( v1State )
diags = resourceDockerService ( ) . Validate ( v1Config )
if diags . HasError ( ) {
fmt . Println ( diags )
2021-03-18 03:30:54 -04:00
t . Error ( "migrated service config is invalid" )
return
}
}
2018-05-16 12:00:04 -04:00
func TestDockerSecretFromRegistryAuth_basic ( t * testing . T ) {
2018-07-03 11:30:53 -04:00
authConfigs := make ( map [ string ] types . AuthConfig )
authConfigs [ "https://repo.my-company.com:8787" ] = types . AuthConfig {
2018-05-16 12:00:04 -04:00
Username : "myuser" ,
Password : "mypass" ,
Email : "" ,
ServerAddress : "repo.my-company.com:8787" ,
}
foundAuthConfig := fromRegistryAuth ( "repo.my-company.com:8787/my_image" , authConfigs )
checkAttribute ( t , "Username" , foundAuthConfig . Username , "myuser" )
checkAttribute ( t , "Password" , foundAuthConfig . Password , "mypass" )
checkAttribute ( t , "Email" , foundAuthConfig . Email , "" )
checkAttribute ( t , "ServerAddress" , foundAuthConfig . ServerAddress , "repo.my-company.com:8787" )
}
func TestDockerSecretFromRegistryAuth_multiple ( t * testing . T ) {
2018-07-03 11:30:53 -04:00
authConfigs := make ( map [ string ] types . AuthConfig )
authConfigs [ "https://repo.my-company.com:8787" ] = types . AuthConfig {
2018-05-16 12:00:04 -04:00
Username : "myuser" ,
Password : "mypass" ,
Email : "" ,
ServerAddress : "repo.my-company.com:8787" ,
}
2018-07-03 11:30:53 -04:00
authConfigs [ "https://nexus.my-fancy-company.com" ] = types . AuthConfig {
2018-05-16 12:00:04 -04:00
Username : "myuser33" ,
Password : "mypass123" ,
Email : "test@example.com" ,
ServerAddress : "nexus.my-fancy-company.com" ,
}
foundAuthConfig := fromRegistryAuth ( "nexus.my-fancy-company.com/the_image" , authConfigs )
checkAttribute ( t , "Username" , foundAuthConfig . Username , "myuser33" )
checkAttribute ( t , "Password" , foundAuthConfig . Password , "mypass123" )
checkAttribute ( t , "Email" , foundAuthConfig . Email , "test@example.com" )
checkAttribute ( t , "ServerAddress" , foundAuthConfig . ServerAddress , "nexus.my-fancy-company.com" )
foundAuthConfig = fromRegistryAuth ( "alpine:3.1" , authConfigs )
checkAttribute ( t , "Username" , foundAuthConfig . Username , "" )
checkAttribute ( t , "Password" , foundAuthConfig . Password , "" )
checkAttribute ( t , "Email" , foundAuthConfig . Email , "" )
checkAttribute ( t , "ServerAddress" , foundAuthConfig . ServerAddress , "" )
}
2020-12-20 05:04:51 -05:00
func checkAttribute ( t * testing . T , name , actual , expected string ) {
2018-05-16 12:00:04 -04:00
if actual != expected {
t . Fatalf ( "bad authconfig attribute for '%q'\nExpected: %s\n Got: %s" , name , expected , actual )
}
}
// ----------------------------------------
// ----------- ACCEPTANCE TESTS -----------
// ----------------------------------------
// Fire and Forget
var serviceIDRegex = regexp . MustCompile ( ` [A-Za-z0-9_\+\.-]+ ` )
2019-05-26 05:42:53 -04:00
func TestAccDockerService_minimalSpec ( t * testing . T ) {
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2018-05-16 12:00:04 -04:00
resource . Test ( t , resource . TestCase {
2021-03-18 03:30:54 -04:00
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
2018-05-16 12:00:04 -04:00
Steps : [ ] resource . TestStep {
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceMinimalSpec" ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2018-05-16 12:00:04 -04:00
) ,
} ,
2019-11-23 08:42:05 -05:00
{
ResourceName : "docker_service.foo" ,
ImportState : true ,
ImportStateVerify : true ,
} ,
2018-05-16 12:00:04 -04:00
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2018-07-03 11:30:53 -04:00
2019-05-26 05:42:53 -04:00
func TestAccDockerService_fullSpec ( t * testing . T ) {
2021-05-31 03:11:49 -04:00
var s swarm . Service
// validates the inspected service json contains
// all attributes set in the terraform spec so all mappers and flatteners
// work as expected. This is to avoid bugs like
// https://github.com/kreuzwerker/terraform-provider-docker/issues/202
testCheckServiceInspect := func ( * terraform . State ) error {
if len ( s . Spec . Labels ) != 1 || ! mapEquals ( "servicelabel" , "true" , s . Spec . Labels ) {
return fmt . Errorf ( "Service Spec.Labels is wrong: %v" , s . Spec . Labels )
}
2019-05-26 05:42:53 -04:00
2021-05-31 03:11:49 -04:00
if len ( s . Spec . TaskTemplate . ContainerSpec . Command ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . Command [ 0 ] != "ls" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Command is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Command )
}
2018-05-16 12:00:04 -04:00
2021-05-31 03:11:49 -04:00
if len ( s . Spec . TaskTemplate . ContainerSpec . Args ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . Args [ 0 ] != "-las" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Args is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Args )
}
2018-07-03 11:30:53 -04:00
2021-05-31 03:11:49 -04:00
if s . Spec . TaskTemplate . ContainerSpec . Hostname == "" ||
s . Spec . TaskTemplate . ContainerSpec . Hostname != "my-fancy-service" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Hostname is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Hostname )
}
2018-05-16 12:00:04 -04:00
2021-05-31 03:11:49 -04:00
// because the order is not deterministic
if len ( s . Spec . TaskTemplate . ContainerSpec . Env ) != 2 ||
( s . Spec . TaskTemplate . ContainerSpec . Env [ 0 ] != "URI=/api-call?param1=value1" && s . Spec . TaskTemplate . ContainerSpec . Env [ 0 ] != "MYFOO=BAR" ) ||
( s . Spec . TaskTemplate . ContainerSpec . Env [ 1 ] != "URI=/api-call?param1=value1" && s . Spec . TaskTemplate . ContainerSpec . Env [ 1 ] != "MYFOO=BAR" ) {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Env is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Env )
}
2018-05-16 12:00:04 -04:00
2021-05-31 03:11:49 -04:00
if s . Spec . TaskTemplate . ContainerSpec . Dir == "" ||
s . Spec . TaskTemplate . ContainerSpec . Dir != "/root" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Dir is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Dir )
}
if s . Spec . TaskTemplate . ContainerSpec . User == "" ||
s . Spec . TaskTemplate . ContainerSpec . User != "root" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.User is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . User )
}
if len ( s . Spec . TaskTemplate . ContainerSpec . Groups ) != 2 ||
s . Spec . TaskTemplate . ContainerSpec . Groups [ 0 ] != "docker" ||
s . Spec . TaskTemplate . ContainerSpec . Groups [ 1 ] != "foogroup" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Groups is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Groups )
}
if s . Spec . TaskTemplate . ContainerSpec . Privileges . CredentialSpec != nil {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Privileges.CredentialSpec is wrong: %v" , s . Spec . TaskTemplate . ContainerSpec . Privileges . CredentialSpec )
}
if s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext == nil ||
s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext . Disable != true ||
s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext . User != "user-label" ||
s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext . Role != "role-label" ||
s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext . Type != "type-label" ||
s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext . Level != "level-label" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Privileges.SELinuxContext is wrong: %v" , s . Spec . TaskTemplate . ContainerSpec . Privileges . SELinuxContext )
}
if s . Spec . TaskTemplate . ContainerSpec . StopSignal == "" ||
s . Spec . TaskTemplate . ContainerSpec . StopSignal != "SIGTERM" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.StopSignal is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . StopSignal )
}
if s . Spec . TaskTemplate . ContainerSpec . ReadOnly != true {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.ReadOnly is wrong: %v" , s . Spec . TaskTemplate . ContainerSpec . ReadOnly )
}
if len ( s . Spec . TaskTemplate . ContainerSpec . Mounts ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . Type != "volume" ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . Source != "tftest-volume" ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . Target != "/mount/test" ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . ReadOnly != true ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . BindOptions != nil ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . Consistency != mount . Consistency ( "" ) ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . VolumeOptions . NoCopy != true ||
! mapEquals ( "foo" , "bar" , s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . VolumeOptions . Labels ) ||
s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . VolumeOptions . DriverConfig . Name != "random-driver" ||
! mapEquals ( "op1" , "val1" , s . Spec . TaskTemplate . ContainerSpec . Mounts [ 0 ] . VolumeOptions . DriverConfig . Options ) {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Mounts is wrong: %#v" , s . Spec . TaskTemplate . ContainerSpec . Mounts )
}
if * s . Spec . TaskTemplate . ContainerSpec . StopGracePeriod != 10 * time . Second {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.StopGracePeriod is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . StopGracePeriod )
}
if s . Spec . TaskTemplate . ContainerSpec . Healthcheck == nil ||
len ( s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Test ) != 4 ||
s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Test [ 0 ] != "CMD" ||
s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Test [ 1 ] != "curl" ||
s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Test [ 2 ] != "-f" ||
s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Test [ 3 ] != "localhost:8080/health" ||
s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Interval != 5 * time . Second ||
s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Timeout != 2 * time . Second ||
time . Duration ( s . Spec . TaskTemplate . ContainerSpec . Healthcheck . Retries ) != 4 {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Healthcheck is wrong: %v" , s . Spec . TaskTemplate . ContainerSpec . Healthcheck )
}
if len ( s . Spec . TaskTemplate . ContainerSpec . Hosts ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . Hosts [ 0 ] != "10.0.1.0 testhost" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Hosts is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Hosts )
}
if s . Spec . TaskTemplate . ContainerSpec . DNSConfig == nil ||
len ( s . Spec . TaskTemplate . ContainerSpec . DNSConfig . Nameservers ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . DNSConfig . Nameservers [ 0 ] != "8.8.8.8" ||
len ( s . Spec . TaskTemplate . ContainerSpec . DNSConfig . Search ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . DNSConfig . Search [ 0 ] != "example.org" ||
len ( s . Spec . TaskTemplate . ContainerSpec . DNSConfig . Options ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . DNSConfig . Options [ 0 ] != "timeout:3" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.DNSConfig is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . DNSConfig )
}
if len ( s . Spec . TaskTemplate . ContainerSpec . Secrets ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . Secrets [ 0 ] . SecretName != "tftest-mysecret" ||
s . Spec . TaskTemplate . ContainerSpec . Secrets [ 0 ] . File . Name != "/secrets.json" ||
s . Spec . TaskTemplate . ContainerSpec . Secrets [ 0 ] . File . UID != "0" ||
s . Spec . TaskTemplate . ContainerSpec . Secrets [ 0 ] . File . GID != "0" ||
// nolint: staticcheck
s . Spec . TaskTemplate . ContainerSpec . Secrets [ 0 ] . File . Mode != os . FileMode ( 777 ) {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Secrets is wrong: %v" , s . Spec . TaskTemplate . ContainerSpec . Secrets )
}
2018-07-03 11:30:53 -04:00
2021-05-31 03:11:49 -04:00
if len ( s . Spec . TaskTemplate . ContainerSpec . Configs ) != 1 ||
s . Spec . TaskTemplate . ContainerSpec . Configs [ 0 ] . ConfigName != "tftest-full-myconfig" ||
s . Spec . TaskTemplate . ContainerSpec . Configs [ 0 ] . File . Name != "/configs.json" ||
s . Spec . TaskTemplate . ContainerSpec . Configs [ 0 ] . File . UID != "0" ||
s . Spec . TaskTemplate . ContainerSpec . Configs [ 0 ] . File . GID != "0" ||
s . Spec . TaskTemplate . ContainerSpec . Configs [ 0 ] . File . Mode != os . FileMode ( 292 ) {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Configs is wrong: %v" , s . Spec . TaskTemplate . ContainerSpec . Configs )
}
if s . Spec . TaskTemplate . ContainerSpec . Isolation == "" ||
s . Spec . TaskTemplate . ContainerSpec . Isolation != "default" {
return fmt . Errorf ( "Service Spec.TaskTemplate.ContainerSpec.Isolation is wrong: %s" , s . Spec . TaskTemplate . ContainerSpec . Isolation )
}
if s . Spec . TaskTemplate . Resources == nil ||
s . Spec . TaskTemplate . Resources . Limits == nil ||
s . Spec . TaskTemplate . Resources . Limits . NanoCPUs != 1000000 ||
s . Spec . TaskTemplate . Resources . Limits . MemoryBytes != 536870912 {
return fmt . Errorf ( "Service Spec.TaskTemplate.Resources is wrong: %v" , s . Spec . TaskTemplate . Resources )
}
if s . Spec . TaskTemplate . RestartPolicy == nil ||
s . Spec . TaskTemplate . RestartPolicy . Condition != "on-failure" ||
* s . Spec . TaskTemplate . RestartPolicy . Delay != 3 * time . Second ||
* s . Spec . TaskTemplate . RestartPolicy . MaxAttempts != 4 ||
* s . Spec . TaskTemplate . RestartPolicy . Window != 10 * time . Second {
return fmt . Errorf ( "Service Spec.TaskTemplate.RestartPolicy is wrong: %v" , s . Spec . TaskTemplate . RestartPolicy )
}
if s . Spec . TaskTemplate . Placement == nil ||
len ( s . Spec . TaskTemplate . Placement . Constraints ) != 1 ||
s . Spec . TaskTemplate . Placement . Constraints [ 0 ] != "node.role==manager" ||
len ( s . Spec . TaskTemplate . Placement . Preferences ) != 1 ||
s . Spec . TaskTemplate . Placement . Preferences [ 0 ] . Spread == nil ||
s . Spec . TaskTemplate . Placement . Preferences [ 0 ] . Spread . SpreadDescriptor != "spread=node.role.manager" ||
// s.Spec.TaskTemplate.Placement.MaxReplicas == uint64(2) || NOTE: mavogel: it's 0x2 in the log but does not work here either
len ( s . Spec . TaskTemplate . Placement . Platforms ) != 1 ||
s . Spec . TaskTemplate . Placement . Platforms [ 0 ] . Architecture != "amd64" ||
s . Spec . TaskTemplate . Placement . Platforms [ 0 ] . OS != "linux" {
return fmt . Errorf ( "Service Spec.TaskTemplate.Placement is wrong: %#v" , s . Spec . TaskTemplate . Placement )
}
if s . Spec . TaskTemplate . Runtime == "" ||
s . Spec . TaskTemplate . Runtime != "container" {
return fmt . Errorf ( "Service Spec.TaskTemplate.Runtime is wrong: %s" , s . Spec . TaskTemplate . Runtime )
}
if len ( s . Spec . TaskTemplate . Networks ) != 1 ||
s . Spec . TaskTemplate . Networks [ 0 ] . Target == "" {
return fmt . Errorf ( "Service Spec.TaskTemplate.Networks is wrong: %s" , s . Spec . TaskTemplate . Networks )
}
if s . Spec . TaskTemplate . LogDriver == nil ||
s . Spec . TaskTemplate . LogDriver . Name != "json-file" ||
! mapEquals ( "max-file" , "3" , s . Spec . TaskTemplate . LogDriver . Options ) ||
! mapEquals ( "max-size" , "10m" , s . Spec . TaskTemplate . LogDriver . Options ) {
return fmt . Errorf ( "Service Spec.TaskTemplate.LogDriver is wrong: %s" , s . Spec . TaskTemplate . LogDriver )
}
if s . Spec . TaskTemplate . ForceUpdate != 0 {
return fmt . Errorf ( "Service Spec.TaskTemplate.ForceUpdate is wrong: %v" , s . Spec . TaskTemplate . ForceUpdate )
}
if s . Spec . Mode . Replicated == nil ||
* s . Spec . Mode . Replicated . Replicas != uint64 ( 2 ) {
return fmt . Errorf ( "Service s.Spec.Mode.Replicated is wrong: %#v" , s . Spec . Mode . Replicated )
}
if s . Spec . UpdateConfig == nil ||
s . Spec . UpdateConfig . Parallelism != uint64 ( 2 ) ||
s . Spec . UpdateConfig . Delay != 10 * time . Second ||
s . Spec . UpdateConfig . FailureAction != "pause" ||
s . Spec . UpdateConfig . Monitor != 5 * time . Second ||
s . Spec . UpdateConfig . MaxFailureRatio != 0.1 ||
s . Spec . UpdateConfig . Order != "start-first" {
return fmt . Errorf ( "Service s.Spec.UpdateConfig is wrong: %#v" , s . Spec . UpdateConfig )
}
if s . Spec . RollbackConfig == nil ||
s . Spec . RollbackConfig . Parallelism != uint64 ( 2 ) ||
s . Spec . RollbackConfig . Delay != 5 * time . Millisecond ||
s . Spec . RollbackConfig . FailureAction != "pause" ||
s . Spec . RollbackConfig . Monitor != 10 * time . Hour ||
s . Spec . RollbackConfig . MaxFailureRatio != 0.9 ||
s . Spec . RollbackConfig . Order != "stop-first" {
return fmt . Errorf ( "Service s.Spec.RollbackConfig is wrong: %#v" , s . Spec . RollbackConfig )
}
if s . Spec . EndpointSpec == nil ||
s . Spec . EndpointSpec . Mode != swarm . ResolutionModeVIP ||
len ( s . Spec . EndpointSpec . Ports ) != 1 ||
s . Spec . EndpointSpec . Ports [ 0 ] . Name != "random" ||
s . Spec . EndpointSpec . Ports [ 0 ] . Protocol != swarm . PortConfigProtocolTCP ||
s . Spec . EndpointSpec . Ports [ 0 ] . TargetPort != uint32 ( 8080 ) ||
s . Spec . EndpointSpec . Ports [ 0 ] . PublishedPort != uint32 ( 8080 ) ||
s . Spec . EndpointSpec . Ports [ 0 ] . PublishMode != swarm . PortConfigPublishModeIngress {
return fmt . Errorf ( "Service s.Spec.EndpointSpec is wrong: %#v" , s . Spec . EndpointSpec )
}
if s . Endpoint . Spec . Mode != swarm . ResolutionModeVIP ||
len ( s . Endpoint . Spec . Ports ) != 1 ||
s . Endpoint . Spec . Ports [ 0 ] . Name != "random" ||
s . Endpoint . Spec . Ports [ 0 ] . Protocol != swarm . PortConfigProtocolTCP ||
s . Endpoint . Spec . Ports [ 0 ] . TargetPort != uint32 ( 8080 ) ||
s . Endpoint . Spec . Ports [ 0 ] . PublishedPort != uint32 ( 8080 ) ||
s . Endpoint . Spec . Ports [ 0 ] . PublishMode != swarm . PortConfigPublishModeIngress ||
len ( s . Endpoint . Ports ) != 1 ||
s . Endpoint . Ports [ 0 ] . Name != "random" ||
s . Endpoint . Ports [ 0 ] . Protocol != swarm . PortConfigProtocolTCP ||
s . Endpoint . Ports [ 0 ] . TargetPort != uint32 ( 8080 ) ||
s . Endpoint . Ports [ 0 ] . PublishedPort != uint32 ( 8080 ) ||
s . Endpoint . Ports [ 0 ] . PublishMode != swarm . PortConfigPublishModeIngress ||
len ( s . Endpoint . VirtualIPs ) != 2 {
return fmt . Errorf ( "Service s.Endpoint is wrong: %#v" , s . Endpoint )
}
return nil
}
ctx := context . Background ( )
resource . Test ( t , resource . TestCase {
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
Steps : [ ] resource . TestStep {
{
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceFullSpec" ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic" ) ,
2019-11-14 08:06:50 -05:00
testCheckLabelMap ( "docker_service.foo" , "labels" , map [ string ] string { "servicelabel" : "true" } ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2019-11-14 08:06:50 -05:00
testCheckLabelMap ( "docker_service.foo" , "task_spec.0.container_spec.0.labels" , map [ string ] string { "foo" : "bar" } ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.command.0" , "ls" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.args.0" , "-las" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hostname" , "my-fancy-service" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.env.MYFOO" , "BAR" ) ,
2019-10-06 06:11:11 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.env.URI" , "/api-call?param1=value1" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dir" , "/root" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.user" , "root" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.groups.0" , "docker" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.groups.1" , "foogroup" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.0.se_linux_context.0.disable" , "true" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.0.se_linux_context.0.user" , "user-label" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.0.se_linux_context.0.role" , "role-label" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.0.se_linux_context.0.type" , "type-label" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.0.se_linux_context.0.level" , "level-label" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.read_only" , "true" ) ,
2021-03-18 03:30:54 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.target" , "/mount/test" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.source" , "tftest-volume" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.type" , "volume" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.read_only" , "true" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.volume_options.0.no_copy" , "true" ) ,
testCheckLabelMap ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.volume_options.0.labels" , map [ string ] string { "foo" : "bar" } ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.volume_options.0.driver_name" , "random-driver" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.0.volume_options.0.driver_options.op1" , "val1" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.stop_signal" , "SIGTERM" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.stop_grace_period" , "10s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.0" , "CMD" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.1" , "curl" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.2" , "-f" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.3" , "localhost:8080/health" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.interval" , "5s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.timeout" , "2s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.retries" , "4" ) ,
2021-03-18 03:30:54 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.host" , "testhost" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.ip" , "10.0.1.0" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dns_config.0.nameservers.0" , "8.8.8.8" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dns_config.0.search.0" , "example.org" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dns_config.0.options.0" , "timeout:3" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.configs.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.secrets.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.resources.0.limits.0.nano_cpus" , "1000000" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.resources.0.limits.0.memory_bytes" , "536870912" ) ,
2021-03-18 03:30:54 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.restart_policy.0.condition" , "on-failure" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.restart_policy.0.delay" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.restart_policy.0.max_attempts" , "4" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.restart_policy.0.window" , "10s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.placement.0.constraints.0" , "node.role==manager" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.placement.0.prefs.0" , "spread=node.role.manager" ) ,
2021-01-03 06:37:31 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.placement.0.max_replicas" , "2" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.force_update" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.networks.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.name" , "json-file" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-file" , "3" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-size" , "10m" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.parallelism" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.delay" , "10s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.failure_action" , "pause" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.max_failure_ratio" , "0.1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.monitor" , "5s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.order" , "start-first" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "rollback_config.0.parallelism" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "rollback_config.0.delay" , "5ms" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "rollback_config.0.failure_action" , "pause" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "rollback_config.0.monitor" , "10h" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "rollback_config.0.max_failure_ratio" , "0.9" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "rollback_config.0.order" , "stop-first" ) ,
2018-05-18 06:14:02 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.mode" , "vip" ) ,
2019-12-27 10:48:21 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.name" , "random" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.protocol" , "tcp" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.target_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.published_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.publish_mode" , "ingress" ) ,
2021-05-31 03:11:49 -04:00
testAccServiceRunning ( "docker_service.foo" , & s ) ,
testCheckServiceInspect ,
2018-05-16 12:00:04 -04:00
) ,
} ,
2019-11-23 08:42:05 -05:00
{
ResourceName : "docker_service.foo" ,
ImportState : true ,
ImportStateVerify : true ,
} ,
2018-05-16 12:00:04 -04:00
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2019-05-26 05:42:53 -04:00
func TestAccDockerService_partialReplicationConfig ( t * testing . T ) {
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2018-05-16 12:00:04 -04:00
resource . Test ( t , resource . TestCase {
2021-03-18 03:30:54 -04:00
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
2018-05-16 12:00:04 -04:00
Steps : [ ] resource . TestStep {
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServicePartialReplicationConfig" ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "1" ) ,
) ,
} ,
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServicePartialReplicationConfigStep2" ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "1" ) ,
) ,
} ,
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServicePartialReplicationConfigStep3" ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "2" ) ,
) ,
} ,
2019-11-23 08:42:05 -05:00
{
ResourceName : "docker_service.foo" ,
ImportState : true ,
ImportStateVerify : true ,
} ,
2018-05-16 12:00:04 -04:00
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2019-05-26 05:42:53 -04:00
func TestAccDockerService_globalReplicationMode ( t * testing . T ) {
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2018-05-16 12:00:04 -04:00
resource . Test ( t , resource . TestCase {
2021-03-18 03:30:54 -04:00
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
2018-05-16 12:00:04 -04:00
Steps : [ ] resource . TestStep {
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceGlobalReplicationMode" ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.global" , "true" ) ,
) ,
} ,
2019-11-23 08:42:05 -05:00
{
ResourceName : "docker_service.foo" ,
ImportState : true ,
ImportStateVerify : true ,
} ,
2018-05-16 12:00:04 -04:00
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2019-05-26 05:42:53 -04:00
func TestAccDockerService_ConflictingGlobalAndReplicated ( t * testing . T ) {
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2018-05-16 12:00:04 -04:00
resource . Test ( t , resource . TestCase {
2021-03-18 03:30:54 -04:00
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
2018-05-16 12:00:04 -04:00
Steps : [ ] resource . TestStep {
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceConflictingGlobalAndReplicated" ) ,
2018-05-16 12:00:04 -04:00
ExpectError : regexp . MustCompile ( ` .*conflicts with.* ` ) ,
} ,
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2018-07-03 11:30:53 -04:00
2019-05-26 05:42:53 -04:00
func TestAccDockerService_ConflictingGlobalModeAndConverge ( t * testing . T ) {
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2018-05-16 12:00:04 -04:00
resource . Test ( t , resource . TestCase {
2021-03-18 03:30:54 -04:00
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
2018-05-16 12:00:04 -04:00
Steps : [ ] resource . TestStep {
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceConflictingGlobalModeAndConverge" ) ,
2018-05-16 12:00:04 -04:00
ExpectError : regexp . MustCompile ( ` .*conflicts with.* ` ) ,
} ,
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2019-05-26 05:42:53 -04:00
// Converging tests
func TestAccDockerService_privateImageConverge ( t * testing . T ) {
registry := "127.0.0.1:15000"
2019-05-31 09:08:32 -04:00
image := "127.0.0.1:15000/tftest-service:v1"
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2019-05-26 05:42:53 -04:00
2018-05-16 12:00:04 -04:00
resource . Test ( t , resource . TestCase {
2021-03-18 03:30:54 -04:00
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
2018-05-16 12:00:04 -04:00
Steps : [ ] resource . TestStep {
2019-03-01 16:02:17 -05:00
{
2021-05-31 03:11:49 -04:00
Config : fmt . Sprintf ( loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServicePrivateImageConverge" ) , registry , image ) ,
2019-05-26 05:42:53 -04:00
Check : resource . ComposeTestCheckFunc (
2019-11-23 08:42:05 -05:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-foo" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2019-05-26 05:42:53 -04:00
) ,
} ,
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2019-05-26 05:42:53 -04:00
} )
}
2021-05-31 03:11:49 -04:00
func TestAccDockerService_nonExistingPrivateImageConverge ( t * testing . T ) {
resource . Test ( t , resource . TestCase {
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
Steps : [ ] resource . TestStep {
{
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceNonExistingPrivateImageConverge" ) ,
ExpectError : regexp . MustCompile ( ` .*did not converge after.* ` ) ,
Check : resource . ComposeTestCheckFunc (
isServiceRemoved ( "tftest-service-privateimagedoesnotexist" ) ,
) ,
} ,
} ,
} )
}
func TestAccDockerService_nonExistingPublicImageConverge ( t * testing . T ) {
resource . Test ( t , resource . TestCase {
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
Steps : [ ] resource . TestStep {
{
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServicenonExistingPublicImageConverge" ) ,
ExpectError : regexp . MustCompile ( ` .*did not converge after.* ` ) ,
Check : resource . ComposeTestCheckFunc (
isServiceRemoved ( "tftest-service-publicimagedoesnotexist" ) ,
) ,
} ,
} ,
} )
}
func TestAccDockerService_convergeAndStopGracefully ( t * testing . T ) {
ctx := context . Background ( )
resource . Test ( t , resource . TestCase {
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
Steps : [ ] resource . TestStep {
{
Config : loadTestConfiguration ( t , RESOURCE , "docker_service" , "testAccDockerServiceConvergeAndStopGracefully" ) ,
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-basic-converge" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2021-05-31 03:11:49 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "2" ) ,
testValueHigherEqualThan ( "docker_service.foo" , "endpoint_spec.0.ports.0.target_port" , 8080 ) ,
testValueHigherEqualThan ( "docker_service.foo" , "endpoint_spec.0.ports.0.published_port" , 30000 ) ,
) ,
} ,
} ,
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
} )
}
func TestAccDockerService_updateFailsAndRollbackConverge ( t * testing . T ) {
image := "127.0.0.1:15000/tftest-service:v1"
imageFail := "127.0.0.1:15000/tftest-service:v3"
ctx := context . Background ( )
resource . Test ( t , resource . TestCase {
PreCheck : func ( ) { testAccPreCheck ( t ) } ,
ProviderFactories : providerFactories ,
Steps : [ ] resource . TestStep {
{
Config : fmt . Sprintf ( loadTestConfiguration ( t , RESOURCE , "docker_service" , "updateFailsAndRollbackConvergeConfig" ) , image ) ,
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-updateFailsAndRollbackConverge" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2021-05-31 03:11:49 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "2" ) ,
) ,
} ,
{
Config : fmt . Sprintf ( loadTestConfiguration ( t , RESOURCE , "docker_service" , "updateFailsAndRollbackConvergeConfig" ) , imageFail ) ,
ExpectError : regexp . MustCompile ( ` .*rollback completed.* ` ) ,
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-service-updateFailsAndRollbackConverge" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2021-05-31 03:11:49 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , "2" ) ,
) ,
} ,
} ,
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
} )
}
2019-05-26 05:42:53 -04:00
func TestAccDockerService_updateMultiplePropertiesConverge ( t * testing . T ) {
// Step 1
configData := "ewogICJwcmVmaXgiOiAiMTIzIgp9"
secretData := "ewogICJrZXkiOiAiUVdFUlRZIgp9"
image := "127.0.0.1:15000/tftest-service:v1"
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2019-05-26 05:42:53 -04:00
mounts := `
2019-06-10 18:24:55 -04:00
mounts {
2021-01-19 10:20:29 -05:00
source = docker_volume . foo . name
2019-06-10 18:24:55 -04:00
target = "/mount/test"
type = "volume"
read_only = true
volume_options {
2019-11-14 08:06:50 -05:00
labels {
label = "env"
value = "dev"
}
labels {
label = "terraform"
value = "true"
2019-05-26 05:42:53 -04:00
}
}
2019-06-10 18:24:55 -04:00
}
2019-05-26 05:42:53 -04:00
`
hosts := `
2019-06-10 18:24:55 -04:00
hosts {
host = "testhost"
ip = "10.0.1.0"
}
2019-05-26 05:42:53 -04:00
`
logging := `
name = "json-file"
2019-06-10 18:24:55 -04:00
options = {
2019-05-26 05:42:53 -04:00
max - size = "10m"
max - file = "3"
}
`
healthcheckInterval := "1s"
healthcheckTimeout := "500ms"
replicas := 2
portsSpec := `
2019-06-10 18:24:55 -04:00
ports {
target_port = "8080"
published_port = "8081"
}
2019-05-26 05:42:53 -04:00
`
// Step 2
configData2 := "ewogICJwcmVmaXgiOiAiNTY3Igp9" // UPDATED to prefix: 567
secretData2 := "ewogICJrZXkiOiAiUVdFUlRZIgp9" // UPDATED to YXCVB
image2 := "127.0.0.1:15000/tftest-service:v2"
healthcheckInterval2 := "2s"
mounts2 := `
2019-06-10 18:24:55 -04:00
mounts {
2021-01-19 10:20:29 -05:00
source = docker_volume . foo . name
2019-06-10 18:24:55 -04:00
target = "/mount/test"
type = "volume"
read_only = true
volume_options {
2019-11-14 08:06:50 -05:00
labels {
label = "env"
value = "dev"
}
labels {
label = "terraform"
value = "true"
2019-05-26 05:42:53 -04:00
}
2019-06-10 18:24:55 -04:00
}
}
mounts {
2021-01-19 10:20:29 -05:00
source = docker_volume . foo2 . name
2019-06-10 18:24:55 -04:00
target = "/mount/test2"
type = "volume"
read_only = true
volume_options {
2019-11-14 08:06:50 -05:00
labels {
label = "env"
value = "dev"
}
labels {
label = "terraform"
value = "true"
2019-05-26 05:42:53 -04:00
}
}
2019-06-10 18:24:55 -04:00
}
2019-05-26 05:42:53 -04:00
`
hosts2 := `
2019-06-10 18:24:55 -04:00
hosts {
host = "testhost2"
ip = "10.0.2.2"
}
2019-05-26 05:42:53 -04:00
`
logging2 := `
name = "json-file"
2019-06-10 18:24:55 -04:00
options = {
2019-05-26 05:42:53 -04:00
max - size = "15m"
max - file = "5"
}
`
healthcheckTimeout2 := "800ms"
replicas2 := 6
portsSpec2 := `
2019-06-10 18:24:55 -04:00
ports {
target_port = "8080"
published_port = "8081"
}
ports {
target_port = "8080"
published_port = "8082"
}
2019-05-26 05:42:53 -04:00
`
// Step 3
configData3 := configData2
secretData3 := secretData2
image3 := image2
mounts3 := mounts2
hosts3 := hosts2
logging3 := logging2
healthcheckInterval3 := healthcheckInterval2
healthcheckTimeout3 := healthcheckTimeout2
replicas3 := 3 // only decrease
portsSpec3 := portsSpec2
2019-06-10 18:24:55 -04:00
2019-05-26 05:42:53 -04:00
resource . Test ( t , resource . TestCase {
2021-06-21 03:24:02 -04:00
PreCheck : func ( ) {
testAccPreCheck ( t )
// Note mavogel: we download all images upfront and use a data_source then
// becausee the test is only flaky in CI. See
// https://github.com/kreuzwerker/terraform-provider-docker/runs/2732063570
pullImageForTest ( t , image )
pullImageForTest ( t , image2 )
pullImageForTest ( t , image3 )
} ,
2021-03-18 03:30:54 -04:00
ProviderFactories : providerFactories ,
2019-05-26 05:42:53 -04:00
Steps : [ ] resource . TestStep {
{
Config : fmt . Sprintf ( updateMultiplePropertiesConfigConverge , configData , secretData , image , mounts , hosts , healthcheckInterval , healthcheckTimeout , logging , replicas , portsSpec ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-fnf-service-up-crihiadr" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , strconv . Itoa ( replicas ) ) ,
2019-05-31 09:08:32 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.parallelism" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.delay" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.failure_action" , "continue" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.monitor" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.max_failure_ratio" , "0.5" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.order" , "start-first" ) ,
2018-05-18 06:14:02 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.#" , "1" ) ,
2019-12-27 10:48:21 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.target_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.published_port" , "8081" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.configs.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.secrets.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dir" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dns_config.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.env.%" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.groups.#" , "0" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.0" , "CMD" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.1" , "curl" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.2" , "-f" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.3" , "localhost:8080/health" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.interval" , healthcheckInterval ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.timeout" , healthcheckTimeout ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.retries" , "2" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hostname" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.#" , "1" ) ,
2021-05-31 03:11:49 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.host" , "testhost" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.ip" , "10.0.1.0" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.isolation" , "default" ) ,
2019-11-14 08:06:50 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.labels.#" , "0" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.#" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.stop_grace_period" , "10s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.user" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.name" , "json-file" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.%" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-file" , "3" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-size" , "10m" ) ,
2018-05-16 12:00:04 -04:00
) ,
} ,
2019-03-01 16:02:17 -05:00
{
2019-05-26 05:42:53 -04:00
Config : fmt . Sprintf ( updateMultiplePropertiesConfigConverge , configData2 , secretData2 , image2 , mounts2 , hosts2 , healthcheckInterval2 , healthcheckTimeout2 , logging2 , replicas2 , portsSpec2 ) ,
2018-05-16 12:00:04 -04:00
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-fnf-service-up-crihiadr" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , strconv . Itoa ( replicas2 ) ) ,
2019-05-31 09:08:32 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.parallelism" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.delay" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.failure_action" , "continue" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.monitor" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.max_failure_ratio" , "0.5" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.order" , "start-first" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.#" , "2" ) ,
2019-12-27 10:48:21 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.target_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.published_port" , "8081" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.1.target_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.1.published_port" , "8082" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.configs.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.secrets.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dir" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dns_config.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.env.%" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.groups.#" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.0" , "CMD" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.1" , "curl" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.2" , "-f" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.3" , "localhost:8080/health" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.interval" , healthcheckInterval2 ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.timeout" , healthcheckTimeout2 ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.retries" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hostname" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.#" , "1" ) ,
2021-05-31 03:11:49 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.host" , "testhost2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.ip" , "10.0.2.2" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.isolation" , "default" ) ,
2019-11-14 08:06:50 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.labels.#" , "0" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.#" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.#" , "0" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.stop_grace_period" , "10s" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.user" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.name" , "json-file" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.%" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-file" , "5" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-size" , "15m" ) ,
) ,
} ,
{
Config : fmt . Sprintf ( updateMultiplePropertiesConfigConverge , configData3 , secretData3 , image3 , mounts3 , hosts3 , healthcheckInterval3 , healthcheckTimeout3 , logging3 , replicas3 , portsSpec3 ) ,
Check : resource . ComposeTestCheckFunc (
resource . TestMatchResourceAttr ( "docker_service.foo" , "id" , serviceIDRegex ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "name" , "tftest-fnf-service-up-crihiadr" ) ,
2021-06-21 03:24:02 -04:00
resource . TestMatchResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.image" , regexp . MustCompile ( ` sha256.* ` ) ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "mode.0.replicated.0.replicas" , strconv . Itoa ( replicas3 ) ) ,
2019-05-31 09:08:32 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.parallelism" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.delay" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.failure_action" , "continue" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.monitor" , "3s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.max_failure_ratio" , "0.5" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "update_config.0.order" , "start-first" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.#" , "2" ) ,
2019-12-27 10:48:21 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.target_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.0.published_port" , "8081" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.1.target_port" , "8080" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "endpoint_spec.0.ports.1.published_port" , "8082" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.configs.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.secrets.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dir" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.dns_config.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.env.%" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.groups.#" , "0" ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.0" , "CMD" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.1" , "curl" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.2" , "-f" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.test.3" , "localhost:8080/health" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.interval" , healthcheckInterval3 ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.timeout" , healthcheckTimeout3 ) ,
2018-05-16 12:00:04 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.healthcheck.0.retries" , "2" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hostname" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.#" , "1" ) ,
2021-05-31 03:11:49 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.host" , "testhost2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.hosts.0.ip" , "10.0.2.2" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.isolation" , "default" ) ,
2019-11-14 08:06:50 -05:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.labels.#" , "0" ) ,
2019-05-26 05:42:53 -04:00
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.mounts.#" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.privileges.#" , "0" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.stop_grace_period" , "10s" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.container_spec.0.user" , "" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.#" , "1" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.name" , "json-file" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.%" , "2" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-file" , "5" ) ,
resource . TestCheckResourceAttr ( "docker_service.foo" , "task_spec.0.log_driver.0.options.max-size" , "15m" ) ,
2018-05-16 12:00:04 -04:00
) ,
} ,
} ,
2021-03-18 03:30:54 -04:00
CheckDestroy : func ( state * terraform . State ) error {
return checkAndRemoveImages ( ctx , state )
} ,
2018-05-16 12:00:04 -04:00
} )
}
2019-05-26 05:42:53 -04:00
const updateMultiplePropertiesConfigConverge = `
2021-05-31 03:11:49 -04:00
provider "docker" {
2019-05-26 05:42:53 -04:00
alias = "private"
2021-06-21 03:24:02 -04:00
registry_auth {
address = "127.0.0.1:15000"
}
2021-05-31 03:11:49 -04:00
}
resource "docker_volume" "foo" {
2019-05-26 05:42:53 -04:00
name = "tftest-volume"
2021-05-31 03:11:49 -04:00
}
resource "docker_volume" "foo2" {
2019-05-26 05:42:53 -04:00
name = "tftest-volume2"
2021-05-31 03:11:49 -04:00
}
resource "docker_config" "service_config" {
name = "tftest-myconfig-${uuid()}"
data = "%s"
2019-05-26 05:42:53 -04:00
lifecycle {
2021-05-31 03:11:49 -04:00
ignore_changes = [ "name" ]
create_before_destroy = true
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
}
resource "docker_secret" "service_secret" {
name = "tftest-tftest-mysecret-${replace(timestamp(), " : ", " . ")}"
data = "%s"
2019-05-26 05:42:53 -04:00
lifecycle {
2021-05-31 03:11:49 -04:00
ignore_changes = [ "name" ]
create_before_destroy = true
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
}
2021-06-21 03:24:02 -04:00
data "docker_image" "tftest_image" {
name = "%s"
}
2021-05-31 03:11:49 -04:00
resource "docker_service" "foo" {
2019-05-26 05:42:53 -04:00
provider = "docker.private"
name = "tftest-fnf-service-up-crihiadr"
2021-06-21 03:24:02 -04:00
2021-05-31 03:11:49 -04:00
auth {
2021-06-21 03:24:02 -04:00
server_address = "127.0.0.1:15000"
username = "testuser"
password = "testpwd"
2021-05-31 03:11:49 -04:00
}
2019-05-26 05:42:53 -04:00
task_spec {
2021-05-31 03:11:49 -04:00
container_spec {
2021-06-21 03:24:02 -04:00
image = data . docker_image . tftest_image . repo_digest
2021-05-31 03:11:49 -04:00
% s
% s
configs {
config_id = docker_config . service_config . id
config_name = docker_config . service_config . name
file_name = "/configs.json"
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
secrets {
secret_id = docker_secret . service_secret . id
secret_name = docker_secret . service_secret . name
file_name = "/secrets.json"
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
healthcheck {
test = [ "CMD" , "curl" , "-f" , "localhost:8080/health" ]
interval = "%s"
timeout = "%s"
start_period = "1s"
retries = 2
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
stop_grace_period = "10s"
}
log_driver {
2019-06-10 18:24:55 -04:00
% s
2021-05-31 03:11:49 -04:00
}
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
2019-05-26 05:42:53 -04:00
mode {
2021-05-31 03:11:49 -04:00
replicated {
replicas = % d
}
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
2019-05-26 05:42:53 -04:00
update_config {
2021-05-31 03:11:49 -04:00
parallelism = 2
delay = "3s"
failure_action = "continue"
monitor = "3s"
max_failure_ratio = "0.5"
order = "start-first"
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
2019-05-26 05:42:53 -04:00
endpoint_spec {
2021-05-31 03:11:49 -04:00
% s
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
2019-05-26 05:42:53 -04:00
converge_config {
2021-05-31 03:11:49 -04:00
delay = "7s"
timeout = "2m"
2019-05-26 05:42:53 -04:00
}
2021-05-31 03:11:49 -04:00
}
2019-05-26 05:42:53 -04:00
`
2018-05-16 12:00:04 -04:00
// Helpers
2019-05-26 05:42:53 -04:00
// isServiceRemoved checks if a service was removed successfully
2018-05-16 12:00:04 -04:00
func isServiceRemoved ( serviceName string ) resource . TestCheckFunc {
return func ( s * terraform . State ) error {
2021-03-18 03:30:54 -04:00
ctx := context . Background ( )
2018-05-16 12:00:04 -04:00
client := testAccProvider . Meta ( ) . ( * ProviderConfig ) . DockerClient
2018-07-03 11:30:53 -04:00
filters := filters . NewArgs ( )
filters . Add ( "name" , serviceName )
2021-03-18 03:30:54 -04:00
services , err := client . ServiceList ( ctx , types . ServiceListOptions {
2018-07-03 11:30:53 -04:00
Filters : filters ,
2018-05-16 12:00:04 -04:00
} )
if err != nil {
return fmt . Errorf ( "Error listing service for name %s: %v" , serviceName , err )
}
length := len ( services )
if length != 0 {
return fmt . Errorf ( "Service should be removed but is running: %s" , serviceName )
}
return nil
}
}
2019-05-26 05:42:53 -04:00
// checkAndRemoveImages checks and removes all private images with
// the given pattern. This ensures that the image are not kept on the swarm nodes
// and the tests are independent of each other
2021-03-18 03:30:54 -04:00
func checkAndRemoveImages ( ctx context . Context , s * terraform . State ) error {
2019-05-26 05:42:53 -04:00
retrySleepSeconds := 3
maxRetryDeleteCount := 6
imagePattern := "127.0.0.1:15000/tftest-service*"
client := testAccProvider . Meta ( ) . ( * ProviderConfig ) . DockerClient
filters := filters . NewArgs ( )
filters . Add ( "reference" , imagePattern )
2021-03-18 03:30:54 -04:00
images , err := client . ImageList ( ctx , types . ImageListOptions {
2019-05-26 05:42:53 -04:00
Filters : filters ,
} )
if err != nil {
return err
}
retryDeleteCount := 0
for i := 0 ; i < len ( images ) ; {
image := images [ i ]
2021-03-18 03:30:54 -04:00
_ , err := client . ImageRemove ( ctx , image . ID , types . ImageRemoveOptions {
2019-05-26 05:42:53 -04:00
Force : true ,
} )
if err != nil {
if strings . Contains ( err . Error ( ) , "image is being used by running container" ) {
if retryDeleteCount == maxRetryDeleteCount {
return fmt . Errorf ( "could not delete image '%s' after %d retries" , image . ID , maxRetryDeleteCount )
}
<- time . After ( time . Duration ( retrySleepSeconds ) * time . Second )
retryDeleteCount ++
continue
}
return err
}
i ++
}
2021-03-18 03:30:54 -04:00
imagesAfterDelete , err := client . ImageList ( ctx , types . ImageListOptions {
2019-05-26 05:42:53 -04:00
Filters : filters ,
} )
if err != nil {
return err
}
if len ( imagesAfterDelete ) != 0 {
2021-05-11 04:00:02 -04:00
return fmt . Errorf ( "Expected images of pattern '%s' to be deleted, but there is/are still %d" , imagePattern , len ( imagesAfterDelete ) )
2019-05-26 05:42:53 -04:00
}
return nil
}
2021-05-31 03:11:49 -04:00
func testAccServiceRunning ( resourceName string , service * swarm . Service ) resource . TestCheckFunc {
return func ( s * terraform . State ) error {
ctx := context . Background ( )
rs , ok := s . RootModule ( ) . Resources [ resourceName ]
if ! ok {
return fmt . Errorf ( "Resource with name '%s' not found in state" , resourceName )
}
if rs . Primary . ID == "" {
return fmt . Errorf ( "No ID is set" )
}
client := testAccProvider . Meta ( ) . ( * ProviderConfig ) . DockerClient
inspectedService , _ , err := client . ServiceInspectWithRaw ( ctx , rs . Primary . ID , types . ServiceInspectOptions { } )
if err != nil {
return fmt . Errorf ( "Service with ID '%s': %w" , rs . Primary . ID , err )
}
// we set the value to the pointer to be able to use the value
// outside of the function
* service = inspectedService
return nil
}
}