mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2025-12-20 22:59:42 -05:00
Fix container ports issue for asc ordering (#115)
* Attempts to fix container ports issue by converting list to a set. * Revert "Attempts to fix container ports issue by converting list to a set." This reverts commit 5660759875ca65e2b8c5b9aa8b25cc3ff7eee2d9. * adds migration state func for container. Suppresses diff for port migration * Updates changelog for v1.1.1
This commit is contained in:
parent
a853943351
commit
1ac859bd81
3 changed files with 175 additions and 4 deletions
|
|
@ -1,5 +1,10 @@
|
||||||
## 1.1.1 (Unreleased)
|
## 1.1.1 (Unreleased)
|
||||||
|
|
||||||
|
BUG FIXES
|
||||||
|
* Fixes no more 'force new resource' for container ports when
|
||||||
|
there are no changes. This was caused to the ascending order. See [GH-110]
|
||||||
|
for details and [[#115](https://github.com/terraform-providers/terraform-provider-docker/pull/115)]
|
||||||
|
|
||||||
DOCS
|
DOCS
|
||||||
* Corrects `networks_advanced` section [GH-109]
|
* Corrects `networks_advanced` section [GH-109]
|
||||||
* Corrects `tmpfs_options` section [GH-122]
|
* Corrects `tmpfs_options` section [GH-122]
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,19 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceDockerContainer() *schema.Resource {
|
func resourceDockerContainer() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Create: resourceDockerContainerCreate,
|
Create: resourceDockerContainerCreate,
|
||||||
Read: resourceDockerContainerRead,
|
Read: resourceDockerContainerRead,
|
||||||
Update: resourceDockerContainerUpdate,
|
Update: resourceDockerContainerUpdate,
|
||||||
Delete: resourceDockerContainerDelete,
|
Delete: resourceDockerContainerDelete,
|
||||||
|
MigrateState: resourceDockerContainerMigrateState,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"name": &schema.Schema{
|
"name": &schema.Schema{
|
||||||
|
|
@ -259,6 +263,7 @@ func resourceDockerContainer() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DiffSuppressFunc: suppressIfPortsDidNotChangeForMigrationV0ToV1(),
|
||||||
},
|
},
|
||||||
|
|
||||||
"host": &schema.Schema{
|
"host": &schema.Schema{
|
||||||
|
|
@ -601,3 +606,49 @@ func resourceDockerContainer() *schema.Resource {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func suppressIfPortsDidNotChangeForMigrationV0ToV1() schema.SchemaDiffSuppressFunc {
|
||||||
|
return func(k, old, new string, d *schema.ResourceData) bool {
|
||||||
|
portsOldRaw, portsNewRaw := d.GetChange("ports")
|
||||||
|
portsOld := portsOldRaw.([]interface{})
|
||||||
|
portsNew := portsNewRaw.([]interface{})
|
||||||
|
if len(portsOld) != len(portsNew) {
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: old and new don't have the same length")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: old and new have same length")
|
||||||
|
|
||||||
|
for _, portOld := range portsOld {
|
||||||
|
portOldMapped := portOld.(map[string]interface{})
|
||||||
|
oldInternalPort := portOldMapped["internal"]
|
||||||
|
portFound := false
|
||||||
|
for _, portNew := range portsNew {
|
||||||
|
portNewMapped := portNew.(map[string]interface{})
|
||||||
|
newInternalPort := portNewMapped["internal"]
|
||||||
|
// port is still there in new
|
||||||
|
if newInternalPort == oldInternalPort {
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: comparing port '%v'", oldInternalPort)
|
||||||
|
portFound = true
|
||||||
|
if portNewMapped["external"] != portOldMapped["external"] {
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: 'external' changed for '%v'", oldInternalPort)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if portNewMapped["ip"] != portOldMapped["ip"] {
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: 'ip' changed for '%v'", oldInternalPort)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if portNewMapped["protocol"] != portOldMapped["protocol"] {
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: 'protocol' changed for '%v'", oldInternalPort)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// port was deleted or exchanges in new
|
||||||
|
if !portFound {
|
||||||
|
log.Printf("[DEBUG] suppress diff ports: port was deleted '%v'", oldInternalPort)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
115
docker/resource_docker_container_migrate.go
Normal file
115
docker/resource_docker_container_migrate.go
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceDockerContainerMigrateState(
|
||||||
|
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
|
||||||
|
switch v {
|
||||||
|
case 0:
|
||||||
|
log.Println("[INFO] Found Docker Container State v0; migrating to v1")
|
||||||
|
return migrateDockerContainerMigrateStateV0toV1(is, meta)
|
||||||
|
default:
|
||||||
|
return is, fmt.Errorf("Unexpected schema version: %d", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateDockerContainerMigrateStateV0toV1(is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
|
||||||
|
if is.Empty() {
|
||||||
|
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
|
||||||
|
return is, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Docker Container Attributes before Migration: %#v", is.Attributes)
|
||||||
|
|
||||||
|
err := updateV0ToV1PortsOrder(is, meta)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Docker Container Attributes after State Migration: %#v", is.Attributes)
|
||||||
|
|
||||||
|
return is, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type mappedPort struct {
|
||||||
|
internal int
|
||||||
|
external int
|
||||||
|
ip string
|
||||||
|
protocol string
|
||||||
|
}
|
||||||
|
|
||||||
|
type byPort []mappedPort
|
||||||
|
|
||||||
|
func (s byPort) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
func (s byPort) Swap(i, j int) {
|
||||||
|
s[i], s[j] = s[j], s[i]
|
||||||
|
}
|
||||||
|
func (s byPort) Less(i, j int) bool {
|
||||||
|
return s[i].internal < s[j].internal
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateV0ToV1PortsOrder(is *terraform.InstanceState, meta interface{}) error {
|
||||||
|
reader := &schema.MapFieldReader{
|
||||||
|
Schema: resourceDockerContainer().Schema,
|
||||||
|
Map: schema.BasicMapReader(is.Attributes),
|
||||||
|
}
|
||||||
|
|
||||||
|
writer := &schema.MapFieldWriter{
|
||||||
|
Schema: resourceDockerContainer().Schema,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := reader.ReadField([]string{"ports"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Value == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// map the ports into a struct, so they can be sorted easily
|
||||||
|
portsMapped := make([]mappedPort, 0)
|
||||||
|
portsRaw := result.Value.([]interface{})
|
||||||
|
for _, portRaw := range portsRaw {
|
||||||
|
if portRaw == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
portTyped := portRaw.(map[string]interface{})
|
||||||
|
portMapped := mappedPort{
|
||||||
|
internal: portTyped["internal"].(int),
|
||||||
|
external: portTyped["external"].(int),
|
||||||
|
ip: portTyped["ip"].(string),
|
||||||
|
protocol: portTyped["protocol"].(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
portsMapped = append(portsMapped, portMapped)
|
||||||
|
}
|
||||||
|
sort.Sort(byPort(portsMapped))
|
||||||
|
|
||||||
|
// map the sorted ports to an output structure tf can write
|
||||||
|
outputPorts := make([]interface{}, 0)
|
||||||
|
for _, mappedPort := range portsMapped {
|
||||||
|
outputPort := make(map[string]interface{}, 0)
|
||||||
|
outputPort["internal"] = mappedPort.internal
|
||||||
|
outputPort["external"] = mappedPort.external
|
||||||
|
outputPort["ip"] = mappedPort.ip
|
||||||
|
outputPort["protocol"] = mappedPort.protocol
|
||||||
|
outputPorts = append(outputPorts, outputPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store them back to state
|
||||||
|
if err := writer.WriteField([]string{"ports"}, outputPorts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range writer.Map() {
|
||||||
|
is.Attributes[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue