Skip to content

Commit

Permalink
Resolve hashicorp#293 and hashicorp#358 adding ipv6_address, ipv4_add…
Browse files Browse the repository at this point in the history
…ress, static_ips and static_mac options for podman tasks.

Podman API version checks whether to set the properties directly or whether to use the new PerNetworkOptions framework.

ipv6_address and ipv4_address are provided for backwards compatibility, and for compatibility with docker. For Podman 4.0.0 these are merged into static_ips and sent as a PerNetorkOptions entry for the default network.
Added API version check, static mac support, new array-based option for static IPs to match the podman API
  • Loading branch information
Andrew Cassidy authored and zandeez committed Jul 2, 2024
1 parent 7c74d43 commit 2320cbb
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 3 deletions.
20 changes: 20 additions & 0 deletions api/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down
14 changes: 11 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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"`
Expand Down
76 changes: 76 additions & 0 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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, err := net.ParseMAC(driverConfig.StaticMAC)
if err == 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, err := net.ParseMAC(driverConfig.StaticMAC)
if err == 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
Expand Down

0 comments on commit 2320cbb

Please sign in to comment.