mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-23 08:09:37 -05:00
Closes #222 * fix(service): changes ports from set to list. adapts tests. marks published port computed. uses endpoint spec from api to flatten.
557 lines
15 KiB
Go
557 lines
15 KiB
Go
package docker
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/mount"
|
|
"github.com/docker/docker/api/types/swarm"
|
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
|
)
|
|
|
|
func flattenTaskSpec(in swarm.TaskSpec) []interface{} {
|
|
m := make(map[string]interface{})
|
|
if in.ContainerSpec != nil {
|
|
m["container_spec"] = flattenContainerSpec(in.ContainerSpec)
|
|
}
|
|
if in.Resources != nil {
|
|
m["resources"] = flattenTaskResources(in.Resources)
|
|
}
|
|
if in.RestartPolicy != nil {
|
|
m["restart_policy"] = flattenTaskRestartPolicy(in.RestartPolicy)
|
|
}
|
|
if in.Placement != nil {
|
|
m["placement"] = flattenTaskPlacement(in.Placement)
|
|
}
|
|
if in.ForceUpdate >= 0 {
|
|
m["force_update"] = in.ForceUpdate
|
|
}
|
|
if len(in.Runtime) > 0 {
|
|
m["runtime"] = in.Runtime
|
|
}
|
|
if len(in.Networks) > 0 {
|
|
m["networks"] = flattenTaskNetworks(in.Networks)
|
|
}
|
|
if in.LogDriver != nil {
|
|
m["log_driver"] = flattenTaskLogDriver(in.LogDriver)
|
|
}
|
|
|
|
return []interface{}{m}
|
|
}
|
|
|
|
func flattenServiceMode(in swarm.ServiceMode) []interface{} {
|
|
m := make(map[string]interface{})
|
|
if in.Replicated != nil {
|
|
m["replicated"] = flattenReplicated(in.Replicated)
|
|
}
|
|
if in.Global != nil {
|
|
m["global"] = true
|
|
} else {
|
|
m["global"] = false
|
|
}
|
|
|
|
return []interface{}{m}
|
|
}
|
|
|
|
func flattenReplicated(in *swarm.ReplicatedService) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
m := make(map[string]interface{})
|
|
if in != nil {
|
|
if in.Replicas != nil {
|
|
replicas := int(*in.Replicas)
|
|
m["replicas"] = replicas
|
|
}
|
|
}
|
|
out = append(out, m)
|
|
return out
|
|
}
|
|
|
|
func flattenServiceUpdateOrRollbackConfig(in *swarm.UpdateConfig) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
if in == nil {
|
|
return out
|
|
}
|
|
|
|
m := make(map[string]interface{})
|
|
m["parallelism"] = in.Parallelism
|
|
m["delay"] = shortDur(in.Delay)
|
|
m["failure_action"] = in.FailureAction
|
|
m["monitor"] = shortDur(in.Monitor)
|
|
m["max_failure_ratio"] = strconv.FormatFloat(float64(in.MaxFailureRatio), 'f', 1, 64)
|
|
m["order"] = in.Order
|
|
out = append(out, m)
|
|
return out
|
|
}
|
|
|
|
func flattenServiceEndpointSpec(in swarm.Endpoint) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
m := make(map[string]interface{})
|
|
m["mode"] = string(in.Spec.Mode)
|
|
m["ports"] = flattenServicePorts(in.Ports)
|
|
|
|
out = append(out, m)
|
|
return out
|
|
}
|
|
|
|
///// start TaskSpec
|
|
func flattenContainerSpec(in *swarm.ContainerSpec) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
m := make(map[string]interface{})
|
|
if len(in.Image) > 0 {
|
|
m["image"] = in.Image
|
|
}
|
|
if len(in.Labels) > 0 {
|
|
m["labels"] = mapToLabelSet(in.Labels)
|
|
}
|
|
if len(in.Command) > 0 {
|
|
m["command"] = in.Command
|
|
}
|
|
if len(in.Args) > 0 {
|
|
m["args"] = in.Args
|
|
}
|
|
if len(in.Hostname) > 0 {
|
|
m["hostname"] = in.Hostname
|
|
}
|
|
if len(in.Env) > 0 {
|
|
m["env"] = mapStringSliceToMap(in.Env)
|
|
}
|
|
if len(in.User) > 0 {
|
|
m["user"] = in.User
|
|
}
|
|
if len(in.Dir) > 0 {
|
|
m["dir"] = in.Dir
|
|
}
|
|
if len(in.Groups) > 0 {
|
|
m["groups"] = in.Groups
|
|
}
|
|
if in.Privileges != nil {
|
|
m["privileges"] = flattenPrivileges(in.Privileges)
|
|
}
|
|
if in.ReadOnly {
|
|
m["read_only"] = in.ReadOnly
|
|
}
|
|
if len(in.Mounts) > 0 {
|
|
m["mounts"] = flattenServiceMounts(in.Mounts)
|
|
}
|
|
if len(in.StopSignal) > 0 {
|
|
m["stop_signal"] = in.StopSignal
|
|
}
|
|
if in.StopGracePeriod != nil {
|
|
m["stop_grace_period"] = shortDur(*in.StopGracePeriod)
|
|
}
|
|
if in.Healthcheck != nil {
|
|
m["healthcheck"] = flattenServiceHealthcheck(in.Healthcheck)
|
|
}
|
|
if len(in.Hosts) > 0 {
|
|
m["hosts"] = flattenServiceHosts(in.Hosts)
|
|
}
|
|
if in.DNSConfig != nil {
|
|
m["dns_config"] = flattenServiceDNSConfig(in.DNSConfig)
|
|
}
|
|
if len(in.Secrets) > 0 {
|
|
m["secrets"] = flattenServiceSecrets(in.Secrets)
|
|
}
|
|
if len(in.Configs) > 0 {
|
|
m["configs"] = flattenServiceConfigs(in.Configs)
|
|
}
|
|
if len(in.Isolation) > 0 {
|
|
m["isolation"] = string(in.Isolation)
|
|
}
|
|
out = append(out, m)
|
|
return out
|
|
}
|
|
|
|
func flattenPrivileges(in *swarm.Privileges) []interface{} {
|
|
if in == nil {
|
|
return make([]interface{}, 0, 0)
|
|
}
|
|
|
|
var out = make([]interface{}, 1, 1)
|
|
m := make(map[string]interface{})
|
|
|
|
if in.CredentialSpec != nil {
|
|
credSpec := make([]interface{}, 1, 1)
|
|
internal := make(map[string]interface{})
|
|
internal["file"] = in.CredentialSpec.File
|
|
internal["registry"] = in.CredentialSpec.Registry
|
|
credSpec[0] = internal
|
|
m["credential_spec"] = credSpec
|
|
}
|
|
if in.SELinuxContext != nil {
|
|
seLinuxContext := make([]interface{}, 1, 1)
|
|
internal := make(map[string]interface{})
|
|
internal["disable"] = in.SELinuxContext.Disable
|
|
internal["user"] = in.SELinuxContext.User
|
|
internal["role"] = in.SELinuxContext.Role
|
|
internal["type"] = in.SELinuxContext.Type
|
|
internal["level"] = in.SELinuxContext.Level
|
|
seLinuxContext[0] = internal
|
|
m["se_linux_context"] = seLinuxContext
|
|
}
|
|
out[0] = m
|
|
return out
|
|
}
|
|
|
|
func flattenServiceMounts(in []mount.Mount) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
m := make(map[string]interface{})
|
|
m["target"] = v.Target
|
|
m["source"] = v.Source
|
|
m["type"] = string(v.Type)
|
|
m["read_only"] = v.ReadOnly
|
|
if v.BindOptions != nil {
|
|
bindOptions := make([]interface{}, 0, 0)
|
|
bindOptionsItem := make(map[string]interface{}, 0)
|
|
|
|
if len(v.BindOptions.Propagation) > 0 {
|
|
bindOptionsItem["propagation"] = string(v.BindOptions.Propagation)
|
|
}
|
|
|
|
bindOptions = append(bindOptions, bindOptionsItem)
|
|
m["bind_options"] = bindOptions
|
|
}
|
|
|
|
if v.VolumeOptions != nil {
|
|
volumeOptions := make([]interface{}, 0, 0)
|
|
volumeOptionsItem := make(map[string]interface{}, 0)
|
|
|
|
volumeOptionsItem["no_copy"] = v.VolumeOptions.NoCopy
|
|
volumeOptionsItem["labels"] = mapToLabelSet(v.VolumeOptions.Labels)
|
|
if v.VolumeOptions.DriverConfig != nil {
|
|
if len(v.VolumeOptions.DriverConfig.Name) > 0 {
|
|
volumeOptionsItem["driver_name"] = v.VolumeOptions.DriverConfig.Name
|
|
}
|
|
volumeOptionsItem["driver_options"] = mapStringStringToMapStringInterface(v.VolumeOptions.DriverConfig.Options)
|
|
}
|
|
|
|
volumeOptions = append(volumeOptions, volumeOptionsItem)
|
|
m["volume_options"] = volumeOptions
|
|
}
|
|
|
|
if v.TmpfsOptions != nil {
|
|
tmpfsOptions := make([]interface{}, 0, 0)
|
|
tmpfsOptionsItem := make(map[string]interface{}, 0)
|
|
|
|
tmpfsOptionsItem["size_bytes"] = int(v.TmpfsOptions.SizeBytes)
|
|
tmpfsOptionsItem["mode"] = v.TmpfsOptions.Mode.Perm
|
|
|
|
tmpfsOptions = append(tmpfsOptions, tmpfsOptionsItem)
|
|
m["tmpfs_options"] = tmpfsOptions
|
|
}
|
|
|
|
out[i] = m
|
|
}
|
|
taskSpecResource := resourceDockerService().Schema["task_spec"].Elem.(*schema.Resource)
|
|
containerSpecResource := taskSpecResource.Schema["container_spec"].Elem.(*schema.Resource)
|
|
mountsResource := containerSpecResource.Schema["mounts"].Elem.(*schema.Resource)
|
|
f := schema.HashResource(mountsResource)
|
|
return schema.NewSet(f, out)
|
|
}
|
|
|
|
func flattenServiceHealthcheck(in *container.HealthConfig) []interface{} {
|
|
if in == nil {
|
|
return make([]interface{}, 0, 0)
|
|
}
|
|
|
|
var out = make([]interface{}, 1, 1)
|
|
m := make(map[string]interface{})
|
|
if len(in.Test) > 0 {
|
|
m["test"] = in.Test
|
|
}
|
|
m["interval"] = shortDur(in.Interval)
|
|
m["timeout"] = shortDur(in.Timeout)
|
|
m["start_period"] = shortDur(in.StartPeriod)
|
|
m["retries"] = in.Retries
|
|
out[0] = m
|
|
return out
|
|
}
|
|
|
|
func flattenServiceHosts(in []string) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
m := make(map[string]interface{})
|
|
split := strings.Split(v, ":")
|
|
m["host"] = split[0]
|
|
m["ip"] = split[1]
|
|
out[i] = m
|
|
}
|
|
taskSpecResource := resourceDockerService().Schema["task_spec"].Elem.(*schema.Resource)
|
|
containerSpecResource := taskSpecResource.Schema["container_spec"].Elem.(*schema.Resource)
|
|
hostsResource := containerSpecResource.Schema["hosts"].Elem.(*schema.Resource)
|
|
f := schema.HashResource(hostsResource)
|
|
return schema.NewSet(f, out)
|
|
}
|
|
|
|
func flattenServiceDNSConfig(in *swarm.DNSConfig) []interface{} {
|
|
if in == nil {
|
|
return make([]interface{}, 0, 0)
|
|
}
|
|
|
|
var out = make([]interface{}, 1, 1)
|
|
m := make(map[string]interface{})
|
|
if len(in.Nameservers) > 0 {
|
|
m["nameservers"] = in.Nameservers
|
|
}
|
|
if len(in.Search) > 0 {
|
|
m["search"] = in.Search
|
|
}
|
|
if len(in.Options) > 0 {
|
|
m["options"] = in.Options
|
|
}
|
|
out[0] = m
|
|
return out
|
|
}
|
|
|
|
func flattenServiceSecrets(in []*swarm.SecretReference) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
m := make(map[string]interface{})
|
|
m["secret_id"] = v.SecretID
|
|
if len(v.SecretName) > 0 {
|
|
m["secret_name"] = v.SecretName
|
|
}
|
|
if v.File != nil {
|
|
m["file_name"] = v.File.Name
|
|
if len(v.File.UID) > 0 {
|
|
m["file_uid"] = v.File.UID
|
|
}
|
|
if len(v.File.GID) > 0 {
|
|
m["file_gid"] = v.File.GID
|
|
}
|
|
m["file_mode"] = int(v.File.Mode)
|
|
}
|
|
out[i] = m
|
|
}
|
|
taskSpecResource := resourceDockerService().Schema["task_spec"].Elem.(*schema.Resource)
|
|
containerSpecResource := taskSpecResource.Schema["container_spec"].Elem.(*schema.Resource)
|
|
secretsResource := containerSpecResource.Schema["secrets"].Elem.(*schema.Resource)
|
|
f := schema.HashResource(secretsResource)
|
|
return schema.NewSet(f, out)
|
|
}
|
|
|
|
func flattenServiceConfigs(in []*swarm.ConfigReference) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
m := make(map[string]interface{})
|
|
m["config_id"] = v.ConfigID
|
|
if len(v.ConfigName) > 0 {
|
|
m["config_name"] = v.ConfigName
|
|
}
|
|
if v.File != nil {
|
|
m["file_name"] = v.File.Name
|
|
if len(v.File.UID) > 0 {
|
|
m["file_uid"] = v.File.UID
|
|
}
|
|
if len(v.File.GID) > 0 {
|
|
m["file_gid"] = v.File.GID
|
|
}
|
|
m["file_mode"] = int(v.File.Mode)
|
|
}
|
|
out[i] = m
|
|
}
|
|
taskSpecResource := resourceDockerService().Schema["task_spec"].Elem.(*schema.Resource)
|
|
containerSpecResource := taskSpecResource.Schema["container_spec"].Elem.(*schema.Resource)
|
|
configsResource := containerSpecResource.Schema["configs"].Elem.(*schema.Resource)
|
|
f := schema.HashResource(configsResource)
|
|
return schema.NewSet(f, out)
|
|
}
|
|
|
|
func flattenTaskResources(in *swarm.ResourceRequirements) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
if in != nil {
|
|
m := make(map[string]interface{})
|
|
m["limits"] = flattenResourceLimitsOrReservations(in.Limits)
|
|
m["reservation"] = flattenResourceLimitsOrReservations(in.Reservations)
|
|
out = append(out, m)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func flattenResourceLimitsOrReservations(in *swarm.Resources) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
if in != nil {
|
|
m := make(map[string]interface{})
|
|
m["nano_cpus"] = in.NanoCPUs
|
|
m["memory_bytes"] = in.MemoryBytes
|
|
m["generic_resources"] = flattenResourceGenericResource(in.GenericResources)
|
|
out = append(out, m)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func flattenResourceGenericResource(in []swarm.GenericResource) []interface{} {
|
|
var out = make([]interface{}, 0, 0)
|
|
if in != nil && len(in) > 0 {
|
|
m := make(map[string]interface{})
|
|
named := make([]string, 0)
|
|
discrete := make([]string, 0)
|
|
for _, genericResource := range in {
|
|
if genericResource.NamedResourceSpec != nil {
|
|
named = append(named, genericResource.NamedResourceSpec.Kind+"="+genericResource.NamedResourceSpec.Value)
|
|
}
|
|
if genericResource.DiscreteResourceSpec != nil {
|
|
discrete = append(discrete, genericResource.DiscreteResourceSpec.Kind+"="+strconv.Itoa(int(genericResource.DiscreteResourceSpec.Value)))
|
|
}
|
|
}
|
|
m["named_resources_spec"] = newStringSet(schema.HashString, named)
|
|
m["discrete_resources_spec"] = newStringSet(schema.HashString, discrete)
|
|
out = append(out, m)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func flattenTaskRestartPolicy(in *swarm.RestartPolicy) map[string]interface{} {
|
|
m := make(map[string]interface{})
|
|
if len(in.Condition) > 0 {
|
|
m["condition"] = string(in.Condition)
|
|
}
|
|
if in.Delay != nil {
|
|
m["delay"] = shortDur(*in.Delay)
|
|
}
|
|
if in.MaxAttempts != nil {
|
|
mapped := *in.MaxAttempts
|
|
m["max_attempts"] = strconv.Itoa(int(mapped))
|
|
}
|
|
if in.Window != nil {
|
|
m["window"] = shortDur(*in.Window)
|
|
}
|
|
return m
|
|
}
|
|
|
|
func flattenTaskPlacement(in *swarm.Placement) []interface{} {
|
|
if in == nil {
|
|
return make([]interface{}, 0, 0)
|
|
}
|
|
var out = make([]interface{}, 1, 1)
|
|
m := make(map[string]interface{})
|
|
if len(in.Constraints) > 0 {
|
|
m["constraints"] = newStringSet(schema.HashString, in.Constraints)
|
|
}
|
|
if len(in.Preferences) > 0 {
|
|
m["prefs"] = flattenPlacementPrefs(in.Preferences)
|
|
}
|
|
if len(in.Platforms) > 0 {
|
|
m["platforms"] = flattenPlacementPlatforms(in.Platforms)
|
|
}
|
|
out[0] = m
|
|
return out
|
|
}
|
|
|
|
func flattenPlacementPrefs(in []swarm.PlacementPreference) *schema.Set {
|
|
if in == nil || len(in) == 0 {
|
|
return schema.NewSet(schema.HashString, make([]interface{}, 0, 0))
|
|
}
|
|
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
out[i] = v.Spread.SpreadDescriptor
|
|
}
|
|
return schema.NewSet(schema.HashString, out)
|
|
}
|
|
|
|
func flattenPlacementPlatforms(in []swarm.Platform) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
m := make(map[string]interface{})
|
|
m["architecture"] = v.Architecture
|
|
m["os"] = v.OS
|
|
out[i] = m
|
|
}
|
|
taskSpecResource := resourceDockerService().Schema["task_spec"].Elem.(*schema.Resource)
|
|
placementResource := taskSpecResource.Schema["placement"].Elem.(*schema.Resource)
|
|
f := schema.HashResource(placementResource)
|
|
return schema.NewSet(f, out)
|
|
}
|
|
|
|
func flattenTaskNetworks(in []swarm.NetworkAttachmentConfig) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
out[i] = v.Target
|
|
}
|
|
return schema.NewSet(schema.HashString, out)
|
|
}
|
|
|
|
func flattenTaskLogDriver(in *swarm.Driver) []interface{} {
|
|
if in == nil {
|
|
return make([]interface{}, 0, 0)
|
|
}
|
|
|
|
var out = make([]interface{}, 1, 1)
|
|
m := make(map[string]interface{})
|
|
m["name"] = in.Name
|
|
if len(in.Options) > 0 {
|
|
m["options"] = in.Options
|
|
}
|
|
out[0] = m
|
|
return out
|
|
}
|
|
|
|
///// end TaskSpec
|
|
///// start EndpointSpec
|
|
func flattenServicePorts(in []swarm.PortConfig) []interface{} {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
m := make(map[string]interface{})
|
|
m["name"] = v.Name
|
|
m["protocol"] = string(v.Protocol)
|
|
m["target_port"] = int(v.TargetPort)
|
|
m["published_port"] = int(v.PublishedPort)
|
|
m["publish_mode"] = string(v.PublishMode)
|
|
out[i] = m
|
|
}
|
|
return out
|
|
}
|
|
|
|
///// end EndpointSpec
|
|
|
|
// HELPERS
|
|
func shortDur(d time.Duration) string {
|
|
s := d.String()
|
|
if strings.HasSuffix(s, "m0s") {
|
|
s = s[:len(s)-2]
|
|
}
|
|
if strings.HasSuffix(s, "h0m") {
|
|
s = s[:len(s)-2]
|
|
}
|
|
return s
|
|
}
|
|
|
|
func newStringSet(f schema.SchemaSetFunc, in []string) *schema.Set {
|
|
var out = make([]interface{}, len(in), len(in))
|
|
for i, v := range in {
|
|
out[i] = v
|
|
}
|
|
return schema.NewSet(f, out)
|
|
}
|
|
|
|
// mapStringSliceToMap maps a slice with '=' delimiter to as map: e.g.
|
|
// - 'foo=bar' -> foo = "bar"
|
|
// - 'foo=bar?p=baz' -> foo = "bar?p=baz"
|
|
func mapStringSliceToMap(in []string) map[string]string {
|
|
mapped := make(map[string]string, len(in))
|
|
for _, v := range in {
|
|
if len(v) > 0 {
|
|
splitted := strings.Split(v, "=")
|
|
key := splitted[0]
|
|
value := strings.Join(splitted[1:], "=")
|
|
mapped[key] = value
|
|
}
|
|
}
|
|
return mapped
|
|
}
|
|
|
|
// mapStringStringToMapStringInterface maps a string string map to a string interface map
|
|
func mapStringStringToMapStringInterface(in map[string]string) map[string]interface{} {
|
|
if in == nil || len(in) == 0 {
|
|
return make(map[string]interface{}, 0)
|
|
}
|
|
|
|
mapped := make(map[string]interface{}, len(in))
|
|
for k, v := range in {
|
|
mapped[k] = v
|
|
}
|
|
return mapped
|
|
}
|