Repository: compose-spec/compose-go
Pull request #70 (2020-08-24 07:29:03)

Support IPAM configuration
This implement full IPAM configuration as defined by the compose-spec : https://github.com/compose-spec/compose-spec/blob/master/spec.md#ipam

Also updated "full config" tests so they use the same sample as the spec


Patch:
diff --git a/compatibility/checker.go b/compatibility/checker.go
index 3b6c2a4..a23c57d 100644
--- a/compatibility/checker.go
+++ b/compatibility/checker.go
@@ -170,6 +170,10 @@ type Checker interface {
 	CheckPorts(service *types.ServiceConfig) bool
 	CheckServiceVolumes(service *types.ServiceConfig) bool
 	CheckNetworkConfigIpam(network *types.NetworkConfig)
+	CheckNetworkConfigIpamSubnet(config *types.IPAMPool)
+	CheckNetworkConfigIpamGateway(config *types.IPAMPool)
+	CheckNetworkConfigIpamIPRange(config *types.IPAMPool)
+	CheckNetworkConfigIpamAuxiliaryAddresses(config *types.IPAMPool)
 	CheckNetworkConfigDriver(network *types.NetworkConfig)
 	CheckNetworkConfigDriverOpts(network *types.NetworkConfig)
 	CheckNetworkConfigExternal(network *types.NetworkConfig)
diff --git a/compatibility/networks.go b/compatibility/networks.go
index df87875..4701693 100644
--- a/compatibility/networks.go
+++ b/compatibility/networks.go
@@ -51,6 +51,9 @@ func (c *AllowList) CheckNetworkConfigIpam(config *types.NetworkConfig) {
 		}
 		for _, p := range config.Ipam.Config {
 			c.CheckNetworkConfigIpamSubnet(p)
+			c.CheckNetworkConfigIpamGateway(p)
+			c.CheckNetworkConfigIpamIPRange(p)
+			c.CheckNetworkConfigIpamAuxiliaryAddresses(p)
 		}
 	}
 }
@@ -67,7 +70,27 @@ func (c *AllowList) CheckNetworkConfigIpamSubnet(config *types.IPAMPool) {
 		config.Subnet = ""
 		c.Unsupported("networks.ipam.config.subnet")
 	}
+}
+
+func (c *AllowList) CheckNetworkConfigIpamGateway(config *types.IPAMPool) {
+	if !c.supported("networks.ipam.config.gateway") && config.Gateway != "" {
+		config.Gateway = ""
+		c.Unsupported("networks.ipam.config.gateway")
+	}
+}
 
+func (c *AllowList) CheckNetworkConfigIpamIPRange(config *types.IPAMPool) {
+	if !c.supported("networks.ipam.config.ip_range") && config.IPRange != "" {
+		config.IPRange = ""
+		c.Unsupported("networks.ipam.config.ip_range")
+	}
+}
+
+func (c *AllowList) CheckNetworkConfigIpamAuxiliaryAddresses(config *types.IPAMPool) {
+	if !c.supported("networks.ipam.config.aux_addresses") && len(config.AuxiliaryAddresses) > 0 {
+		config.AuxiliaryAddresses = nil
+		c.Unsupported("networks.ipam.config.aux_addresses")
+	}
 }
 
 func (c *AllowList) CheckNetworkConfigExternal(config *types.NetworkConfig) {
diff --git a/loader/full-example.yml b/loader/full-example.yml
index cb5fcd9..9463445 100644
--- a/loader/full-example.yml
+++ b/loader/full-example.yml
@@ -305,10 +305,15 @@ networks:
       #   com.docker.network.enable_ipv6: "true"
       #   com.docker.network.numeric_value: 1
       config:
-      - subnet: 172.16.238.0/24
-        # gateway: 172.16.238.1
+      - subnet: 172.28.0.0/16
+        ip_range: 172.28.5.0/24
+        gateway: 172.28.5.254
+        aux_addresses:
+          host1: 172.28.1.5
+          host2: 172.28.1.6
+          host3: 172.28.1.7
       - subnet: 2001:3984:3989::/64
-        # gateway: 2001:3984:3989::1
+        gateway: 2001:3984:3989::1
 
     labels:
       foo: bar
diff --git a/types/types.go b/types/types.go
index f2bc09d..8b056c8 100644
--- a/types/types.go
+++ b/types/types.go
@@ -595,8 +595,11 @@ type IPAMConfig struct {
 
 // IPAMPool for a network
 type IPAMPool struct {
-	Subnet     string                 `yaml:",omitempty" json:"subnet,omitempty"`
-	Extensions map[string]interface{} `yaml:",inline" json:"-"`
+	Subnet             string                 `yaml:",omitempty" json:"subnet,omitempty"`
+	Gateway            string                 `yaml:",omitempty" json:"gateway,omitempty"`
+	IPRange            string                 `mapstructure:"ip_range" yaml:"ip_range,omitempty" json:"ip_range,omitempty"`
+	AuxiliaryAddresses map[string]string      `mapstructure:"aux_addresses" yaml:"aux_addresses,omitempty" json:"aux_addresses,omitempty"`
+	Extensions         map[string]interface{} `yaml:",inline" json:"-"`
 }
 
 // VolumeConfig for a volume


Test patch:
diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go
index 5ef1244..2dcdae3 100644
--- a/loader/full-struct_test.go
+++ b/loader/full-struct_test.go
@@ -420,8 +420,20 @@ func networks() map[string]types.NetworkConfig {
 			Ipam: types.IPAMConfig{
 				Driver: "overlay",
 				Config: []*types.IPAMPool{
-					{Subnet: "172.16.238.0/24"},
-					{Subnet: "2001:3984:3989::/64"},
+					{
+						Subnet:  "172.28.0.0/16",
+						IPRange: "172.28.5.0/24",
+						Gateway: "172.28.5.254",
+						AuxiliaryAddresses: map[string]string{
+							"host1": "172.28.1.5",
+							"host2": "172.28.1.6",
+							"host3": "172.28.1.7",
+						},
+					},
+					{
+						Subnet:  "2001:3984:3989::/64",
+						Gateway: "2001:3984:3989::1",
+					},
 				},
 			},
 			Labels: map[string]string{
@@ -847,8 +859,15 @@ networks:
     ipam:
       driver: overlay
       config:
-      - subnet: 172.16.238.0/24
+      - subnet: 172.28.0.0/16
+        gateway: 172.28.5.254
+        ip_range: 172.28.5.0/24
+        aux_addresses:
+          host1: 172.28.1.5
+          host2: 172.28.1.6
+          host3: 172.28.1.7
       - subnet: 2001:3984:3989::/64
+        gateway: 2001:3984:3989::1
     labels:
       foo: bar
   some-network: {}
@@ -971,10 +990,18 @@ func fullExampleJSON(workingDir, homeDir string) string {
         "driver": "overlay",
         "config": [
           {
-            "subnet": "172.16.238.0/24"
+            "subnet": "172.28.0.0/16",
+            "gateway": "172.28.5.254",
+            "ip_range": "172.28.5.0/24",
+            "aux_addresses": {
+              "host1": "172.28.1.5",
+              "host2": "172.28.1.6",
+              "host3": "172.28.1.7"
+            }
           },
           {
-            "subnet": "2001:3984:3989::/64"
+            "subnet": "2001:3984:3989::/64",
+            "gateway": "2001:3984:3989::1"
           }
         ]
       },