Merge pull request #2327 from jefferai/f-delay-on-link
Fix two serious problems when using links in Docker containers
This commit is contained in:
commit
b26df75b50
|
@ -5,11 +5,16 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
dc "github.com/fsouza/go-dockerclient"
|
dc "github.com/fsouza/go-dockerclient"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
creationTime time.Time
|
||||||
|
)
|
||||||
|
|
||||||
func resourceDockerContainerCreate(d *schema.ResourceData, meta interface{}) error {
|
func resourceDockerContainerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
var err error
|
var err error
|
||||||
client := meta.(*dc.Client)
|
client := meta.(*dc.Client)
|
||||||
|
@ -23,9 +28,8 @@ func resourceDockerContainerCreate(d *schema.ResourceData, meta interface{}) err
|
||||||
if _, ok := data.DockerImages[image]; !ok {
|
if _, ok := data.DockerImages[image]; !ok {
|
||||||
if _, ok := data.DockerImages[image+":latest"]; !ok {
|
if _, ok := data.DockerImages[image+":latest"]; !ok {
|
||||||
return fmt.Errorf("Unable to find image %s", image)
|
return fmt.Errorf("Unable to find image %s", image)
|
||||||
} else {
|
|
||||||
image = image + ":latest"
|
|
||||||
}
|
}
|
||||||
|
image = image + ":latest"
|
||||||
}
|
}
|
||||||
|
|
||||||
// The awesome, wonderful, splendiferous, sensical
|
// The awesome, wonderful, splendiferous, sensical
|
||||||
|
@ -108,6 +112,7 @@ func resourceDockerContainerCreate(d *schema.ResourceData, meta interface{}) err
|
||||||
hostConfig.Links = stringSetToStringSlice(v.(*schema.Set))
|
hostConfig.Links = stringSetToStringSlice(v.(*schema.Set))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
creationTime = time.Now()
|
||||||
if err := client.StartContainer(retContainer.ID, hostConfig); err != nil {
|
if err := client.StartContainer(retContainer.ID, hostConfig); err != nil {
|
||||||
return fmt.Errorf("Unable to start container: %s", err)
|
return fmt.Errorf("Unable to start container: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -122,21 +127,49 @@ func resourceDockerContainerRead(d *schema.ResourceData, meta interface{}) error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiContainer == nil {
|
if apiContainer == nil {
|
||||||
// This container doesn't exist anymore
|
// This container doesn't exist anymore
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
container, err := client.InspectContainer(apiContainer.ID)
|
var container *dc.Container
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error inspecting container %s: %s", apiContainer.ID, err)
|
loops := 1 // if it hasn't just been created, don't delay
|
||||||
|
if !creationTime.IsZero() {
|
||||||
|
loops = 30 // with 500ms spacing, 15 seconds; ought to be plenty
|
||||||
|
}
|
||||||
|
sleepTime := 500 * time.Millisecond
|
||||||
|
|
||||||
|
for i := loops; i > 0; i-- {
|
||||||
|
container, err = client.InspectContainer(apiContainer.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error inspecting container %s: %s", apiContainer.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if container.State.Running ||
|
||||||
|
(!container.State.Running && !d.Get("must_run").(bool)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if creationTime.IsZero() { // We didn't just create it, so don't wait around
|
||||||
|
return resourceDockerContainerDelete(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
if container.State.FinishedAt.After(creationTime) {
|
||||||
|
// It exited immediately, so error out so dependent containers
|
||||||
|
// aren't started
|
||||||
|
resourceDockerContainerDelete(d, meta)
|
||||||
|
return fmt.Errorf("Container %s exited after creation, error was: %s", apiContainer.ID, container.State.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(sleepTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Get("must_run").(bool) && !container.State.Running {
|
// Handle the case of the for loop above running its course
|
||||||
return resourceDockerContainerDelete(d, meta)
|
if !container.State.Running && d.Get("must_run").(bool) {
|
||||||
|
resourceDockerContainerDelete(d, meta)
|
||||||
|
return fmt.Errorf("Container %s failed to be in running state", apiContainer.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Network Settings
|
// Read Network Settings
|
||||||
|
@ -201,15 +234,17 @@ func fetchDockerContainer(name string, client *dc.Client) (*dc.APIContainers, er
|
||||||
// Sometimes the Docker API prefixes container names with /
|
// Sometimes the Docker API prefixes container names with /
|
||||||
// like it does in these commands. But if there's no
|
// like it does in these commands. But if there's no
|
||||||
// set name, it just uses the ID without a /...ugh.
|
// set name, it just uses the ID without a /...ugh.
|
||||||
var dockerContainerName string
|
switch len(apiContainer.Names) {
|
||||||
if len(apiContainer.Names) > 0 {
|
case 0:
|
||||||
dockerContainerName = strings.TrimLeft(apiContainer.Names[0], "/")
|
if apiContainer.ID == name {
|
||||||
} else {
|
return &apiContainer, nil
|
||||||
dockerContainerName = apiContainer.ID
|
}
|
||||||
}
|
default:
|
||||||
|
for _, containerName := range apiContainer.Names {
|
||||||
if dockerContainerName == name {
|
if strings.TrimLeft(containerName, "/") == name {
|
||||||
return &apiContainer, nil
|
return &apiContainer, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue