Merge pull request #28 from dcbw/update-for-interface-change

pkg,plugins: update for Result struct Interface index changes
This commit is contained in:
Dan Williams 2017-07-05 10:29:05 -05:00 committed by GitHub
commit 74054da7c5
18 changed files with 174 additions and 80 deletions

28
Godeps/Godeps.json generated
View File

@ -8,38 +8,38 @@
"Deps": [ "Deps": [
{ {
"ImportPath": "github.com/containernetworking/cni/libcni", "ImportPath": "github.com/containernetworking/cni/libcni",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/containernetworking/cni/pkg/invoke", "ImportPath": "github.com/containernetworking/cni/pkg/invoke",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/containernetworking/cni/pkg/skel", "ImportPath": "github.com/containernetworking/cni/pkg/skel",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/containernetworking/cni/pkg/types", "ImportPath": "github.com/containernetworking/cni/pkg/types",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/containernetworking/cni/pkg/types/020", "ImportPath": "github.com/containernetworking/cni/pkg/types/020",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/containernetworking/cni/pkg/types/current", "ImportPath": "github.com/containernetworking/cni/pkg/types/current",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/containernetworking/cni/pkg/version", "ImportPath": "github.com/containernetworking/cni/pkg/version",
"Comment": "v0.5.2", "Comment": "v0.5.2-git49d814c",
"Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" "Rev": "49d814cf37bfea351a1caedd0c66825c9d6fca52"
}, },
{ {
"ImportPath": "github.com/coreos/go-iptables/iptables", "ImportPath": "github.com/coreos/go-iptables/iptables",

View File

@ -53,7 +53,11 @@ func ConfigureIface(ifName string, res *current.Result) error {
var v4gw, v6gw net.IP var v4gw, v6gw net.IP
for _, ipc := range res.IPs { for _, ipc := range res.IPs {
if int(ipc.Interface) >= len(res.Interfaces) || res.Interfaces[ipc.Interface].Name != ifName { if ipc.Interface == nil {
continue
}
intIdx := *ipc.Interface
if intIdx < 0 || intIdx >= len(res.Interfaces) || res.Interfaces[intIdx].Name != ifName {
// IP address is for a different interface // IP address is for a different interface
return fmt.Errorf("failed to add IP addr %v to %q: invalid interface index", ipc, ifName) return fmt.Errorf("failed to add IP addr %v to %q: invalid interface index", ipc, ifName)
} }

View File

@ -109,13 +109,13 @@ var _ = Describe("IPAM Operations", func() {
IPs: []*current.IPConfig{ IPs: []*current.IPConfig{
{ {
Version: "4", Version: "4",
Interface: 0, Interface: current.Int(0),
Address: *ipv4, Address: *ipv4,
Gateway: ipgw4, Gateway: ipgw4,
}, },
{ {
Version: "6", Version: "6",
Interface: 0, Interface: current.Int(0),
Address: *ipv6, Address: *ipv6,
Gateway: ipgw6, Gateway: ipgw6,
}, },
@ -226,7 +226,7 @@ var _ = Describe("IPAM Operations", func() {
}) })
It("returns an error when the interface index doesn't match the link name", func() { It("returns an error when the interface index doesn't match the link name", func() {
result.IPs[0].Interface = 1 result.IPs[0].Interface = current.Int(1)
err := originalNS.Do(func(ns.NetNS) error { err := originalNS.Do(func(ns.NetNS) error {
return ConfigureIface(LINK_NAME, result) return ConfigureIface(LINK_NAME, result)
}) })
@ -234,7 +234,15 @@ var _ = Describe("IPAM Operations", func() {
}) })
It("returns an error when the interface index is too big", func() { It("returns an error when the interface index is too big", func() {
result.IPs[0].Interface = 2 result.IPs[0].Interface = current.Int(2)
err := originalNS.Do(func(ns.NetNS) error {
return ConfigureIface(LINK_NAME, result)
})
Expect(err).To(HaveOccurred())
})
It("returns an error when the interface index is too small", func() {
result.IPs[0].Interface = current.Int(-1)
err := originalNS.Do(func(ns.NetNS) error { err := originalNS.Do(func(ns.NetNS) error {
return ConfigureIface(LINK_NAME, result) return ConfigureIface(LINK_NAME, result)
}) })
@ -255,4 +263,37 @@ var _ = Describe("IPAM Operations", func() {
}) })
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("does not panic when interface is not specified", func() {
result = &current.Result{
Interfaces: []*current.Interface{
{
Name: "eth0",
Mac: "00:11:22:33:44:55",
Sandbox: "/proc/3553/ns/net",
},
{
Name: "fake0",
Mac: "00:33:44:55:66:77",
Sandbox: "/proc/1234/ns/net",
},
},
IPs: []*current.IPConfig{
{
Version: "4",
Address: *ipv4,
Gateway: ipgw4,
},
{
Version: "6",
Address: *ipv6,
Gateway: ipgw6,
},
},
}
err := originalNS.Do(func(ns.NetNS) error {
return ConfigureIface(LINK_NAME, result)
})
Expect(err).NotTo(HaveOccurred())
})
}) })

View File

@ -86,27 +86,25 @@ var _ = Describe("host-local Operations", func() {
// Gomega is cranky about slices with different caps // Gomega is cranky about slices with different caps
Expect(*result.IPs[0]).To(Equal( Expect(*result.IPs[0]).To(Equal(
current.IPConfig{ current.IPConfig{
Version: "4", Version: "4",
Interface: 0, Address: mustCIDR("10.1.2.2/24"),
Address: mustCIDR("10.1.2.2/24"), Gateway: net.ParseIP("10.1.2.1"),
Gateway: net.ParseIP("10.1.2.1"),
})) }))
Expect(*result.IPs[1]).To(Equal( Expect(*result.IPs[1]).To(Equal(
current.IPConfig{ current.IPConfig{
Version: "6", Version: "6",
Interface: 0, Address: mustCIDR("2001:db8:1::2/64"),
Address: mustCIDR("2001:db8:1::2/64"), Gateway: net.ParseIP("2001:db8:1::1"),
Gateway: net.ParseIP("2001:db8:1::1"),
}, },
)) ))
Expect(len(result.IPs)).To(Equal(2)) Expect(len(result.IPs)).To(Equal(2))
Expect(result.Routes).To(Equal([]*types.Route{ Expect(result.Routes).To(Equal([]*types.Route{
&types.Route{Dst: mustCIDR("0.0.0.0/0"), GW: nil}, {Dst: mustCIDR("0.0.0.0/0"), GW: nil},
&types.Route{Dst: mustCIDR("::/0"), GW: nil}, {Dst: mustCIDR("::/0"), GW: nil},
&types.Route{Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("1.1.1.1")}, {Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("1.1.1.1")},
&types.Route{Dst: mustCIDR("2001:db8:2::0/64"), GW: net.ParseIP("2001:db8:3::1")}, {Dst: mustCIDR("2001:db8:2::0/64"), GW: net.ParseIP("2001:db8:3::1")},
})) }))
ipFilePath1 := filepath.Join(tmpDir, "mynet", "10.1.2.2") ipFilePath1 := filepath.Join(tmpDir, "mynet", "10.1.2.2")

View File

@ -100,7 +100,7 @@ func calcGateways(result *current.Result, n *NetConf) (*gwInfo, *gwInfo, error)
defaultNet.Mask = net.IPMask(defaultNet.IP) defaultNet.Mask = net.IPMask(defaultNet.IP)
// All IPs currently refer to the container interface // All IPs currently refer to the container interface
ipc.Interface = 2 ipc.Interface = current.Int(2)
// If not provided, calculate the gateway address corresponding // If not provided, calculate the gateway address corresponding
// to the selected IP address // to the selected IP address

View File

@ -159,7 +159,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
for _, ipc := range result.IPs { for _, ipc := range result.IPs {
// All addresses belong to the ipvlan interface // All addresses belong to the ipvlan interface
ipc.Interface = 0 ipc.Interface = current.Int(0)
} }
result.Interfaces = []*current.Interface{ipvlanInterface} result.Interfaces = []*current.Interface{ipvlanInterface}

View File

@ -179,7 +179,7 @@ func cmdAdd(args *skel.CmdArgs) error {
for _, ipc := range result.IPs { for _, ipc := range result.IPs {
// All addresses apply to the container macvlan interface // All addresses apply to the container macvlan interface
ipc.Interface = 0 ipc.Interface = current.Int(0)
} }
err = netns.Do(func(_ ns.NetNS) error { err = netns.Do(func(_ ns.NetNS) error {

View File

@ -75,7 +75,7 @@ func setupContainerVeth(netns ns.NetNS, ifName string, mtu int, pr *current.Resu
for _, ipc := range pr.IPs { for _, ipc := range pr.IPs {
// All addresses apply to the container veth interface // All addresses apply to the container veth interface
ipc.Interface = 1 ipc.Interface = current.Int(1)
} }
pr.Interfaces = []*current.Interface{hostInterface, containerInterface} pr.Interfaces = []*current.Interface{hostInterface, containerInterface}

View File

@ -148,7 +148,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
for _, ipc := range result.IPs { for _, ipc := range result.IPs {
// All addresses belong to the vlan interface // All addresses belong to the vlan interface
ipc.Interface = 0 ipc.Interface = current.Int(0)
} }
result.Interfaces = []*current.Interface{vlanInterface} result.Interfaces = []*current.Interface{vlanInterface}

View File

@ -164,9 +164,14 @@ func parseConfig(stdin []byte, ifName string) (*PortMapConf, error) {
} }
// Skip known non-sandbox interfaces // Skip known non-sandbox interfaces
intIdx := ip.Interface if ip.Interface != nil {
if intIdx >= 0 && intIdx < len(conf.PrevResult.Interfaces) && conf.PrevResult.Interfaces[intIdx].Name != ifName { intIdx := *ip.Interface
continue if intIdx >= 0 &&
intIdx < len(conf.PrevResult.Interfaces) &&
(conf.PrevResult.Interfaces[intIdx].Name != ifName ||
conf.PrevResult.Interfaces[intIdx].Sandbox == "") {
continue
}
} }
switch ip.Version { switch ip.Version {
case "6": case "6":

View File

@ -134,7 +134,8 @@ var _ = Describe("portmap integration tests", func() {
var contIP net.IP var contIP net.IP
for _, ip := range result.IPs { for _, ip := range result.IPs {
if result.Interfaces[ip.Interface].Sandbox == "" { intfIndex := *ip.Interface
if result.Interfaces[intfIndex].Sandbox == "" {
continue continue
} }
contIP = ip.Address.IP contIP = ip.Address.IP

View File

@ -124,6 +124,34 @@ var _ = Describe("portmapping configuration", func() {
_, err := parseConfig(configBytes, "container") _, err := parseConfig(configBytes, "container")
Expect(err).To(MatchError("Invalid host port number: 0")) Expect(err).To(MatchError("Invalid host port number: 0"))
}) })
It("Does not fail on missing prevResult interface index", func() {
configBytes := []byte(`{
"name": "test",
"type": "portmap",
"cniVersion": "0.3.1",
"runtimeConfig": {
"portMappings": [
{ "hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
]
},
"conditionsV4": ["a", "b"],
"prevResult": {
"interfaces": [
{"name": "host"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.1/24",
"gateway": "10.0.0.1"
}
]
}
}`)
_, err := parseConfig(configBytes, "container")
Expect(err).NotTo(HaveOccurred())
})
}) })
Describe("Generating chains", func() { Describe("Generating chains", func() {

View File

@ -106,7 +106,10 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
} else { } else {
for _, ip := range conf.PrevResult.IPs { for _, ip := range conf.PrevResult.IPs {
intIdx := ip.Interface if ip.Interface == nil {
continue
}
intIdx := *ip.Interface
// Every IP is indexed in to the interfaces array, with "-1" standing // Every IP is indexed in to the interfaces array, with "-1" standing
// for an unknown interface (which we'll assume to be Container-side // for an unknown interface (which we'll assume to be Container-side
// Skip all IPs we know belong to an interface with the wrong name. // Skip all IPs we know belong to an interface with the wrong name.

View File

@ -57,13 +57,16 @@ func (args *Args) AsEnv() []string {
pluginArgsStr = stringify(args.PluginArgs) pluginArgsStr = stringify(args.PluginArgs)
} }
env = append(env, // Ensure that the custom values are first, so any value present in
"CNI_COMMAND="+args.Command, // the process environment won't override them.
"CNI_CONTAINERID="+args.ContainerID, env = append([]string{
"CNI_NETNS="+args.NetNS, "CNI_COMMAND=" + args.Command,
"CNI_ARGS="+pluginArgsStr, "CNI_CONTAINERID=" + args.ContainerID,
"CNI_IFNAME="+args.IfName, "CNI_NETNS=" + args.NetNS,
"CNI_PATH="+args.Path) "CNI_ARGS=" + pluginArgsStr,
"CNI_IFNAME=" + args.IfName,
"CNI_PATH=" + args.Path,
}, env...)
return env return env
} }

View File

@ -50,13 +50,9 @@ func pluginErr(err error, output []byte) error {
if _, ok := err.(*exec.ExitError); ok { if _, ok := err.(*exec.ExitError); ok {
emsg := types.Error{} emsg := types.Error{}
if perr := json.Unmarshal(output, &emsg); perr != nil { if perr := json.Unmarshal(output, &emsg); perr != nil {
return fmt.Errorf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr) emsg.Msg = fmt.Sprintf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr)
} }
details := "" return &emsg
if emsg.Details != "" {
details = fmt.Sprintf("; %v", emsg.Details)
}
return fmt.Errorf("%v%v", emsg.Msg, details)
} }
return err return err

View File

@ -23,9 +23,9 @@ import (
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
) )
const implementedSpecVersion string = "0.2.0" const ImplementedSpecVersion string = "0.2.0"
var SupportedVersions = []string{"", "0.1.0", implementedSpecVersion} var SupportedVersions = []string{"", "0.1.0", ImplementedSpecVersion}
// Compatibility types for CNI version 0.1.0 and 0.2.0 // Compatibility types for CNI version 0.1.0 and 0.2.0
@ -39,7 +39,7 @@ func NewResult(data []byte) (types.Result, error) {
func GetResult(r types.Result) (*Result, error) { func GetResult(r types.Result) (*Result, error) {
// We expect version 0.1.0/0.2.0 results // We expect version 0.1.0/0.2.0 results
result020, err := r.GetAsVersion(implementedSpecVersion) result020, err := r.GetAsVersion(ImplementedSpecVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -52,18 +52,20 @@ func GetResult(r types.Result) (*Result, error) {
// Result is what gets returned from the plugin (via stdout) to the caller // Result is what gets returned from the plugin (via stdout) to the caller
type Result struct { type Result struct {
IP4 *IPConfig `json:"ip4,omitempty"` CNIVersion string `json:"cniVersion,omitempty"`
IP6 *IPConfig `json:"ip6,omitempty"` IP4 *IPConfig `json:"ip4,omitempty"`
DNS types.DNS `json:"dns,omitempty"` IP6 *IPConfig `json:"ip6,omitempty"`
DNS types.DNS `json:"dns,omitempty"`
} }
func (r *Result) Version() string { func (r *Result) Version() string {
return implementedSpecVersion return ImplementedSpecVersion
} }
func (r *Result) GetAsVersion(version string) (types.Result, error) { func (r *Result) GetAsVersion(version string) (types.Result, error) {
for _, supportedVersion := range SupportedVersions { for _, supportedVersion := range SupportedVersions {
if version == supportedVersion { if version == supportedVersion {
r.CNIVersion = version
return r, nil return r, nil
} }
} }

View File

@ -24,9 +24,9 @@ import (
"github.com/containernetworking/cni/pkg/types/020" "github.com/containernetworking/cni/pkg/types/020"
) )
const implementedSpecVersion string = "0.3.1" const ImplementedSpecVersion string = "0.3.1"
var SupportedVersions = []string{"0.3.0", implementedSpecVersion} var SupportedVersions = []string{"0.3.0", ImplementedSpecVersion}
func NewResult(data []byte) (types.Result, error) { func NewResult(data []byte) (types.Result, error) {
result := &Result{} result := &Result{}
@ -37,7 +37,7 @@ func NewResult(data []byte) (types.Result, error) {
} }
func GetResult(r types.Result) (*Result, error) { func GetResult(r types.Result) (*Result, error) {
resultCurrent, err := r.GetAsVersion(implementedSpecVersion) resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -63,16 +63,16 @@ func convertFrom020(result types.Result) (*Result, error) {
} }
newResult := &Result{ newResult := &Result{
DNS: oldResult.DNS, CNIVersion: ImplementedSpecVersion,
Routes: []*types.Route{}, DNS: oldResult.DNS,
Routes: []*types.Route{},
} }
if oldResult.IP4 != nil { if oldResult.IP4 != nil {
newResult.IPs = append(newResult.IPs, &IPConfig{ newResult.IPs = append(newResult.IPs, &IPConfig{
Version: "4", Version: "4",
Interface: -1, Address: oldResult.IP4.IP,
Address: oldResult.IP4.IP, Gateway: oldResult.IP4.Gateway,
Gateway: oldResult.IP4.Gateway,
}) })
for _, route := range oldResult.IP4.Routes { for _, route := range oldResult.IP4.Routes {
gw := route.GW gw := route.GW
@ -88,10 +88,9 @@ func convertFrom020(result types.Result) (*Result, error) {
if oldResult.IP6 != nil { if oldResult.IP6 != nil {
newResult.IPs = append(newResult.IPs, &IPConfig{ newResult.IPs = append(newResult.IPs, &IPConfig{
Version: "6", Version: "6",
Interface: -1, Address: oldResult.IP6.IP,
Address: oldResult.IP6.IP, Gateway: oldResult.IP6.Gateway,
Gateway: oldResult.IP6.Gateway,
}) })
for _, route := range oldResult.IP6.Routes { for _, route := range oldResult.IP6.Routes {
gw := route.GW gw := route.GW
@ -117,6 +116,7 @@ func convertFrom030(result types.Result) (*Result, error) {
if !ok { if !ok {
return nil, fmt.Errorf("failed to convert result") return nil, fmt.Errorf("failed to convert result")
} }
newResult.CNIVersion = ImplementedSpecVersion
return newResult, nil return newResult, nil
} }
@ -134,6 +134,7 @@ func NewResultFromResult(result types.Result) (*Result, error) {
// Result is what gets returned from the plugin (via stdout) to the caller // Result is what gets returned from the plugin (via stdout) to the caller
type Result struct { type Result struct {
CNIVersion string `json:"cniVersion,omitempty"`
Interfaces []*Interface `json:"interfaces,omitempty"` Interfaces []*Interface `json:"interfaces,omitempty"`
IPs []*IPConfig `json:"ips,omitempty"` IPs []*IPConfig `json:"ips,omitempty"`
Routes []*types.Route `json:"routes,omitempty"` Routes []*types.Route `json:"routes,omitempty"`
@ -143,7 +144,8 @@ type Result struct {
// Convert to the older 0.2.0 CNI spec Result type // Convert to the older 0.2.0 CNI spec Result type
func (r *Result) convertTo020() (*types020.Result, error) { func (r *Result) convertTo020() (*types020.Result, error) {
oldResult := &types020.Result{ oldResult := &types020.Result{
DNS: r.DNS, CNIVersion: types020.ImplementedSpecVersion,
DNS: r.DNS,
} }
for _, ip := range r.IPs { for _, ip := range r.IPs {
@ -189,12 +191,13 @@ func (r *Result) convertTo020() (*types020.Result, error) {
} }
func (r *Result) Version() string { func (r *Result) Version() string {
return implementedSpecVersion return ImplementedSpecVersion
} }
func (r *Result) GetAsVersion(version string) (types.Result, error) { func (r *Result) GetAsVersion(version string) (types.Result, error) {
switch version { switch version {
case "0.3.0", implementedSpecVersion: case "0.3.0", ImplementedSpecVersion:
r.CNIVersion = version
return r, nil return r, nil
case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]: case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
return r.convertTo020() return r.convertTo020()
@ -244,12 +247,18 @@ func (i *Interface) String() string {
return fmt.Sprintf("%+v", *i) return fmt.Sprintf("%+v", *i)
} }
// Int returns a pointer to the int value passed in. Used to
// set the IPConfig.Interface field.
func Int(v int) *int {
return &v
}
// IPConfig contains values necessary to configure an IP address on an interface // IPConfig contains values necessary to configure an IP address on an interface
type IPConfig struct { type IPConfig struct {
// IP version, either "4" or "6" // IP version, either "4" or "6"
Version string Version string
// Index into Result structs Interfaces list // Index into Result structs Interfaces list
Interface int Interface *int
Address net.IPNet Address net.IPNet
Gateway net.IP Gateway net.IP
} }
@ -261,7 +270,7 @@ func (i *IPConfig) String() string {
// JSON (un)marshallable types // JSON (un)marshallable types
type ipConfig struct { type ipConfig struct {
Version string `json:"version"` Version string `json:"version"`
Interface int `json:"interface,omitempty"` Interface *int `json:"interface,omitempty"`
Address types.IPNet `json:"address"` Address types.IPNet `json:"address"`
Gateway net.IP `json:"gateway,omitempty"` Gateway net.IP `json:"gateway,omitempty"`
} }

View File

@ -136,7 +136,11 @@ type Error struct {
} }
func (e *Error) Error() string { func (e *Error) Error() string {
return e.Msg details := ""
if e.Details != "" {
details = fmt.Sprintf("; %v", e.Details)
}
return fmt.Sprintf("%v%v", e.Msg, details)
} }
func (e *Error) Print() error { func (e *Error) Print() error {