types: make Result an interface and move existing Result to separate package
This commit is contained in:
parent
cb4cd0e12c
commit
befb95977c
@ -42,10 +42,10 @@ type NetworkConfigList struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CNI interface {
|
type CNI interface {
|
||||||
AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (*types.Result, error)
|
AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
|
||||||
DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
|
DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
|
||||||
|
|
||||||
AddNetwork(net *NetworkConfig, rt *RuntimeConf) (*types.Result, error)
|
AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||||
DelNetwork(net *NetworkConfig, rt *RuntimeConf) error
|
DelNetwork(net *NetworkConfig, rt *RuntimeConf) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ type CNIConfig struct {
|
|||||||
// CNIConfig implements the CNI interface
|
// CNIConfig implements the CNI interface
|
||||||
var _ CNI = &CNIConfig{}
|
var _ CNI = &CNIConfig{}
|
||||||
|
|
||||||
func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult *types.Result) (*NetworkConfig, error) {
|
func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult types.Result) (*NetworkConfig, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Ensure every config uses the same name and version
|
// Ensure every config uses the same name and version
|
||||||
@ -81,8 +81,8 @@ func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult *ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddNetworkList executes a sequence of plugins with the ADD command
|
// AddNetworkList executes a sequence of plugins with the ADD command
|
||||||
func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (*types.Result, error) {
|
func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
|
||||||
var prevResult *types.Result
|
var prevResult types.Result
|
||||||
for _, net := range list.Plugins {
|
for _, net := range list.Plugins {
|
||||||
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -127,7 +127,7 @@ func (c *CNIConfig) DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddNetwork executes the plugin with the ADD command
|
// AddNetwork executes the plugin with the ADD command
|
||||||
func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (*types.Result, error) {
|
func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
||||||
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/libcni"
|
"github.com/containernetworking/cni/libcni"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
|
noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@ -116,11 +117,14 @@ var _ = Describe("Invoking plugins", func() {
|
|||||||
|
|
||||||
Describe("AddNetwork", func() {
|
Describe("AddNetwork", func() {
|
||||||
It("executes the plugin with command ADD", func() {
|
It("executes the plugin with command ADD", func() {
|
||||||
result, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
|
r, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
Expect(result).To(Equal(&types.Result{
|
result, err := current.GetResult(r)
|
||||||
IP4: &types.IPConfig{
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(result).To(Equal(¤t.Result{
|
||||||
|
IP4: ¤t.IPConfig{
|
||||||
IP: net.IPNet{
|
IP: net.IPNet{
|
||||||
IP: net.ParseIP("10.1.2.3"),
|
IP: net.ParseIP("10.1.2.3"),
|
||||||
Mask: net.IPv4Mask(255, 255, 255, 0),
|
Mask: net.IPv4Mask(255, 255, 255, 0),
|
||||||
@ -263,12 +267,15 @@ var _ = Describe("Invoking plugins", func() {
|
|||||||
|
|
||||||
Describe("AddNetworkList", func() {
|
Describe("AddNetworkList", func() {
|
||||||
It("executes all plugins with command ADD and returns an intermediate result", func() {
|
It("executes all plugins with command ADD and returns an intermediate result", func() {
|
||||||
result, err := cniConfig.AddNetworkList(netConfigList, runtimeConfig)
|
r, err := cniConfig.AddNetworkList(netConfigList, runtimeConfig)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
Expect(result).To(Equal(&types.Result{
|
result, err := current.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(result).To(Equal(¤t.Result{
|
||||||
// IP4 added by first plugin
|
// IP4 added by first plugin
|
||||||
IP4: &types.IPConfig{
|
IP4: ¤t.IPConfig{
|
||||||
IP: net.IPNet{
|
IP: net.IPNet{
|
||||||
IP: net.ParseIP("10.1.2.3"),
|
IP: net.ParseIP("10.1.2.3"),
|
||||||
Mask: net.IPv4Mask(255, 255, 255, 0),
|
Mask: net.IPv4Mask(255, 255, 255, 0),
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DelegateAdd(delegatePlugin string, netconf []byte) (*types.Result, error) {
|
func DelegateAdd(delegatePlugin string, netconf []byte) (types.Result, error) {
|
||||||
if os.Getenv("CNI_COMMAND") != "ADD" {
|
if os.Getenv("CNI_COMMAND") != "ADD" {
|
||||||
return nil, fmt.Errorf("CNI_COMMAND is not ADD")
|
return nil, fmt.Errorf("CNI_COMMAND is not ADD")
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
package invoke
|
package invoke
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -23,7 +22,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (*types.Result, error) {
|
func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) {
|
||||||
return defaultPluginExec.WithResult(pluginPath, netconf, args)
|
return defaultPluginExec.WithResult(pluginPath, netconf, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,15 +48,20 @@ type PluginExec struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs) (*types.Result, error) {
|
func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) {
|
||||||
stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
|
stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &types.Result{}
|
// Plugin must return result in same version as specified in netconf
|
||||||
err = json.Unmarshal(stdoutBytes, res)
|
versionDecoder := &version.ConfigDecoder{}
|
||||||
return res, err
|
confVersion, err := versionDecoder.Decode(netconf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return version.NewResult(confVersion, stdoutBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIArgs) error {
|
func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIArgs) error {
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/invoke"
|
"github.com/containernetworking/cni/pkg/invoke"
|
||||||
"github.com/containernetworking/cni/pkg/invoke/fakes"
|
"github.com/containernetworking/cni/pkg/invoke/fakes"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@ -56,7 +57,10 @@ var _ = Describe("Executing a plugin, unit tests", func() {
|
|||||||
|
|
||||||
Describe("returning a result", func() {
|
Describe("returning a result", func() {
|
||||||
It("unmarshals the result bytes into the Result type", func() {
|
It("unmarshals the result bytes into the Result type", func() {
|
||||||
result, err := pluginExec.WithResult(pluginPath, netconf, cniargs)
|
r, err := pluginExec.WithResult(pluginPath, netconf, cniargs)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
result, err := current.GetResult(r)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(result.IP4.IP.IP.String()).To(Equal("1.2.3.4"))
|
Expect(result.IP4.IP.IP.String()).To(Equal("1.2.3.4"))
|
||||||
})
|
})
|
||||||
|
@ -21,11 +21,12 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/invoke"
|
"github.com/containernetworking/cni/pkg/invoke"
|
||||||
"github.com/containernetworking/cni/pkg/ip"
|
"github.com/containernetworking/cni/pkg/ip"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
|
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExecAdd(plugin string, netconf []byte) (*types.Result, error) {
|
func ExecAdd(plugin string, netconf []byte) (types.Result, error) {
|
||||||
return invoke.DelegateAdd(plugin, netconf)
|
return invoke.DelegateAdd(plugin, netconf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ func ExecDel(plugin string, netconf []byte) error {
|
|||||||
|
|
||||||
// ConfigureIface takes the result of IPAM plugin and
|
// ConfigureIface takes the result of IPAM plugin and
|
||||||
// applies to the ifName interface
|
// applies to the ifName interface
|
||||||
func ConfigureIface(ifName string, res *types.Result) error {
|
func ConfigureIface(ifName string, res *current.Result) error {
|
||||||
link, err := netlink.LinkByName(ifName)
|
link, err := netlink.LinkByName(ifName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to lookup %q: %v", ifName, err)
|
return fmt.Errorf("failed to lookup %q: %v", ifName, err)
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
package testutils
|
package testutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func envCleanup() {
|
func envCleanup() {
|
||||||
@ -29,7 +29,7 @@ func envCleanup() {
|
|||||||
os.Unsetenv("CNI_IFNAME")
|
os.Unsetenv("CNI_IFNAME")
|
||||||
}
|
}
|
||||||
|
|
||||||
func CmdAddWithResult(cniNetns, cniIfname string, conf []byte, f func() error) (*types.Result, []byte, error) {
|
func CmdAddWithResult(cniNetns, cniIfname string, conf []byte, f func() error) (types.Result, []byte, error) {
|
||||||
os.Setenv("CNI_COMMAND", "ADD")
|
os.Setenv("CNI_COMMAND", "ADD")
|
||||||
os.Setenv("CNI_PATH", os.Getenv("PATH"))
|
os.Setenv("CNI_PATH", os.Getenv("PATH"))
|
||||||
os.Setenv("CNI_NETNS", cniNetns)
|
os.Setenv("CNI_NETNS", cniNetns)
|
||||||
@ -57,13 +57,19 @@ func CmdAddWithResult(cniNetns, cniIfname string, conf []byte, f func() error) (
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := types.Result{}
|
// Plugin must return result in same version as specified in netconf
|
||||||
err = json.Unmarshal(out, &result)
|
versionDecoder := &version.ConfigDecoder{}
|
||||||
|
confVersion, err := versionDecoder.Decode(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &result, out, nil
|
result, err := version.NewResult(confVersion, out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CmdDelWithResult(cniNetns, cniIfname string, f func() error) error {
|
func CmdDelWithResult(cniNetns, cniIfname string, f func() error) error {
|
||||||
|
157
pkg/types/current/types.go
Normal file
157
pkg/types/current/types.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// 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 current
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const implementedSpecVersion string = "0.2.0"
|
||||||
|
|
||||||
|
var SupportedVersions = []string{"", "0.1.0", implementedSpecVersion}
|
||||||
|
|
||||||
|
func NewResult(data []byte) (types.Result, error) {
|
||||||
|
result := &Result{}
|
||||||
|
if err := json.Unmarshal(data, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetResult(r types.Result) (*Result, error) {
|
||||||
|
newResult, err := r.GetAsVersion(implementedSpecVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, ok := newResult.(*Result)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to convert result")
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultConverters = []struct {
|
||||||
|
versions []string
|
||||||
|
convert func(types.Result) (*Result, error)
|
||||||
|
}{
|
||||||
|
{SupportedVersions, convertFrom020},
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFrom020(result types.Result) (*Result, error) {
|
||||||
|
newResult, ok := result.(*Result)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to convert result")
|
||||||
|
}
|
||||||
|
return newResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResultFromResult(result types.Result) (*Result, error) {
|
||||||
|
version := result.Version()
|
||||||
|
for _, converter := range resultConverters {
|
||||||
|
for _, supportedVersion := range converter.versions {
|
||||||
|
if version == supportedVersion {
|
||||||
|
return converter.convert(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unsupported CNI result version %q", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Version() string {
|
||||||
|
return implementedSpecVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
||||||
|
for _, supportedVersion := range SupportedVersions {
|
||||||
|
if version == supportedVersion {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot convert version %q to %s", SupportedVersions, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Print() error {
|
||||||
|
data, err := json.MarshalIndent(r, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = os.Stdout.Write(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a formatted string in the form of "[IP4: $1,][ IP6: $2,] DNS: $3" where
|
||||||
|
// $1 represents the receiver's IPv4, $2 represents the receiver's IPv6 and $3 the
|
||||||
|
// receiver's DNS. If $1 or $2 are nil, they won't be present in the returned string.
|
||||||
|
func (r *Result) String() string {
|
||||||
|
var str string
|
||||||
|
if r.IP4 != nil {
|
||||||
|
str = fmt.Sprintf("IP4:%+v, ", *r.IP4)
|
||||||
|
}
|
||||||
|
if r.IP6 != nil {
|
||||||
|
str += fmt.Sprintf("IP6:%+v, ", *r.IP6)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%sDNS:%+v", str, r.DNS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPConfig contains values necessary to configure an interface
|
||||||
|
type IPConfig struct {
|
||||||
|
IP net.IPNet
|
||||||
|
Gateway net.IP
|
||||||
|
Routes []types.Route
|
||||||
|
}
|
||||||
|
|
||||||
|
// net.IPNet is not JSON (un)marshallable so this duality is needed
|
||||||
|
// for our custom IPNet type
|
||||||
|
|
||||||
|
// JSON (un)marshallable types
|
||||||
|
type ipConfig struct {
|
||||||
|
IP types.IPNet `json:"ip"`
|
||||||
|
Gateway net.IP `json:"gateway,omitempty"`
|
||||||
|
Routes []types.Route `json:"routes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IPConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
ipc := ipConfig{
|
||||||
|
IP: types.IPNet(c.IP),
|
||||||
|
Gateway: c.Gateway,
|
||||||
|
Routes: c.Routes,
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(ipc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *IPConfig) UnmarshalJSON(data []byte) error {
|
||||||
|
ipc := ipConfig{}
|
||||||
|
if err := json.Unmarshal(data, &ipc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.IP = net.IPNet(ipc.IP)
|
||||||
|
c.Gateway = ipc.Gateway
|
||||||
|
c.Routes = ipc.Routes
|
||||||
|
return nil
|
||||||
|
}
|
27
pkg/types/current/types_suite_test.go
Normal file
27
pkg/types/current/types_suite_test.go
Normal file
@ -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 current_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTypes010(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "0.1.0 Types Suite")
|
||||||
|
}
|
128
pkg/types/current/types_test.go
Normal file
128
pkg/types/current/types_test.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// 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 current_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Ensures compatibility with the 0.1.0 spec", func() {
|
||||||
|
It("correctly encodes a 0.1.0 Result", func() {
|
||||||
|
ipv4, err := types.ParseCIDR("1.2.3.30/24")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(ipv4).NotTo(BeNil())
|
||||||
|
|
||||||
|
routegwv4, routev4, err := net.ParseCIDR("15.5.6.8/24")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(routev4).NotTo(BeNil())
|
||||||
|
Expect(routegwv4).NotTo(BeNil())
|
||||||
|
|
||||||
|
ipv6, err := types.ParseCIDR("abcd:1234:ffff::cdde/64")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(ipv6).NotTo(BeNil())
|
||||||
|
|
||||||
|
routegwv6, routev6, err := net.ParseCIDR("1111:dddd::aaaa/80")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(routev6).NotTo(BeNil())
|
||||||
|
Expect(routegwv6).NotTo(BeNil())
|
||||||
|
|
||||||
|
// Set every field of the struct to ensure source compatibility
|
||||||
|
res := current.Result{
|
||||||
|
IP4: ¤t.IPConfig{
|
||||||
|
IP: *ipv4,
|
||||||
|
Gateway: net.ParseIP("1.2.3.1"),
|
||||||
|
Routes: []types.Route{
|
||||||
|
{Dst: *routev4, GW: routegwv4},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
IP6: ¤t.IPConfig{
|
||||||
|
IP: *ipv6,
|
||||||
|
Gateway: net.ParseIP("abcd:1234:ffff::1"),
|
||||||
|
Routes: []types.Route{
|
||||||
|
{Dst: *routev6, GW: routegwv6},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DNS: types.DNS{
|
||||||
|
Nameservers: []string{"1.2.3.4", "1::cafe"},
|
||||||
|
Domain: "acompany.com",
|
||||||
|
Search: []string{"somedomain.com", "otherdomain.net"},
|
||||||
|
Options: []string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(res.String()).To(Equal("IP4:{IP:{IP:1.2.3.30 Mask:ffffff00} Gateway:1.2.3.1 Routes:[{Dst:{IP:15.5.6.0 Mask:ffffff00} GW:15.5.6.8}]}, IP6:{IP:{IP:abcd:1234:ffff::cdde Mask:ffffffffffffffff0000000000000000} Gateway:abcd:1234:ffff::1 Routes:[{Dst:{IP:1111:dddd:: Mask:ffffffffffffffffffff000000000000} GW:1111:dddd::aaaa}]}, DNS:{Nameservers:[1.2.3.4 1::cafe] Domain:acompany.com Search:[somedomain.com otherdomain.net] Options:[foo bar]}"))
|
||||||
|
|
||||||
|
// Redirect stdout to capture JSON result
|
||||||
|
oldStdout := os.Stdout
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
os.Stdout = w
|
||||||
|
err = res.Print()
|
||||||
|
w.Close()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// parse the result
|
||||||
|
out, err := ioutil.ReadAll(r)
|
||||||
|
os.Stdout = oldStdout
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(string(out)).To(Equal(`{
|
||||||
|
"ip4": {
|
||||||
|
"ip": "1.2.3.30/24",
|
||||||
|
"gateway": "1.2.3.1",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"dst": "15.5.6.0/24",
|
||||||
|
"gw": "15.5.6.8"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ip6": {
|
||||||
|
"ip": "abcd:1234:ffff::cdde/64",
|
||||||
|
"gateway": "abcd:1234:ffff::1",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"dst": "1111:dddd::/80",
|
||||||
|
"gw": "1111:dddd::aaaa"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dns": {
|
||||||
|
"nameservers": [
|
||||||
|
"1.2.3.4",
|
||||||
|
"1::cafe"
|
||||||
|
],
|
||||||
|
"domain": "acompany.com",
|
||||||
|
"search": [
|
||||||
|
"somedomain.com",
|
||||||
|
"otherdomain.net"
|
||||||
|
],
|
||||||
|
"options": [
|
||||||
|
"foo",
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`))
|
||||||
|
})
|
||||||
|
})
|
@ -16,7 +16,6 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@ -61,7 +60,6 @@ type NetConf struct {
|
|||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
PrevResult *Result `json:"prevResult,omitempty"`
|
|
||||||
IPAM struct {
|
IPAM struct {
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
} `json:"ipam,omitempty"`
|
} `json:"ipam,omitempty"`
|
||||||
@ -76,36 +74,31 @@ type NetConfList struct {
|
|||||||
Plugins []*NetConf `json:"plugins,omitempty"`
|
Plugins []*NetConf `json:"plugins,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result is what gets returned from the plugin (via stdout) to the caller
|
type ResultFactoryFunc func([]byte) (Result, error)
|
||||||
type Result struct {
|
|
||||||
IP4 *IPConfig `json:"ip4,omitempty"`
|
// Result is an interface that provides the result of plugin execution
|
||||||
IP6 *IPConfig `json:"ip6,omitempty"`
|
type Result interface {
|
||||||
DNS DNS `json:"dns,omitempty"`
|
// The highest CNI specification result verison the result supports
|
||||||
|
// without having to convert
|
||||||
|
Version() string
|
||||||
|
|
||||||
|
// Returns the result converted into the requested CNI specification
|
||||||
|
// result version, or an error if conversion failed
|
||||||
|
GetAsVersion(version string) (Result, error)
|
||||||
|
|
||||||
|
// Prints the result in JSON format to stdout
|
||||||
|
Print() error
|
||||||
|
|
||||||
|
// Returns a JSON string representation of the result
|
||||||
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) Print() error {
|
func PrintResult(result Result, version string) error {
|
||||||
return prettyPrint(r)
|
newResult, err := result.GetAsVersion(version)
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
// String returns a formatted string in the form of "[IP4: $1,][ IP6: $2,] DNS: $3" where
|
|
||||||
// $1 represents the receiver's IPv4, $2 represents the receiver's IPv6 and $3 the
|
|
||||||
// receiver's DNS. If $1 or $2 are nil, they won't be present in the returned string.
|
|
||||||
func (r *Result) String() string {
|
|
||||||
var str string
|
|
||||||
if r.IP4 != nil {
|
|
||||||
str = fmt.Sprintf("IP4:%+v, ", *r.IP4)
|
|
||||||
}
|
}
|
||||||
if r.IP6 != nil {
|
return newResult.Print()
|
||||||
str += fmt.Sprintf("IP6:%+v, ", *r.IP6)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%sDNS:%+v", str, r.DNS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPConfig contains values necessary to configure an interface
|
|
||||||
type IPConfig struct {
|
|
||||||
IP net.IPNet
|
|
||||||
Gateway net.IP
|
|
||||||
Routes []Route
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNS contains values interesting for DNS resolvers
|
// DNS contains values interesting for DNS resolvers
|
||||||
@ -147,39 +140,11 @@ func (e *Error) Print() error {
|
|||||||
// for our custom IPNet type
|
// for our custom IPNet type
|
||||||
|
|
||||||
// JSON (un)marshallable types
|
// JSON (un)marshallable types
|
||||||
type ipConfig struct {
|
|
||||||
IP IPNet `json:"ip"`
|
|
||||||
Gateway net.IP `json:"gateway,omitempty"`
|
|
||||||
Routes []Route `json:"routes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type route struct {
|
type route struct {
|
||||||
Dst IPNet `json:"dst"`
|
Dst IPNet `json:"dst"`
|
||||||
GW net.IP `json:"gw,omitempty"`
|
GW net.IP `json:"gw,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *IPConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
ipc := ipConfig{
|
|
||||||
IP: IPNet(c.IP),
|
|
||||||
Gateway: c.Gateway,
|
|
||||||
Routes: c.Routes,
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(ipc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *IPConfig) UnmarshalJSON(data []byte) error {
|
|
||||||
ipc := ipConfig{}
|
|
||||||
if err := json.Unmarshal(data, &ipc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.IP = net.IPNet(ipc.IP)
|
|
||||||
c.Gateway = ipc.Gateway
|
|
||||||
c.Routes = ipc.Routes
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Route) UnmarshalJSON(data []byte) error {
|
func (r *Route) UnmarshalJSON(data []byte) error {
|
||||||
rt := route{}
|
rt := route{}
|
||||||
if err := json.Unmarshal(data, &rt); err != nil {
|
if err := json.Unmarshal(data, &rt); err != nil {
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version/testhelpers"
|
"github.com/containernetworking/cni/pkg/version/testhelpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -114,8 +115,8 @@ func main() { skel.PluginMain(c, c) }
|
|||||||
//
|
//
|
||||||
// As we change the CNI spec, the Result type and this value may change.
|
// As we change the CNI spec, the Result type and this value may change.
|
||||||
// The text of the example plugins should not.
|
// The text of the example plugins should not.
|
||||||
var ExpectedResult = &types.Result{
|
var ExpectedResult = ¤t.Result{
|
||||||
IP4: &types.IPConfig{
|
IP4: ¤t.IPConfig{
|
||||||
IP: net.IPNet{
|
IP: net.IPNet{
|
||||||
IP: net.ParseIP("10.1.2.3"),
|
IP: net.ParseIP("10.1.2.3"),
|
||||||
Mask: net.CIDRMask(24, 32),
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
@ -18,11 +18,11 @@ import "fmt"
|
|||||||
|
|
||||||
type ErrorIncompatible struct {
|
type ErrorIncompatible struct {
|
||||||
Config string
|
Config string
|
||||||
Plugin []string
|
Supported []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorIncompatible) Details() string {
|
func (e *ErrorIncompatible) Details() string {
|
||||||
return fmt.Sprintf("config is %q, plugin supports %q", e.Config, e.Plugin)
|
return fmt.Sprintf("config is %q, plugin supports %q", e.Config, e.Supported)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorIncompatible) Error() string {
|
func (e *ErrorIncompatible) Error() string {
|
||||||
@ -31,17 +31,19 @@ func (e *ErrorIncompatible) Error() string {
|
|||||||
|
|
||||||
type Reconciler struct{}
|
type Reconciler struct{}
|
||||||
|
|
||||||
func (*Reconciler) Check(configVersion string, pluginInfo PluginInfo) *ErrorIncompatible {
|
func (r *Reconciler) Check(configVersion string, pluginInfo PluginInfo) *ErrorIncompatible {
|
||||||
pluginVersions := pluginInfo.SupportedVersions()
|
return r.CheckRaw(configVersion, pluginInfo.SupportedVersions())
|
||||||
|
}
|
||||||
|
|
||||||
for _, pluginVersion := range pluginVersions {
|
func (*Reconciler) CheckRaw(configVersion string, supportedVersions []string) *ErrorIncompatible {
|
||||||
if configVersion == pluginVersion {
|
for _, supportedVersion := range supportedVersions {
|
||||||
|
if configVersion == supportedVersion {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ErrorIncompatible{
|
return &ErrorIncompatible{
|
||||||
Config: configVersion,
|
Config: configVersion,
|
||||||
Plugin: pluginVersions,
|
Supported: supportedVersions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ var _ = Describe("Reconcile versions of net config with versions supported by pl
|
|||||||
|
|
||||||
Expect(err).To(Equal(&version.ErrorIncompatible{
|
Expect(err).To(Equal(&version.ErrorIncompatible{
|
||||||
Config: "0.1.0",
|
Config: "0.1.0",
|
||||||
Plugin: []string{"1.2.3", "4.3.2"},
|
Supported: []string{"1.2.3", "4.3.2"},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Expect(err.Error()).To(Equal(`incompatible CNI versions: config is "0.1.0", plugin supports ["1.2.3" "4.3.2"]`))
|
Expect(err.Error()).To(Equal(`incompatible CNI versions: config is "0.1.0", plugin supports ["1.2.3" "4.3.2"]`))
|
||||||
|
@ -14,6 +14,13 @@
|
|||||||
|
|
||||||
package version
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
|
)
|
||||||
|
|
||||||
// Current reports the version of the CNI spec implemented by this library
|
// Current reports the version of the CNI spec implemented by this library
|
||||||
func Current() string {
|
func Current() string {
|
||||||
return "0.2.0"
|
return "0.2.0"
|
||||||
@ -27,3 +34,25 @@ func Current() string {
|
|||||||
// Any future CNI spec versions which meet this definition should be added to
|
// Any future CNI spec versions which meet this definition should be added to
|
||||||
// this list.
|
// this list.
|
||||||
var Legacy = PluginSupports("0.1.0", "0.2.0")
|
var Legacy = PluginSupports("0.1.0", "0.2.0")
|
||||||
|
|
||||||
|
var resultFactories = []struct {
|
||||||
|
supportedVersions []string
|
||||||
|
newResult types.ResultFactoryFunc
|
||||||
|
}{
|
||||||
|
{current.SupportedVersions, current.NewResult},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds a Result object matching the requested version (if any) and asks
|
||||||
|
// that object to parse the plugin result, returning an error if parsing failed.
|
||||||
|
func NewResult(version string, resultBytes []byte) (types.Result, error) {
|
||||||
|
reconciler := &Reconciler{}
|
||||||
|
for _, resultFactory := range resultFactories {
|
||||||
|
err := reconciler.CheckRaw(version, resultFactory.supportedVersions)
|
||||||
|
if err == nil {
|
||||||
|
// Result supports this version
|
||||||
|
return resultFactory.newResult(resultBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("unsupported CNI result version %q", version)
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/coreos/go-systemd/activation"
|
"github.com/coreos/go-systemd/activation"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ func newDHCP() *DHCP {
|
|||||||
|
|
||||||
// Allocate acquires an IP from a DHCP server for a specified container.
|
// Allocate acquires an IP from a DHCP server for a specified container.
|
||||||
// The acquired lease will be maintained until Release() is called.
|
// The acquired lease will be maintained until Release() is called.
|
||||||
func (d *DHCP) Allocate(args *skel.CmdArgs, result *types.Result) error {
|
func (d *DHCP) Allocate(args *skel.CmdArgs, result *current.Result) error {
|
||||||
conf := types.NetConf{}
|
conf := types.NetConf{}
|
||||||
if err := json.Unmarshal(args.StdinData, &conf); err != nil {
|
if err := json.Unmarshal(args.StdinData, &conf); err != nil {
|
||||||
return fmt.Errorf("error parsing netconf: %v", err)
|
return fmt.Errorf("error parsing netconf: %v", err)
|
||||||
@ -70,7 +71,7 @@ func (d *DHCP) Allocate(args *skel.CmdArgs, result *types.Result) error {
|
|||||||
|
|
||||||
d.setLease(args.ContainerID, conf.Name, l)
|
d.setLease(args.ContainerID, conf.Name, l)
|
||||||
|
|
||||||
result.IP4 = &types.IPConfig{
|
result.IP4 = ¤t.IPConfig{
|
||||||
IP: *ipn,
|
IP: *ipn,
|
||||||
Gateway: l.Gateway(),
|
Gateway: l.Gateway(),
|
||||||
Routes: l.Routes(),
|
Routes: l.Routes(),
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cmdAdd(args *skel.CmdArgs) error {
|
func cmdAdd(args *skel.CmdArgs) error {
|
||||||
result := types.Result{}
|
result := ¤t.Result{}
|
||||||
if err := rpcCall("DHCP.Allocate", args, &result); err != nil {
|
if err := rpcCall("DHCP.Allocate", args, result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return result.Print()
|
return result.Print()
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/ip"
|
"github.com/containernetworking/cni/pkg/ip"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/plugins/ipam/host-local/backend"
|
"github.com/containernetworking/cni/plugins/ipam/host-local/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ func validateRangeIP(ip net.IP, ipnet *net.IPNet, start net.IP, end net.IP) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns newly allocated IP along with its config
|
// Returns newly allocated IP along with its config
|
||||||
func (a *IPAllocator) Get(id string) (*types.IPConfig, error) {
|
func (a *IPAllocator) Get(id string) (*current.IPConfig, error) {
|
||||||
a.store.Lock()
|
a.store.Lock()
|
||||||
defer a.store.Unlock()
|
defer a.store.Unlock()
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ func (a *IPAllocator) Get(id string) (*types.IPConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if reserved {
|
if reserved {
|
||||||
return &types.IPConfig{
|
return ¤t.IPConfig{
|
||||||
IP: net.IPNet{IP: requestedIP, Mask: a.conf.Subnet.Mask},
|
IP: net.IPNet{IP: requestedIP, Mask: a.conf.Subnet.Mask},
|
||||||
Gateway: gw,
|
Gateway: gw,
|
||||||
Routes: a.conf.Routes,
|
Routes: a.conf.Routes,
|
||||||
@ -184,7 +184,7 @@ func (a *IPAllocator) Get(id string) (*types.IPConfig, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if reserved {
|
if reserved {
|
||||||
return &types.IPConfig{
|
return ¤t.IPConfig{
|
||||||
IP: net.IPNet{IP: cur, Mask: a.conf.Subnet.Mask},
|
IP: net.IPNet{IP: cur, Mask: a.conf.Subnet.Mask},
|
||||||
Gateway: gw,
|
Gateway: gw,
|
||||||
Routes: a.conf.Routes,
|
Routes: a.conf.Routes,
|
||||||
|
@ -17,6 +17,7 @@ package allocator
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
fakestore "github.com/containernetworking/cni/plugins/ipam/host-local/backend/testing"
|
fakestore "github.com/containernetworking/cni/plugins/ipam/host-local/backend/testing"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@ -30,7 +31,7 @@ type AllocatorTestCase struct {
|
|||||||
lastIP string
|
lastIP string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t AllocatorTestCase) run() (*types.IPConfig, error) {
|
func (t AllocatorTestCase) run() (*current.IPConfig, error) {
|
||||||
subnet, err := types.ParseCIDR(t.subnet)
|
subnet, err := types.ParseCIDR(t.subnet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/testutils"
|
"github.com/containernetworking/cni/pkg/testutils"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@ -62,11 +63,14 @@ var _ = Describe("host-local Operations", func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the IP
|
// Allocate the IP
|
||||||
result, _, err := testutils.CmdAddWithResult(nspath, ifname, []byte(conf), func() error {
|
r, _, err := testutils.CmdAddWithResult(nspath, ifname, []byte(conf), func() error {
|
||||||
return cmdAdd(args)
|
return cmdAdd(args)
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
result, err := current.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
expectedAddress, err := types.ParseCIDR("10.1.2.2/24")
|
expectedAddress, err := types.ParseCIDR("10.1.2.2/24")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
expectedAddress.IP = expectedAddress.IP.To16()
|
expectedAddress.IP = expectedAddress.IP.To16()
|
||||||
@ -124,11 +128,14 @@ var _ = Describe("host-local Operations", func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the IP
|
// Allocate the IP
|
||||||
result, _, err := testutils.CmdAddWithResult(nspath, ifname, []byte(conf), func() error {
|
r, _, err := testutils.CmdAddWithResult(nspath, ifname, []byte(conf), func() error {
|
||||||
return cmdAdd(args)
|
return cmdAdd(args)
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
result, err := current.GetResult(r)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
ipFilePath := filepath.Join(tmpDir, "mynet", result.IP4.IP.IP.String())
|
ipFilePath := filepath.Join(tmpDir, "mynet", result.IP4.IP.IP.String())
|
||||||
contents, err := ioutil.ReadFile(ipFilePath)
|
contents, err := ioutil.ReadFile(ipFilePath)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/plugins/ipam/host-local/backend/disk"
|
"github.com/containernetworking/cni/plugins/ipam/host-local/backend/disk"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r := types.Result{}
|
r := ¤t.Result{}
|
||||||
|
|
||||||
if ipamConf.ResolvConf != "" {
|
if ipamConf.ResolvConf != "" {
|
||||||
dns, err := parseResolvConf(ipamConf.ResolvConf)
|
dns, err := parseResolvConf(ipamConf.ResolvConf)
|
||||||
@ -54,11 +54,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ipConf, err := allocator.Get(args.ContainerID)
|
r.IP4, err = allocator.Get(args.ContainerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.IP4 = ipConf
|
|
||||||
|
|
||||||
return r.Print()
|
return r.Print()
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/ns"
|
"github.com/containernetworking/cni/pkg/ns"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/utils"
|
"github.com/containernetworking/cni/pkg/utils"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
@ -234,7 +235,12 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := current.GetResult(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/ns"
|
"github.com/containernetworking/cni/pkg/ns"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
@ -125,10 +126,15 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
result, err := current.GetResult(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if result.IP4 == nil {
|
if result.IP4 == nil {
|
||||||
return errors.New("IPAM plugin returned missing IPv4 config")
|
return errors.New("IPAM plugin returned missing IPv4 config")
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/containernetworking/cni/pkg/ns"
|
"github.com/containernetworking/cni/pkg/ns"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
@ -41,7 +41,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err // not tested
|
return err // not tested
|
||||||
}
|
}
|
||||||
|
|
||||||
result := types.Result{}
|
result := current.Result{}
|
||||||
return result.Print()
|
return result.Print()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/ns"
|
"github.com/containernetworking/cni/pkg/ns"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/utils/sysctl"
|
"github.com/containernetworking/cni/pkg/utils/sysctl"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
@ -141,10 +142,15 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
result, err := current.GetResult(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if result.IP4 == nil {
|
if result.IP4 == nil {
|
||||||
return errors.New("IPAM plugin returned missing IPv4 config")
|
return errors.New("IPAM plugin returned missing IPv4 config")
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/ns"
|
"github.com/containernetworking/cni/pkg/ns"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/utils"
|
"github.com/containernetworking/cni/pkg/utils"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
@ -46,7 +47,7 @@ type NetConf struct {
|
|||||||
MTU int `json:"mtu"`
|
MTU int `json:"mtu"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupContainerVeth(netns, ifName string, mtu int, pr *types.Result) (string, error) {
|
func setupContainerVeth(netns, ifName string, mtu int, pr *current.Result) (string, error) {
|
||||||
// The IPAM result will be something like IP=192.168.3.5/24, GW=192.168.3.1.
|
// The IPAM result will be something like IP=192.168.3.5/24, GW=192.168.3.1.
|
||||||
// What we want is really a point-to-point link but veth does not support IFF_POINTOPONT.
|
// What we want is really a point-to-point link but veth does not support IFF_POINTOPONT.
|
||||||
// Next best thing would be to let it ARP but set interface to 192.168.3.5/32 and
|
// Next best thing would be to let it ARP but set interface to 192.168.3.5/32 and
|
||||||
@ -102,7 +103,7 @@ func setupContainerVeth(netns, ifName string, mtu int, pr *types.Result) (string
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range []netlink.Route{
|
for _, r := range []netlink.Route{
|
||||||
netlink.Route{
|
{
|
||||||
LinkIndex: contVeth.Attrs().Index,
|
LinkIndex: contVeth.Attrs().Index,
|
||||||
Dst: &net.IPNet{
|
Dst: &net.IPNet{
|
||||||
IP: pr.IP4.Gateway,
|
IP: pr.IP4.Gateway,
|
||||||
@ -111,7 +112,7 @@ func setupContainerVeth(netns, ifName string, mtu int, pr *types.Result) (string
|
|||||||
Scope: netlink.SCOPE_LINK,
|
Scope: netlink.SCOPE_LINK,
|
||||||
Src: pr.IP4.IP.IP,
|
Src: pr.IP4.IP.IP,
|
||||||
},
|
},
|
||||||
netlink.Route{
|
{
|
||||||
LinkIndex: contVeth.Attrs().Index,
|
LinkIndex: contVeth.Attrs().Index,
|
||||||
Dst: &net.IPNet{
|
Dst: &net.IPNet{
|
||||||
IP: pr.IP4.IP.IP.Mask(pr.IP4.IP.Mask),
|
IP: pr.IP4.IP.IP.Mask(pr.IP4.IP.Mask),
|
||||||
@ -132,7 +133,7 @@ func setupContainerVeth(netns, ifName string, mtu int, pr *types.Result) (string
|
|||||||
return hostVethName, err
|
return hostVethName, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupHostVeth(vethName string, ipConf *types.IPConfig) error {
|
func setupHostVeth(vethName string, ipConf *current.IPConfig) error {
|
||||||
// hostVeth moved namespaces and may have a new ifindex
|
// hostVeth moved namespaces and may have a new ifindex
|
||||||
veth, err := netlink.LinkByName(vethName)
|
veth, err := netlink.LinkByName(vethName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -172,7 +173,11 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run the IPAM plugin and get back the config to apply
|
// run the IPAM plugin and get back the config to apply
|
||||||
result, err := ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
|
r, err := ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
result, err := current.GetResult(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/ns"
|
"github.com/containernetworking/cni/pkg/ns"
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := types.Result{}
|
result := current.Result{}
|
||||||
return result.Print()
|
return result.Print()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/skel"
|
"github.com/containernetworking/cni/pkg/skel"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/types/current"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
|
noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
|
||||||
)
|
)
|
||||||
@ -38,7 +39,7 @@ import (
|
|||||||
type NetConf struct {
|
type NetConf struct {
|
||||||
types.NetConf
|
types.NetConf
|
||||||
DebugFile string `json:"debugFile"`
|
DebugFile string `json:"debugFile"`
|
||||||
PrevResult *types.Result `json:"prevResult,omitempty"`
|
PrevResult *current.Result `json:"prevResult,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConf(bytes []byte) (*NetConf, error) {
|
func loadConf(bytes []byte) (*NetConf, error) {
|
||||||
@ -121,7 +122,12 @@ func debugBehavior(args *skel.CmdArgs, command string) error {
|
|||||||
return errors.New(debug.ReportError)
|
return errors.New(debug.ReportError)
|
||||||
} else if debug.ReportResult == "PASSTHROUGH" || debug.ReportResult == "INJECT-DNS" {
|
} else if debug.ReportResult == "PASSTHROUGH" || debug.ReportResult == "INJECT-DNS" {
|
||||||
if debug.ReportResult == "INJECT-DNS" {
|
if debug.ReportResult == "INJECT-DNS" {
|
||||||
netConf.PrevResult.DNS.Nameservers = []string{"1.2.3.4"}
|
newResult, err := current.NewResultFromResult(netConf.PrevResult)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newResult.DNS.Nameservers = []string{"1.2.3.4"}
|
||||||
|
netConf.PrevResult = newResult
|
||||||
}
|
}
|
||||||
newResult, err := json.Marshal(netConf.PrevResult)
|
newResult, err := json.Marshal(netConf.PrevResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
2
test
2
test
@ -11,7 +11,7 @@ set -e
|
|||||||
|
|
||||||
source ./build
|
source ./build
|
||||||
|
|
||||||
TESTABLE="libcni plugins/ipam/dhcp plugins/ipam/host-local plugins/ipam/host-local/backend/allocator plugins/main/loopback pkg/invoke pkg/ns pkg/skel pkg/types pkg/utils plugins/main/ipvlan plugins/main/macvlan plugins/main/bridge plugins/main/ptp plugins/test/noop pkg/utils/hwaddr pkg/ip pkg/version pkg/version/testhelpers plugins/meta/flannel"
|
TESTABLE="libcni plugins/ipam/dhcp plugins/ipam/host-local plugins/ipam/host-local/backend/allocator plugins/main/loopback pkg/invoke pkg/ns pkg/skel pkg/types pkg/types/current pkg/utils plugins/main/ipvlan plugins/main/macvlan plugins/main/bridge plugins/main/ptp plugins/test/noop pkg/utils/hwaddr pkg/ip pkg/version pkg/version/testhelpers plugins/meta/flannel"
|
||||||
FORMATTABLE="$TESTABLE pkg/testutils plugins/meta/flannel plugins/meta/tuning"
|
FORMATTABLE="$TESTABLE pkg/testutils plugins/meta/flannel plugins/meta/tuning"
|
||||||
|
|
||||||
# user has not provided PKG override
|
# user has not provided PKG override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user