terraform-provider-docker/internal/provider/resource_docker_network_funcs.go

214 lines
6.6 KiB
Go
Raw Normal View History

package provider
import (
"context"
"encoding/json"
"log"
"time"
"github.com/docker/docker/api/types/network"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
networkReadRefreshTimeout = 30 * time.Second
networkReadRefreshWaitBeforeRefreshes = 5 * time.Second
networkReadRefreshDelay = 2 * time.Second
networkRemoveRefreshTimeout = 30 * time.Second
networkRemoveRefreshWaitBeforeRefreshes = 5 * time.Second
networkRemoveRefreshDelay = 2 * time.Second
)
func resourceDockerNetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*ProviderConfig).DockerClient
createOpts := network.CreateOptions{}
if v, ok := d.GetOk("labels"); ok {
2019-11-12 17:41:59 -05:00
createOpts.Labels = labelSetToMap(v.(*schema.Set))
}
if v, ok := d.GetOk("driver"); ok {
createOpts.Driver = v.(string)
}
if v, ok := d.GetOk("options"); ok {
createOpts.Options = mapTypeMapValsToString(v.(map[string]interface{}))
}
if v, ok := d.GetOk("internal"); ok {
createOpts.Internal = v.(bool)
}
if v, ok := d.GetOk("attachable"); ok {
createOpts.Attachable = v.(bool)
}
if v, ok := d.GetOk("ingress"); ok {
createOpts.Ingress = v.(bool)
}
if v, ok := d.GetOk("ipv6"); ok {
enableIPv6 := v.(bool)
createOpts.EnableIPv6 = &enableIPv6
}
ipamOpts := &network.IPAM{}
ipamOptsSet := false
if v, ok := d.GetOk("ipam_driver"); ok {
ipamOpts.Driver = v.(string)
ipamOptsSet = true
}
if v, ok := d.GetOk("ipam_config"); ok {
ipamOpts.Config = ipamConfigSetToIpamConfigs(v.(*schema.Set))
ipamOptsSet = true
}
if v, ok := d.GetOk("ipam_options"); ok {
ipamOpts.Options = mapTypeMapValsToString(v.(map[string]interface{}))
ipamOptsSet = true
}
if ipamOptsSet {
createOpts.IPAM = ipamOpts
}
retNetwork, err := client.NetworkCreate(ctx, d.Get("name").(string), createOpts)
if err != nil {
return diag.Errorf("Unable to create network: %s", err)
}
d.SetId(retNetwork.ID)
chore/refactor tests (#201) * chore: format test configs for datasources * chore: outlines load test config helper and structure * docs(contributing): add command for resouce tests to have an example of the regex * refactor: move container test configs into separate files * fix: add insecure_skip_verify for image pulls to fix the local test setup with invalid certs * chore(ci): remove insecure registry adaption * chore: regenerate website * chore: update gitignore for scipts/testing dir * fix: replace nodejs services with go versions * fix: move testing program versions in separate files * test: reactivate flaky test from travis * chore: fix linter on all go files * fix(linter): testing go servers * chore(ci): add env for go version * chore(ci): name workflow steps also moves description of available docker versions in to acc dockerfile * Revert "test: reactivate flaky test from travis" This reverts commit b02654acc4d6b7d02c8f3ba090e6a3f248741b10. * docs: fix provider-ssh example * chore: use alpine als final image for tests * refactor: move test configs from folder into testname.tf files * refactor: image delete log is now debug and indented * refactor: image test config into seprate files * refactor: move network test config into seperate files * refactor: move plugin test config into seperate files * chore: rename registry image test file * refactor: move registry_image test config into seperate files * chore: format secret test configs * refactor: inline volume test configs * fix: remove unused volume label test function * refactor: move service test configs into seperate files * test: reactivate and fix service test * chore: simplify insecure skip verify add to http client * chore(ci): debug into service test * chore(ci): add testacc setup * chore: format tf config for provider test * chore(ci): add debug output for config.json * fix: check service auth for emptyness * fix: remove re-read of provider auth config because the bug occured only in CI as the meta object might be GCd * test: pass auth to service instead of provider * chore: reactivate all acc tests * test: outlines service inspect json check for full spec * test: add service inspect json checks * test: finish service inspect json checks * chore(service): move test helper to end to of the file * chore: move mapEquals to test helpers * test: add json inspect for config * chore: add debug inspect log for plugin, secret and volume * test: add json inspect for secret * test: add json inspect for image * test: add json inspect for network * test: add json inspect for plugin * test: add json inspect for volume * test: inline ds plugin test configs * test: inline network configs * test: move ds reg image configs into separate files * test: reactivates container upload checks * chore: adapt issues ref from old to new xw repo * fix: reactivate network ingress test and provide helpers for removing the default ingress network and leaving the swamr * docs: rerun website gen * test: fix reg image build and keep test * chore: add name to todo * chore: move ds network and plugin specs to file * chore: format provider test spec * chore: use simpler error message for empty strings
2021-05-31 03:11:49 -04:00
// d.Set("check_duplicate") TODO mavogel
return resourceDockerNetworkRead(ctx, d, meta)
}
func resourceDockerNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("[INFO] Waiting for network: '%s' to expose all fields: max '%v seconds'", d.Id(), networkReadRefreshTimeout)
stateConf := &resource.StateChangeConf{
Pending: []string{"pending"},
Target: []string{"all_fields", "removed"},
Refresh: resourceDockerNetworkReadRefreshFunc(ctx, d, meta),
Timeout: networkReadRefreshTimeout,
MinTimeout: networkReadRefreshWaitBeforeRefreshes,
Delay: networkReadRefreshDelay,
}
// Wait, catching any errors
_, err := stateConf.WaitForStateContext(ctx)
if err != nil {
return diag.FromErr(err)
}
return nil
}
func resourceDockerNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("[INFO] Waiting for network: '%s' to be removed: max '%v seconds'", d.Id(), networkRemoveRefreshTimeout)
stateConf := &resource.StateChangeConf{
Pending: []string{"pending"},
Target: []string{"removed"},
Refresh: resourceDockerNetworkRemoveRefreshFunc(ctx, d, meta),
Timeout: networkRemoveRefreshTimeout,
MinTimeout: networkRemoveRefreshWaitBeforeRefreshes,
Delay: networkRemoveRefreshDelay,
}
// Wait, catching any errors
_, err := stateConf.WaitForStateContext(ctx)
if err != nil {
return diag.FromErr(err)
}
d.SetId("")
return nil
}
func ipamConfigSetToIpamConfigs(ipamConfigSet *schema.Set) []network.IPAMConfig {
ipamConfigs := make([]network.IPAMConfig, ipamConfigSet.Len())
for i, ipamConfigInt := range ipamConfigSet.List() {
ipamConfigRaw := ipamConfigInt.(map[string]interface{})
ipamConfig := network.IPAMConfig{}
ipamConfig.Subnet = ipamConfigRaw["subnet"].(string)
ipamConfig.IPRange = ipamConfigRaw["ip_range"].(string)
ipamConfig.Gateway = ipamConfigRaw["gateway"].(string)
auxAddressRaw := ipamConfigRaw["aux_address"].(map[string]interface{})
ipamConfig.AuxAddress = make(map[string]string, len(auxAddressRaw))
for k, v := range auxAddressRaw {
ipamConfig.AuxAddress[k] = v.(string)
}
ipamConfigs[i] = ipamConfig
}
return ipamConfigs
}
func resourceDockerNetworkReadRefreshFunc(ctx context.Context,
d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
client := meta.(*ProviderConfig).DockerClient
networkID := d.Id()
retNetwork, _, err := client.NetworkInspectWithRaw(ctx, networkID, network.InspectOptions{})
if err != nil {
log.Printf("[WARN] Network (%s) not found, removing from state", networkID)
d.SetId("")
return networkID, "removed", nil
}
jsonObj, _ := json.MarshalIndent(retNetwork, "", "\t")
log.Printf("[DEBUG] Docker network inspect: %s", jsonObj)
d.Set("name", retNetwork.Name)
d.Set("labels", mapToLabelSet(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("ipam_driver", retNetwork.IPAM.Driver)
d.Set("ipam_options", retNetwork.IPAM.Options)
d.Set("scope", retNetwork.Scope)
if retNetwork.Scope == "overlay" {
if len(retNetwork.Options) != 0 {
d.Set("options", retNetwork.Options)
} else {
log.Printf("[DEBUG] options: %v not exposed", retNetwork.Options)
return networkID, "pending", nil
}
} else {
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
}
}
func resourceDockerNetworkRemoveRefreshFunc(ctx context.Context,
d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
client := meta.(*ProviderConfig).DockerClient
networkID := d.Id()
_, _, err := client.NetworkInspectWithRaw(ctx, networkID, network.InspectOptions{})
if err != nil {
log.Printf("[INFO] Network (%s) not found. Already removed", networkID)
return networkID, "removed", nil
}
if err := client.NetworkRemove(ctx, networkID); err != nil {
if containsIgnorableErrorMessage(err.Error(), "has active endpoints") {
return networkID, "pending", nil
}
return networkID, "other", err
}
return networkID, "removed", nil
}
}