diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index c0caa006..a2845532 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -9,57 +9,67 @@ { "ImportPath": "github.com/containernetworking/cni/pkg/invoke", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/ip", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/ipam", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/ns", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/skel", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/testutils", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/types", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/types/020", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/types/current", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" + }, + { + "ImportPath": "github.com/containernetworking/cni/pkg/utils", + "Comment": "v0.5.0", + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/utils/hwaddr", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" + }, + { + "ImportPath": "github.com/containernetworking/cni/pkg/utils/sysctl", + "Comment": "v0.5.0", + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/containernetworking/cni/pkg/version", "Comment": "v0.5.0", - "Rev": "4ce9b019aab51b28a32ff6549784a69f9b209fe4" + "Rev": "1a9288c3c09cea4e580fdb1a636f1c5e185a391f" }, { "ImportPath": "github.com/coreos/go-iptables/iptables", diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/exec_test.go b/vendor/github.com/containernetworking/cni/pkg/invoke/exec_test.go index 7e804ab7..33ffc2de 100644 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/exec_test.go +++ b/vendor/github.com/containernetworking/cni/pkg/invoke/exec_test.go @@ -50,7 +50,7 @@ var _ = Describe("Executing a plugin, unit tests", func() { VersionDecoder: versionDecoder, } pluginPath = "/some/plugin/path" - netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.0" }`) + netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.1" }`) cniargs = &fakes.CNIArgs{} cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"} }) diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec_test.go b/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec_test.go index 5ab23ae5..5d759f24 100644 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec_test.go +++ b/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec_test.go @@ -58,7 +58,7 @@ var _ = Describe("RawExec", func() { "CNI_PATH=/some/bin/path", "CNI_IFNAME=some-eth0", } - stdin = []byte(`{"some":"stdin-json", "cniVersion": "0.3.0"}`) + stdin = []byte(`{"some":"stdin-json", "cniVersion": "0.3.1"}`) execer = &invoke.RawExec{} }) diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/link.go b/vendor/github.com/containernetworking/cni/pkg/ip/link.go index 6431bb41..a9842627 100644 --- a/vendor/github.com/containernetworking/cni/pkg/ip/link.go +++ b/vendor/github.com/containernetworking/cni/pkg/ip/link.go @@ -16,6 +16,7 @@ package ip import ( "crypto/rand" + "errors" "fmt" "net" "os" @@ -25,6 +26,10 @@ import ( "github.com/vishvananda/netlink" ) +var ( + ErrLinkNotFound = errors.New("link not found") +) + func makeVethPair(name, peer string, mtu int) (netlink.Link, error) { veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{ @@ -98,30 +103,38 @@ func RenameLink(curName, newName string) error { return err } -// SetupVeth sets up a virtual ethernet link. -// Should be in container netns, and will switch back to hostNS to set the host -// veth end up. -func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (hostVeth, contVeth netlink.Link, err error) { - var hostVethName string - hostVethName, contVeth, err = makeVeth(contVethName, mtu) +func ifaceFromNetlinkLink(l netlink.Link) net.Interface { + a := l.Attrs() + return net.Interface{ + Index: a.Index, + MTU: a.MTU, + Name: a.Name, + HardwareAddr: a.HardwareAddr, + Flags: a.Flags, + } +} + +// SetupVeth sets up a pair of virtual ethernet devices. +// Call SetupVeth from inside the container netns. It will create both veth +// devices and move the host-side veth into the provided hostNS namespace. +// On success, SetupVeth returns (hostVeth, containerVeth, nil) +func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) { + hostVethName, contVeth, err := makeVeth(contVethName, mtu) if err != nil { - return + return net.Interface{}, net.Interface{}, err } if err = netlink.LinkSetUp(contVeth); err != nil { - err = fmt.Errorf("failed to set %q up: %v", contVethName, err) - return + return net.Interface{}, net.Interface{}, fmt.Errorf("failed to set %q up: %v", contVethName, err) } - hostVeth, err = netlink.LinkByName(hostVethName) + hostVeth, err := netlink.LinkByName(hostVethName) if err != nil { - err = fmt.Errorf("failed to lookup %q: %v", hostVethName, err) - return + return net.Interface{}, net.Interface{}, fmt.Errorf("failed to lookup %q: %v", hostVethName, err) } if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil { - err = fmt.Errorf("failed to move veth to host netns: %v", err) - return + return net.Interface{}, net.Interface{}, fmt.Errorf("failed to move veth to host netns: %v", err) } err = hostNS.Do(func(_ ns.NetNS) error { @@ -135,7 +148,10 @@ func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (hostVeth, contVet } return nil }) - return + if err != nil { + return net.Interface{}, net.Interface{}, err + } + return ifaceFromNetlinkLink(hostVeth), ifaceFromNetlinkLink(contVeth), nil } // DelLinkByName removes an interface link. @@ -157,6 +173,9 @@ func DelLinkByName(ifName string) error { func DelLinkByNameAddr(ifName string, family int) (*net.IPNet, error) { iface, err := netlink.LinkByName(ifName) if err != nil { + if err != nil && err.Error() == "Link not found" { + return nil, ErrLinkNotFound + } return nil, fmt.Errorf("failed to lookup %q: %v", ifName, err) } diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/link_test.go b/vendor/github.com/containernetworking/cni/pkg/ip/link_test.go index 3df9ab8f..23182a54 100644 --- a/vendor/github.com/containernetworking/cni/pkg/ip/link_test.go +++ b/vendor/github.com/containernetworking/cni/pkg/ip/link_test.go @@ -46,8 +46,8 @@ var _ = Describe("Link", func() { hostNetNS ns.NetNS containerNetNS ns.NetNS ifaceCounter int = 0 - hostVeth netlink.Link - containerVeth netlink.Link + hostVeth net.Interface + containerVeth net.Interface hostVethName string containerVethName string @@ -78,8 +78,8 @@ var _ = Describe("Link", func() { } Expect(err).NotTo(HaveOccurred()) - hostVethName = hostVeth.Attrs().Name - containerVethName = containerVeth.Attrs().Name + hostVethName = hostVeth.Name + containerVethName = containerVeth.Name return nil }) @@ -98,7 +98,7 @@ var _ = Describe("Link", func() { containerVethFromName, err := netlink.LinkByName(containerVethName) Expect(err).NotTo(HaveOccurred()) - Expect(containerVethFromName.Attrs().Index).To(Equal(containerVeth.Attrs().Index)) + Expect(containerVethFromName.Attrs().Index).To(Equal(containerVeth.Index)) return nil }) @@ -108,7 +108,7 @@ var _ = Describe("Link", func() { hostVethFromName, err := netlink.LinkByName(hostVethName) Expect(err).NotTo(HaveOccurred()) - Expect(hostVethFromName.Attrs().Index).To(Equal(hostVeth.Attrs().Index)) + Expect(hostVethFromName.Attrs().Index).To(Equal(hostVeth.Index)) return nil }) @@ -127,6 +127,20 @@ var _ = Describe("Link", func() { }) }) + Context("deleting an non-existent device", func() { + It("returns known error", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + // This string should match the expected error codes in the cmdDel functions of some of the plugins + _, err := ip.DelLinkByNameAddr("THIS_DONT_EXIST", netlink.FAMILY_V4) + Expect(err).To(Equal(ip.ErrLinkNotFound)) + + return nil + }) + }) + }) + Context("when there is no name available for the host-side", func() { BeforeEach(func() { //adding different interface to container ns @@ -156,7 +170,7 @@ var _ = Describe("Link", func() { hostVeth, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS) Expect(err).NotTo(HaveOccurred()) - hostVethName = hostVeth.Attrs().Name + hostVethName = hostVeth.Name return nil }) diff --git a/vendor/github.com/containernetworking/cni/pkg/types/020/types.go b/vendor/github.com/containernetworking/cni/pkg/types/020/types.go index 666cfe93..2833aba7 100644 --- a/vendor/github.com/containernetworking/cni/pkg/types/020/types.go +++ b/vendor/github.com/containernetworking/cni/pkg/types/020/types.go @@ -23,9 +23,9 @@ import ( "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 @@ -39,7 +39,7 @@ func NewResult(data []byte) (types.Result, error) { func GetResult(r types.Result) (*Result, error) { // We expect version 0.1.0/0.2.0 results - result020, err := r.GetAsVersion(implementedSpecVersion) + result020, err := r.GetAsVersion(ImplementedSpecVersion) if err != nil { 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 type Result struct { - IP4 *IPConfig `json:"ip4,omitempty"` - IP6 *IPConfig `json:"ip6,omitempty"` - DNS types.DNS `json:"dns,omitempty"` + CNIVersion string `json:"cniVersion,omitempty"` + IP4 *IPConfig `json:"ip4,omitempty"` + IP6 *IPConfig `json:"ip6,omitempty"` + DNS types.DNS `json:"dns,omitempty"` } func (r *Result) Version() string { - return implementedSpecVersion + return ImplementedSpecVersion } func (r *Result) GetAsVersion(version string) (types.Result, error) { for _, supportedVersion := range SupportedVersions { if version == supportedVersion { + r.CNIVersion = version return r, nil } } diff --git a/vendor/github.com/containernetworking/cni/pkg/types/current/types.go b/vendor/github.com/containernetworking/cni/pkg/types/current/types.go index e686a9a7..b5715fe6 100644 --- a/vendor/github.com/containernetworking/cni/pkg/types/current/types.go +++ b/vendor/github.com/containernetworking/cni/pkg/types/current/types.go @@ -24,9 +24,9 @@ import ( "github.com/containernetworking/cni/pkg/types/020" ) -const implementedSpecVersion string = "0.3.0" +const ImplementedSpecVersion string = "0.3.1" -var SupportedVersions = []string{implementedSpecVersion} +var SupportedVersions = []string{"0.3.0", ImplementedSpecVersion} func NewResult(data []byte) (types.Result, error) { result := &Result{} @@ -37,7 +37,7 @@ func NewResult(data []byte) (types.Result, error) { } func GetResult(r types.Result) (*Result, error) { - resultCurrent, err := r.GetAsVersion(implementedSpecVersion) + resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion) if err != nil { return nil, err } @@ -63,8 +63,9 @@ func convertFrom020(result types.Result) (*Result, error) { } newResult := &Result{ - DNS: oldResult.DNS, - Routes: []*types.Route{}, + CNIVersion: ImplementedSpecVersion, + DNS: oldResult.DNS, + Routes: []*types.Route{}, } if oldResult.IP4 != nil { @@ -117,6 +118,7 @@ func convertFrom030(result types.Result) (*Result, error) { if !ok { return nil, fmt.Errorf("failed to convert result") } + newResult.CNIVersion = ImplementedSpecVersion return newResult, nil } @@ -129,11 +131,12 @@ func NewResultFromResult(result types.Result) (*Result, error) { } } } - return nil, fmt.Errorf("unsupported CNI result version %q", version) + return nil, fmt.Errorf("unsupported CNI result22 version %q", version) } // Result is what gets returned from the plugin (via stdout) to the caller type Result struct { + CNIVersion string `json:"cniVersion,omitempty"` Interfaces []*Interface `json:"interfaces,omitempty"` IPs []*IPConfig `json:"ips,omitempty"` Routes []*types.Route `json:"routes,omitempty"` @@ -143,7 +146,8 @@ type Result struct { // Convert to the older 0.2.0 CNI spec Result type func (r *Result) convertTo020() (*types020.Result, error) { oldResult := &types020.Result{ - DNS: r.DNS, + CNIVersion: types020.ImplementedSpecVersion, + DNS: r.DNS, } for _, ip := range r.IPs { @@ -189,17 +193,18 @@ func (r *Result) convertTo020() (*types020.Result, error) { } func (r *Result) Version() string { - return implementedSpecVersion + return ImplementedSpecVersion } func (r *Result) GetAsVersion(version string) (types.Result, error) { switch version { - case implementedSpecVersion: + case "0.3.0", ImplementedSpecVersion: + r.CNIVersion = version return r, nil case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]: return r.convertTo020() } - return nil, fmt.Errorf("cannot convert version 0.3.0 to %q", version) + return nil, fmt.Errorf("cannot convert version 0.3.x to %q", version) } func (r *Result) Print() error { diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/sysctl/sysctl_linux.go b/vendor/github.com/containernetworking/cni/pkg/utils/sysctl/sysctl_linux.go new file mode 100644 index 00000000..fe06d2d9 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/utils/sysctl/sysctl_linux.go @@ -0,0 +1,56 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sysctl + +import ( + "fmt" + "io/ioutil" + "path/filepath" + "strings" +) + +// Sysctl provides a method to set/get values from /proc/sys - in linux systems +// new interface to set/get values of variables formerly handled by sysctl syscall +// If optional `params` have only one string value - this function will +// set this value into corresponding sysctl variable +func Sysctl(name string, params ...string) (string, error) { + if len(params) > 1 { + return "", fmt.Errorf("unexcepted additional parameters") + } else if len(params) == 1 { + return setSysctl(name, params[0]) + } + return getSysctl(name) +} + +func getSysctl(name string) (string, error) { + fullName := filepath.Join("/proc/sys", strings.Replace(name, ".", "/", -1)) + fullName = filepath.Clean(fullName) + data, err := ioutil.ReadFile(fullName) + if err != nil { + return "", err + } + + return string(data[:len(data)-1]), nil +} + +func setSysctl(name, value string) (string, error) { + fullName := filepath.Join("/proc/sys", strings.Replace(name, ".", "/", -1)) + fullName = filepath.Clean(fullName) + if err := ioutil.WriteFile(fullName, []byte(value), 0644); err != nil { + return "", err + } + + return getSysctl(name) +} diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/utils.go b/vendor/github.com/containernetworking/cni/pkg/utils/utils.go new file mode 100644 index 00000000..33a2aa79 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/utils/utils.go @@ -0,0 +1,41 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "crypto/sha512" + "fmt" +) + +const ( + maxChainLength = 28 + chainPrefix = "CNI-" + prefixLength = len(chainPrefix) +) + +// Generates a chain name to be used with iptables. +// Ensures that the generated chain name is exactly +// maxChainLength chars in length +func FormatChainName(name string, id string) string { + chainBytes := sha512.Sum512([]byte(name + id)) + chain := fmt.Sprintf("%s%x", chainPrefix, chainBytes) + return chain[:maxChainLength] +} + +// FormatComment returns a comment used for easier +// rule identification within iptables. +func FormatComment(name string, id string) string { + return fmt.Sprintf("name: %q id: %q", name, id) +} diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/utils_suite_test.go b/vendor/github.com/containernetworking/cni/pkg/utils/utils_suite_test.go new file mode 100644 index 00000000..ee614a70 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/utils/utils_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestUtils(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Utils Suite") +} diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/utils_test.go b/vendor/github.com/containernetworking/cni/pkg/utils/utils_test.go new file mode 100644 index 00000000..d703de42 --- /dev/null +++ b/vendor/github.com/containernetworking/cni/pkg/utils/utils_test.go @@ -0,0 +1,51 @@ +// Copyright 2016 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Utils", func() { + It("must format a short name", func() { + chain := FormatChainName("test", "1234") + Expect(len(chain)).To(Equal(maxChainLength)) + Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8")) + }) + + It("must truncate a long name", func() { + chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + Expect(len(chain)).To(Equal(maxChainLength)) + Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe3")) + }) + + It("must be predictable", func() { + chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + Expect(len(chain1)).To(Equal(maxChainLength)) + Expect(len(chain2)).To(Equal(maxChainLength)) + Expect(chain1).To(Equal(chain2)) + }) + + It("must change when a character changes", func() { + chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235") + Expect(len(chain1)).To(Equal(maxChainLength)) + Expect(len(chain2)).To(Equal(maxChainLength)) + Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe3")) + Expect(chain1).NotTo(Equal(chain2)) + }) +}) diff --git a/vendor/github.com/containernetworking/cni/pkg/version/version.go b/vendor/github.com/containernetworking/cni/pkg/version/version.go index 7c589633..efe8ea87 100644 --- a/vendor/github.com/containernetworking/cni/pkg/version/version.go +++ b/vendor/github.com/containernetworking/cni/pkg/version/version.go @@ -24,7 +24,7 @@ import ( // Current reports the version of the CNI spec implemented by this library func Current() string { - return "0.3.0" + return "0.3.1" } // Legacy PluginInfo describes a plugin that is backwards compatible with the @@ -35,7 +35,7 @@ func Current() string { // Any future CNI spec versions which meet this definition should be added to // this list. var Legacy = PluginSupports("0.1.0", "0.2.0") -var All = PluginSupports("0.1.0", "0.2.0", "0.3.0") +var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1") var resultFactories = []struct { supportedVersions []string