diff --git a/api/structs.go b/api/structs.go index f8fa9295..8b86447d 100644 --- a/api/structs.go +++ b/api/structs.go @@ -326,6 +326,19 @@ type ContainerCgroupConfig struct { CgroupParent string `json:"cgroup_parent,omitempty"` } +// PerNetworkOptions allows you to set options per network the container is +// attached to. +type PerNetworkOptions struct { + // Aliases contains a list of names which the dns server should resolve to this container. Should only be set when DNSEnabled is true on the Network. If aliases are set but there is no dns support for this network the network interface implementation should ignore this and NOT error. Optional. + Aliases []string `json:"aliases,omitempty"` + // InterfaceName for this container. Required in the backend. Optional in the frontend. Will be filled with ethX (where X is a integer) when empty. + InterfaceName string `json:"interface_name,omitempty"` + // StaticIPs for this container. Optional. + StaticIPs []*net.IP `json:"static_ips,omitempty"` + // StaticMac for this container. Optional. + StaticMac *net.HardwareAddr `json:"static_mac,omitempty"` +} + // ContainerNetworkConfig contains information on a container's network // configuration. type ContainerNetworkConfig struct { @@ -407,6 +420,13 @@ type ContainerNetworkConfig struct { // Podman, and instead sourced from the image. // Conflicts with HostAdd. UseImageHosts bool `json:"use_image_hosts,omitempty"` + // Map of networks names or ids that the container should join. You can + // request additional settings for each network, you can set network + // aliases, static ips, static mac address and the network interface name + // for this container on the specific network. If the map is empty and the + // bridge network mode is set the container will be joined to the default + // network. + Networks map[string]PerNetworkOptions `json:"networks,omitempty"` } // ContainerResourceConfig contains information on container resource limits. diff --git a/config.go b/config.go index 72d7dd39..2cb440a2 100644 --- a/config.go +++ b/config.go @@ -92,9 +92,13 @@ var ( hclspec.NewAttr("image_pull_timeout", "string", false), hclspec.NewLiteral(`"5m"`), ), - "init": hclspec.NewAttr("init", "bool", false), - "init_path": hclspec.NewAttr("init_path", "string", false), - "labels": hclspec.NewAttr("labels", "list(map(string))", false), + "init": hclspec.NewAttr("init", "bool", false), + "init_path": hclspec.NewAttr("init_path", "string", false), + "ipv4_address": hclspec.NewAttr("ipv4_address", "string", false), + "ipv6_address": hclspec.NewAttr("ipv6_address", "string", false), + "static_ips": hclspec.NewAttr("static_ips", "list(string)", false), + "static_macs": hclspec.NewAttr("static_macs", "list(string)", false), + "labels": hclspec.NewAttr("labels", "list(map(string))", false), "logging": hclspec.NewBlock("logging", false, hclspec.NewObject(map[string]*hclspec.Spec{ "driver": hclspec.NewAttr("driver", "string", false), "options": hclspec.NewAttr("options", "list(map(string))", false), @@ -203,6 +207,10 @@ type TaskConfig struct { Hostname string `codec:"hostname"` Image string `codec:"image"` ImagePullTimeout string `codec:"image_pull_timeout"` + IPv4Address string `codec:"ipv4_address"` + IPv6Address string `codec:"ipv6_address"` + StaticIPs []string `codec:"static_ips"` + StaticMAC string `codec:"static_mac"` InitPath string `codec:"init_path"` Logging TaskLoggingConfig `codec:"logging"` Labels hclutils.MapStrStr `codec:"labels"` diff --git a/driver.go b/driver.go index 62c9cd9d..1146b545 100644 --- a/driver.go +++ b/driver.go @@ -22,6 +22,7 @@ import ( "github.com/containers/image/v5/pkg/shortnames" "github.com/containers/image/v5/types" "github.com/hashicorp/go-hclog" + version2 "github.com/hashicorp/go-version" "github.com/hashicorp/nomad-driver-podman/api" "github.com/hashicorp/nomad-driver-podman/registry" "github.com/hashicorp/nomad-driver-podman/version" @@ -688,6 +689,81 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive } } + // Process static IP and MAC configuration. IPv4Address and IPv6Address are + // provided for compatibility with Docker, but the podman API v4 exposes a + // list of static addresses too. Add all three options to the API call for + // the default network + if driverConfig.StaticMAC != "" || driverConfig.IPv4Address != "" || driverConfig.IPv6Address != "" || len(driverConfig.StaticIPs) > 0 { + apiVersion, _ := d.podman.Ping(d.ctx) + versionValue, _ := version2.NewVersion(apiVersion) + versionCheck, _ := version2.NewConstraint(">=4.0.0") + + if versionCheck.Check(versionValue) { + // Podman API v4 uses PerNetworkOptions. For now, we'll just use the + // default network. + + netOpts := api.PerNetworkOptions{} + netOpts.StaticIPs = []*net.IP{} + + if driverConfig.IPv4Address != "" { + parsedIP := net.ParseIP(driverConfig.IPv4Address) + if parsedIP != nil { + netOpts.StaticIPs = append(netOpts.StaticIPs, &parsedIP) + } + } + + if driverConfig.IPv6Address != "" { + parsedIPv6 := net.ParseIP(driverConfig.IPv6Address) + if parsedIPv6 != nil { + netOpts.StaticIPs = append(netOpts.StaticIPs, &parsedIPv6) + } + } + + if len(driverConfig.StaticIPs) > 0 { + for _, ip := range driverConfig.StaticIPs { + parsedIP := net.ParseIP(ip) + if parsedIP != nil { + netOpts.StaticIPs = append(netOpts.StaticIPs, &parsedIP) + } + } + } + + // Process Static MAC configuration + if driverConfig.StaticMAC != "" { + parsedMAC, macErr := net.ParseMAC(driverConfig.StaticMAC) + if macErr == nil && parsedMAC != nil { + netOpts.StaticMac = &parsedMAC + } + } + + createOpts.Networks = map[string]api.PerNetworkOptions{"default": netOpts} + } else { + // Before version 4, there were StaticIP, StaticIPv6 and StaticMAC properties + + if driverConfig.IPv4Address != "" { + parsedIP := net.ParseIP(driverConfig.IPv4Address) + if parsedIP != nil { + createOpts.ContainerNetworkConfig.StaticIP = &parsedIP + } + } + + if driverConfig.IPv6Address != "" { + parsedIPv6 := net.ParseIP(driverConfig.IPv6Address) + if parsedIPv6 != nil { + createOpts.ContainerNetworkConfig.StaticIPv6 = &parsedIPv6 + } + } + + // Process Static MAC configuration + if driverConfig.StaticMAC != "" { + parsedMAC, macErr := net.ParseMAC(driverConfig.StaticMAC) + if macErr == nil && parsedMAC != nil { + createOpts.ContainerNetworkConfig.StaticMAC = &parsedMAC + } + } + } + } + // carefully add extra hosts (--add-host) if extraHostsErr := setExtraHosts(driverConfig.ExtraHosts, &createOpts); extraHostsErr != nil { return nil, nil, extraHostsErr