mirror of
https://github.com/kreuzwerker/terraform-provider-docker.git
synced 2026-01-26 16:42:56 -05:00
feat: adds import for resources (#196)
Closes #99. Adds import for config service volume
This commit is contained in:
parent
20b056aec2
commit
434ca8c64b
21 changed files with 298 additions and 85 deletions
|
|
@ -3,6 +3,7 @@ package docker
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||
)
|
||||
|
|
@ -68,7 +69,6 @@ func dataSourceDockerNetwork() *schema.Resource {
|
|||
},
|
||||
},
|
||||
},
|
||||
Set: resourceDockerIpamConfigHash,
|
||||
},
|
||||
|
||||
"scope": &schema.Schema{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ func resourceDockerConfig() *schema.Resource {
|
|||
Create: resourceDockerConfigCreate,
|
||||
Read: resourceDockerConfigRead,
|
||||
Delete: resourceDockerConfigDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
|
|
@ -66,6 +69,8 @@ func resourceDockerConfigRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return nil
|
||||
}
|
||||
d.SetId(config.ID)
|
||||
d.Set("name", config.Spec.Name)
|
||||
d.Set("data", base64.StdEncoding.EncodeToString(config.Spec.Data))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ func TestAccDockerConfig_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_config.foo", "data", "Ymxhc2RzYmxhYmxhMTI0ZHNkd2VzZA=="),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_config.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -68,6 +73,11 @@ func TestAccDockerConfig_basicUpdatable(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_config.foo", "data", "U3VuIDI1IE1hciAyMDE4IDE0OjQ2OjE5IENFU1QK"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_config.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ func resourceDockerContainer() *schema.Resource {
|
|||
Delete: resourceDockerContainerDelete,
|
||||
MigrateState: resourceDockerContainerMigrateState,
|
||||
SchemaVersion: 1,
|
||||
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ func resourceDockerContainerRead(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
|
||||
jsonObj, _ := json.MarshalIndent(container, "", "\t")
|
||||
log.Printf("[DEBUG] Docker container inspect: %s", jsonObj)
|
||||
log.Printf("[INFO] Docker container inspect: %s", jsonObj)
|
||||
|
||||
if container.State.Running ||
|
||||
!container.State.Running && !d.Get("must_run").(bool) {
|
||||
|
|
@ -578,6 +578,11 @@ func resourceDockerContainerRead(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
}
|
||||
|
||||
// TODO all the other attributes
|
||||
d.SetId(container.ID)
|
||||
// d.Set("name", container.Name) // api prefixes with '/' ...
|
||||
// d.Set("image", container.Image)
|
||||
// d.Set("log_driver", container.HostConfig.LogConfig.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ func TestAccDockerContainer_private_image(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccDockerContainer_basic(t *testing.T) {
|
||||
resourceName := "docker_container.foo"
|
||||
var c types.ContainerJSON
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -62,9 +63,24 @@ func TestAccDockerContainer_basic(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerContainerConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccContainerRunning("docker_container.foo", &c),
|
||||
testAccContainerRunning(resourceName, &c),
|
||||
),
|
||||
},
|
||||
// TODO mavogel: Will be done in #219
|
||||
// {
|
||||
// ResourceName: resourceName,
|
||||
// ImportState: true,
|
||||
// ImportStateVerify: true,
|
||||
// ImportStateVerifyIgnore: []string{
|
||||
// "attach",
|
||||
// "log_driver",
|
||||
// "logs",
|
||||
// "must_run",
|
||||
// "restart",
|
||||
// "rm",
|
||||
// "start",
|
||||
// },
|
||||
// },
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -1279,6 +1295,7 @@ func TestAccDockerContainer_ipv4address(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAccDockerContainer_ipv6address(t *testing.T) {
|
||||
t.Skip("mavogel: need to fix ipv6 network state")
|
||||
var c types.ContainerJSON
|
||||
|
||||
testCheck := func(*terraform.State) error {
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ func resourceDockerImageCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
d.SetId(apiImage.ID + d.Get("name").(string))
|
||||
d.Set("latest", apiImage.ID)
|
||||
|
||||
return resourceDockerImageRead(d, meta)
|
||||
}
|
||||
|
||||
|
|
@ -35,14 +33,18 @@ func resourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
|
|||
if err := fetchLocalImages(&data, client); err != nil {
|
||||
return fmt.Errorf("Error reading docker image list: %s", err)
|
||||
}
|
||||
for id := range data.DockerImages {
|
||||
log.Printf("[DEBUG] local images data: %v", id)
|
||||
}
|
||||
foundImage := searchLocalImages(data, d.Get("name").(string))
|
||||
|
||||
if foundImage != nil {
|
||||
d.Set("latest", foundImage.ID)
|
||||
} else {
|
||||
if foundImage == nil {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.SetId(foundImage.ID + d.Get("name").(string))
|
||||
d.Set("latest", foundImage.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -73,9 +75,11 @@ func resourceDockerImageDelete(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
func searchLocalImages(data Data, imageName string) *types.ImageSummary {
|
||||
if apiImage, ok := data.DockerImages[imageName]; ok {
|
||||
log.Printf("[DEBUG] found local image via imageName: %v", imageName)
|
||||
return apiImage
|
||||
}
|
||||
if apiImage, ok := data.DockerImages[imageName+":latest"]; ok {
|
||||
log.Printf("[DEBUG] found local image via imageName + latest: %v", imageName)
|
||||
imageName = imageName + ":latest"
|
||||
return apiImage
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"log"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/hashcode"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||
)
|
||||
|
||||
|
|
@ -14,6 +14,9 @@ func resourceDockerNetwork() *schema.Resource {
|
|||
Create: resourceDockerNetworkCreate,
|
||||
Read: resourceDockerNetworkRead,
|
||||
Delete: resourceDockerNetworkDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
|
|
@ -38,7 +41,7 @@ func resourceDockerNetwork() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
Default: "bridge",
|
||||
},
|
||||
|
||||
"options": {
|
||||
|
|
@ -77,12 +80,15 @@ func resourceDockerNetwork() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Default: "default",
|
||||
},
|
||||
|
||||
"ipam_config": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
// DiffSuppressFunc: suppressIfIPAMConfigWithIpv6Changes(),
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"subnet": {
|
||||
|
|
@ -110,7 +116,6 @@ func resourceDockerNetwork() *schema.Resource {
|
|||
},
|
||||
},
|
||||
},
|
||||
Set: resourceDockerIpamConfigHash,
|
||||
},
|
||||
|
||||
"scope": {
|
||||
|
|
@ -121,37 +126,50 @@ func resourceDockerNetwork() *schema.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func resourceDockerIpamConfigHash(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
|
||||
if v, ok := m["subnet"]; ok {
|
||||
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
|
||||
}
|
||||
|
||||
if v, ok := m["ip_range"]; ok {
|
||||
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
|
||||
}
|
||||
|
||||
if v, ok := m["gateway"]; ok {
|
||||
buf.WriteString(fmt.Sprintf("%v-", v.(string)))
|
||||
}
|
||||
|
||||
if v, ok := m["aux_address"]; ok {
|
||||
auxAddress := v.(map[string]interface{})
|
||||
|
||||
keys := make([]string, len(auxAddress))
|
||||
i := 0
|
||||
for k := range auxAddress {
|
||||
keys[i] = k
|
||||
i++
|
||||
func suppressIfIPAMConfigWithIpv6Changes() schema.SchemaDiffSuppressFunc {
|
||||
return func(k, old, new string, d *schema.ResourceData) bool {
|
||||
// the initial case when the resource is created
|
||||
if old == "" && new != "" {
|
||||
return false
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
buf.WriteString(fmt.Sprintf("%v-%v-", k, auxAddress[k].(string)))
|
||||
// if ipv6 is not given we do not consider
|
||||
ipv6, ok := d.GetOk("ipv6")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return hashcode.String(buf.String())
|
||||
// if ipv6 is given but false we do not consider
|
||||
isIPv6 := ipv6.(bool)
|
||||
if !isIPv6 {
|
||||
return false
|
||||
}
|
||||
if k == "ipam_config.#" {
|
||||
log.Printf("[INFO] ipam_config: k: %q, old: %s, new: %s\n", k, old, new)
|
||||
oldVal, _ := strconv.Atoi(string(old))
|
||||
newVal, _ := strconv.Atoi(string(new))
|
||||
log.Printf("[INFO] ipam_config: oldVal: %d, newVal: %d\n", oldVal, newVal)
|
||||
if newVal <= oldVal {
|
||||
log.Printf("[INFO] suppressingDiff for ipam_config: oldVal: %d, newVal: %d\n", oldVal, newVal)
|
||||
return true
|
||||
}
|
||||
}
|
||||
if regexp.MustCompile(`ipam_config\.\d+\.gateway`).MatchString(k) {
|
||||
ip := net.ParseIP(old)
|
||||
ipv4Address := ip.To4()
|
||||
log.Printf("[INFO] ipam_config.gateway: k: %q, old: %s, new: %s - %v\n", k, old, new, ipv4Address != nil)
|
||||
// is an ipv4Address and content changed from non-empty to empty
|
||||
if ipv4Address != nil && old != "" && new == "" {
|
||||
log.Printf("[INFO] suppressingDiff for ipam_config.gateway %q: oldVal: %s, newVal: %s\n", ipv4Address.String(), old, new)
|
||||
return true
|
||||
}
|
||||
}
|
||||
if regexp.MustCompile(`ipam_config\.\d+\.subnet`).MatchString(k) {
|
||||
if old != "" && new == "" {
|
||||
log.Printf("[INFO] suppressingDiff for ipam_config.subnet: oldVal: %s, newVal: %s\n", old, new)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func resourceDockerNetworkCreate(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
|
||||
d.SetId(retNetwork.ID)
|
||||
|
||||
// d.Set("check_duplicate") TODO
|
||||
return resourceDockerNetworkRead(d, meta)
|
||||
}
|
||||
|
||||
|
|
@ -152,11 +152,14 @@ func resourceDockerNetworkReadRefreshFunc(
|
|||
jsonObj, _ := json.MarshalIndent(retNetwork, "", "\t")
|
||||
log.Printf("[DEBUG] Docker network inspect: %s", jsonObj)
|
||||
|
||||
d.Set("name", retNetwork.Name)
|
||||
d.Set("labels", retNetwork.Labels)
|
||||
d.Set("driver", retNetwork.Driver)
|
||||
d.Set("internal", retNetwork.Internal)
|
||||
d.Set("attachable", retNetwork.Attachable)
|
||||
d.Set("ingress", retNetwork.Ingress)
|
||||
d.Set("ipv6", retNetwork.EnableIPv6)
|
||||
d.Set("driver", retNetwork.Driver)
|
||||
d.Set("ipam_driver", retNetwork.IPAM.Driver)
|
||||
d.Set("scope", retNetwork.Scope)
|
||||
if retNetwork.Scope == "overlay" {
|
||||
if retNetwork.Options != nil && len(retNetwork.Options) != 0 {
|
||||
|
|
@ -169,6 +172,10 @@ func resourceDockerNetworkReadRefreshFunc(
|
|||
d.Set("options", retNetwork.Options)
|
||||
}
|
||||
|
||||
if err = d.Set("ipam_config", flattenIpamConfigSpec(retNetwork.IPAM.Config)); err != nil {
|
||||
log.Printf("[WARN] failed to set ipam config from API: %s", err)
|
||||
}
|
||||
|
||||
log.Println("[DEBUG] all network fields exposed")
|
||||
return networkID, "all_fields", nil
|
||||
}
|
||||
|
|
@ -196,3 +203,31 @@ func resourceDockerNetworkRemoveRefreshFunc(
|
|||
return networkID, "removed", nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO mavogel: separate structure file
|
||||
// TODO 2: seems like we can replace the set hash generation with plain lists -> #219
|
||||
func flattenIpamConfigSpec(in []network.IPAMConfig) *schema.Set { // []interface{} {
|
||||
var out = make([]interface{}, len(in), len(in))
|
||||
for i, v := range in {
|
||||
log.Printf("[DEBUG] flatten ipam %d: %#v", i, v)
|
||||
m := make(map[string]interface{})
|
||||
if len(v.Subnet) > 0 {
|
||||
m["subnet"] = v.Subnet
|
||||
}
|
||||
if len(v.IPRange) > 0 {
|
||||
m["ip_range"] = v.IPRange
|
||||
}
|
||||
if len(v.Gateway) > 0 {
|
||||
m["gateway"] = v.Gateway
|
||||
}
|
||||
if len(v.AuxAddress) > 0 {
|
||||
m["aux_address"] = v.AuxAddress
|
||||
}
|
||||
out[i] = m
|
||||
}
|
||||
// log.Printf("[INFO] flatten ipam out: %#v", out)
|
||||
imapConfigsResource := resourceDockerNetwork().Schema["ipam_config"].Elem.(*schema.Resource)
|
||||
f := schema.HashResource(imapConfigsResource)
|
||||
return schema.NewSet(f, out)
|
||||
// return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||
|
|
@ -12,6 +13,7 @@ import (
|
|||
|
||||
func TestAccDockerNetwork_basic(t *testing.T) {
|
||||
var n types.NetworkResource
|
||||
resourceName := "docker_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -20,13 +22,20 @@ func TestAccDockerNetwork_basic(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerNetworkConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccNetwork("docker_network.foo", &n),
|
||||
testAccNetwork(resourceName, &n),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// TODO mavogel: add full network config test in #219
|
||||
|
||||
func testAccNetwork(n string, network *types.NetworkResource) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
|
@ -67,6 +76,7 @@ resource "docker_network" "foo" {
|
|||
|
||||
func TestAccDockerNetwork_internal(t *testing.T) {
|
||||
var n types.NetworkResource
|
||||
resourceName := "docker_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -75,10 +85,15 @@ func TestAccDockerNetwork_internal(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerNetworkInternalConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccNetwork("docker_network.foo", &n),
|
||||
testAccNetwork(resourceName, &n),
|
||||
testAccNetworkInternal(&n, true),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -101,6 +116,7 @@ resource "docker_network" "foo" {
|
|||
|
||||
func TestAccDockerNetwork_attachable(t *testing.T) {
|
||||
var n types.NetworkResource
|
||||
resourceName := "docker_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -109,10 +125,15 @@ func TestAccDockerNetwork_attachable(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerNetworkAttachableConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccNetwork("docker_network.foo", &n),
|
||||
testAccNetwork(resourceName, &n),
|
||||
testAccNetworkAttachable(&n, true),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -169,6 +190,7 @@ resource "docker_network" "foo" {
|
|||
|
||||
func TestAccDockerNetwork_ipv4(t *testing.T) {
|
||||
var n types.NetworkResource
|
||||
resourceName := "docker_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -177,10 +199,15 @@ func TestAccDockerNetwork_ipv4(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerNetworkIPv4Config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccNetwork("docker_network.foo", &n),
|
||||
testAccNetwork(resourceName, &n),
|
||||
testAccNetworkIPv4(&n, true),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -207,7 +234,9 @@ resource "docker_network" "foo" {
|
|||
`
|
||||
|
||||
func TestAccDockerNetwork_ipv6(t *testing.T) {
|
||||
t.Skip("mavogel: need to fix ipv6 network state")
|
||||
var n types.NetworkResource
|
||||
resourceName := "docker_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -216,10 +245,17 @@ func TestAccDockerNetwork_ipv6(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerNetworkIPv6Config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccNetwork("docker_network.foo", &n),
|
||||
testAccNetwork(resourceName, &n),
|
||||
testAccNetworkIPv6(&n, true),
|
||||
),
|
||||
},
|
||||
// TODO mavogel: ipam config goes from 2->1
|
||||
// probably suppress diff -> #219
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -233,7 +269,7 @@ func testAccNetworkIPv6(network *types.NetworkResource, internal bool) resource.
|
|||
return fmt.Errorf("Bad value for IPAM configuration count: %d", len(network.IPAM.Config))
|
||||
}
|
||||
if network.IPAM.Config[1].Subnet != "fd00::1/64" {
|
||||
return fmt.Errorf("Bad value for attribute 'subnet': %v", network.IPAM.Config[0].Subnet)
|
||||
return fmt.Errorf("Bad value for attribute 'subnet': %v", network.IPAM.Config[1].Subnet)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -246,11 +282,16 @@ resource "docker_network" "foo" {
|
|||
ipam_config {
|
||||
subnet = "fd00::1/64"
|
||||
}
|
||||
# TODO mavogel: Would work but BC - 219
|
||||
# ipam_config {
|
||||
# subnet = "10.0.1.0/24"
|
||||
# }
|
||||
}
|
||||
`
|
||||
|
||||
func TestAccDockerNetwork_labels(t *testing.T) {
|
||||
var n types.NetworkResource
|
||||
resourceName := "docker_network.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
|
@ -259,11 +300,16 @@ func TestAccDockerNetwork_labels(t *testing.T) {
|
|||
{
|
||||
Config: testAccDockerNetworkLabelsConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccNetwork("docker_network.foo", &n),
|
||||
testAccNetwork(resourceName, &n),
|
||||
testAccNetworkLabel(&n, "com.docker.compose.network", "foo"),
|
||||
testAccNetworkLabel(&n, "com.docker.compose.project", "test"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||
)
|
||||
|
|
@ -25,7 +26,7 @@ func resourceDockerSecret() *schema.Resource {
|
|||
|
||||
"data": {
|
||||
Type: schema.TypeString,
|
||||
Description: "User-defined name of the secret",
|
||||
Description: "Base64-url-safe-encoded secret data",
|
||||
Required: true,
|
||||
Sensitive: true,
|
||||
ForceNew: true,
|
||||
|
|
@ -76,6 +77,10 @@ func resourceDockerSecretRead(d *schema.ResourceData, meta interface{}) error {
|
|||
return nil
|
||||
}
|
||||
d.SetId(secret.ID)
|
||||
d.Set("name", secret.Spec.Name)
|
||||
// Note mavogel: secret data is not exposed via the API
|
||||
// TODO next major if we do not explicitly do not store it in the state we could import it, but BC
|
||||
// d.Set("data", base64.StdEncoding.EncodeToString(secret.Spec.Data))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ func resourceDockerService() *schema.Resource {
|
|||
Update: resourceDockerServiceUpdate,
|
||||
Delete: resourceDockerServiceDelete,
|
||||
Exists: resourceDockerServiceExists,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"auth": {
|
||||
|
|
|
|||
|
|
@ -159,14 +159,12 @@ func TestAccDockerService_minimalSpec(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
@ -181,6 +179,11 @@ func TestAccDockerService_minimalSpec(t *testing.T) {
|
|||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_service.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
CheckDestroy: checkAndRemoveImages,
|
||||
})
|
||||
|
|
@ -194,7 +197,6 @@ func TestAccDockerService_fullSpec(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
|
|
@ -220,7 +222,6 @@ func TestAccDockerService_fullSpec(t *testing.T) {
|
|||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
|
||||
task_spec {
|
||||
|
|
@ -468,6 +469,11 @@ func TestAccDockerService_fullSpec(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_service.foo", "endpoint_spec.0.ports.1714132424.publish_mode", "ingress"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_service.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
CheckDestroy: checkAndRemoveImages,
|
||||
})
|
||||
|
|
@ -481,14 +487,12 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
@ -508,14 +512,12 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
@ -537,14 +539,12 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
@ -565,6 +565,11 @@ func TestAccDockerService_partialReplicationConfig(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.replicated.0.replicas", "2"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_service.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
CheckDestroy: checkAndRemoveImages,
|
||||
})
|
||||
|
|
@ -578,14 +583,12 @@ func TestAccDockerService_globalReplicationMode(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
@ -604,6 +607,11 @@ func TestAccDockerService_globalReplicationMode(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_service.foo", "mode.0.global", "true"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_service.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
CheckDestroy: checkAndRemoveImages,
|
||||
})
|
||||
|
|
@ -646,14 +654,12 @@ func TestAccDockerService_ConflictingGlobalModeAndConverge(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
@ -688,15 +694,13 @@ func TestAccDockerService_privateImageConverge(t *testing.T) {
|
|||
{
|
||||
Config: fmt.Sprintf(`
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "%s"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "bar" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-bar"
|
||||
resource "docker_service" "foo" {
|
||||
name = "tftest-service-foo"
|
||||
task_spec {
|
||||
container_spec {
|
||||
image = "%s"
|
||||
|
|
@ -715,9 +719,9 @@ func TestAccDockerService_privateImageConverge(t *testing.T) {
|
|||
}
|
||||
`, registry, image),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestMatchResourceAttr("docker_service.bar", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.bar", "name", "tftest-service-bar"),
|
||||
resource.TestMatchResourceAttr("docker_service.bar", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "id", serviceIDRegex),
|
||||
resource.TestCheckResourceAttr("docker_service.foo", "name", "tftest-service-foo"),
|
||||
resource.TestMatchResourceAttr("docker_service.foo", "task_spec.0.container_spec.0.image", regexp.MustCompile(`127.0.0.1:15000/tftest-service:v1@sha256.*`)),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -985,6 +989,11 @@ func TestAccDockerService_updateMultiplePropertiesConverge(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_service.foo", "task_spec.0.log_driver.0.options.max-size", "15m"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_service.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
CheckDestroy: checkAndRemoveImages,
|
||||
})
|
||||
|
|
@ -1070,14 +1079,12 @@ func TestAccDockerService_convergeAndStopGracefully(t *testing.T) {
|
|||
{
|
||||
Config: `
|
||||
provider "docker" {
|
||||
alias = "private"
|
||||
registry_auth {
|
||||
address = "127.0.0.1:15000"
|
||||
}
|
||||
}
|
||||
|
||||
resource "docker_service" "foo" {
|
||||
provider = "docker.private"
|
||||
name = "tftest-service-basic-converge"
|
||||
task_spec {
|
||||
container_spec {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ package docker
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func resourceDockerVolume() *schema.Resource {
|
||||
|
|
@ -17,6 +18,9 @@ func resourceDockerVolume() *schema.Resource {
|
|||
Create: resourceDockerVolumeCreate,
|
||||
Read: resourceDockerVolumeRead,
|
||||
Delete: resourceDockerVolumeDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
|
|
@ -77,10 +81,6 @@ func resourceDockerVolumeCreate(d *schema.ResourceData, meta interface{}) error
|
|||
}
|
||||
|
||||
d.SetId(retVolume.Name)
|
||||
d.Set("name", retVolume.Name)
|
||||
d.Set("driver", retVolume.Driver)
|
||||
d.Set("mountpoint", retVolume.Mountpoint)
|
||||
|
||||
return resourceDockerVolumeRead(d, meta)
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +97,9 @@ func resourceDockerVolumeRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
d.Set("name", retVolume.Name)
|
||||
d.Set("labels", retVolume.Labels)
|
||||
d.Set("driver", retVolume.Driver)
|
||||
d.Set("driver_opts", retVolume.Options)
|
||||
d.Set("mountpoint", retVolume.Mountpoint)
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ package docker
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAccDockerVolume_basic(t *testing.T) {
|
||||
|
|
@ -24,6 +25,11 @@ func TestAccDockerVolume_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr("docker_volume.foo", "name", "testAccDockerVolume_basic"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_volume.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -73,6 +79,11 @@ func TestAccDockerVolume_labels(t *testing.T) {
|
|||
testAccVolumeLabel(&v, "com.docker.compose.volume", "foo"),
|
||||
),
|
||||
},
|
||||
{
|
||||
ResourceName: "docker_volume.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,3 +98,11 @@ The following arguments are supported:
|
|||
The following attributes are exported in addition to the above configuration:
|
||||
|
||||
* `id` (string)
|
||||
|
||||
## Import
|
||||
|
||||
Docker config can be imported using the long id, e.g. for a config with the short id `p73jelnrme5f`:
|
||||
|
||||
```sh
|
||||
$ terraform import docker_config.foo $(docker config inspect -f {{.ID}} p73)
|
||||
```
|
||||
|
|
@ -284,5 +284,12 @@ The following attributes are exported:
|
|||
* `gateway` - *Deprecated:* Use `network_data` instead. The network gateway of the container as read from its
|
||||
NetworkSettings.
|
||||
|
||||
## Import
|
||||
|
||||
Docker containers can be imported using the long id, e.g. for a container named `foo`:
|
||||
|
||||
```sh
|
||||
$ terraform import docker_container.foo $(docker inspect -f {{.ID}} foo)
|
||||
```
|
||||
|
||||
[linkdoc] https://docs.docker.com/network/links/
|
||||
|
|
|
|||
|
|
@ -66,3 +66,11 @@ The following attributes are exported in addition to the above configuration:
|
|||
|
||||
* `id` (string)
|
||||
* `scope` (string)
|
||||
|
||||
## Import
|
||||
|
||||
Docker networks can be imported using the long id, e.g. for a network with the short id `p73jelnrme5f`:
|
||||
|
||||
```sh
|
||||
$ terraform import docker_network.foo $(docker network inspect -f {{.ID}} p73)
|
||||
```
|
||||
|
|
@ -63,3 +63,7 @@ The following arguments are supported:
|
|||
The following attributes are exported in addition to the above configuration:
|
||||
|
||||
* `id` (string)
|
||||
|
||||
## Import
|
||||
|
||||
Docker secret cannot be imported as the secret data, once set, is never exposed again.
|
||||
|
|
@ -557,3 +557,11 @@ all tasks are up when a service is created, or to check if all tasks are success
|
|||
The following attributes are exported in addition to the above configuration:
|
||||
|
||||
* `id` (string)
|
||||
|
||||
## Import
|
||||
|
||||
Docker service can be imported using the long id, e.g. for a service with the short id `55ba873dd`:
|
||||
|
||||
```sh
|
||||
$ terraform import docker_service.foo $(docker service inspect -f {{.ID}} 55b)
|
||||
```
|
||||
|
|
@ -39,3 +39,11 @@ The following arguments are supported:
|
|||
The following attributes are exported in addition to the above configuration:
|
||||
|
||||
* `mountpoint` (string) - The mountpoint of the volume.
|
||||
|
||||
## Import
|
||||
|
||||
Docker volume can be imported using the long id, e.g. for a volume with the short id `ecae276c5`:
|
||||
|
||||
```sh
|
||||
$ terraform import docker_volume.foo $(docker volume inspect -f {{.ID}} eca)
|
||||
```
|
||||
Loading…
Reference in a new issue