2017-07-21 12:37:50 +00:00
|
|
|
// Copyright (c) 2017 Intel Corporation
|
2016-12-13 14:48:12 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2017-07-21 12:37:50 +00:00
|
|
|
// This is a "Multi-plugin".The delegate concept refered from CNI project
|
2016-12-13 14:48:12 +00:00
|
|
|
// It reads other plugin netconf, and then invoke them, e.g.
|
|
|
|
// flannel or sriov plugin.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2019-05-15 08:06:26 +00:00
|
|
|
"context"
|
2016-12-13 14:48:12 +00:00
|
|
|
"encoding/json"
|
2018-12-06 03:52:30 +00:00
|
|
|
"flag"
|
2016-12-13 14:48:12 +00:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2018-08-28 10:21:50 +00:00
|
|
|
"net"
|
2016-12-13 14:48:12 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2018-11-28 11:27:49 +00:00
|
|
|
"strings"
|
2018-10-10 18:09:38 +00:00
|
|
|
"time"
|
2016-12-13 14:48:12 +00:00
|
|
|
|
2018-07-26 23:04:52 +00:00
|
|
|
"github.com/containernetworking/cni/libcni"
|
2016-12-13 14:48:12 +00:00
|
|
|
"github.com/containernetworking/cni/pkg/invoke"
|
|
|
|
"github.com/containernetworking/cni/pkg/skel"
|
2018-05-01 18:08:39 +00:00
|
|
|
cnitypes "github.com/containernetworking/cni/pkg/types"
|
2020-03-04 07:42:29 +00:00
|
|
|
cnicurrent "github.com/containernetworking/cni/pkg/types/current"
|
2018-12-06 03:52:30 +00:00
|
|
|
cniversion "github.com/containernetworking/cni/pkg/version"
|
2018-06-13 19:51:29 +00:00
|
|
|
"github.com/containernetworking/plugins/pkg/ns"
|
2020-05-28 14:54:51 +00:00
|
|
|
nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
|
|
|
|
nadutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils"
|
|
|
|
"github.com/vishvananda/netlink"
|
2020-05-14 15:54:24 +00:00
|
|
|
k8s "gopkg.in/intel/multus-cni.v3/k8sclient"
|
|
|
|
"gopkg.in/intel/multus-cni.v3/logging"
|
|
|
|
"gopkg.in/intel/multus-cni.v3/netutils"
|
|
|
|
"gopkg.in/intel/multus-cni.v3/types"
|
2020-03-04 07:42:29 +00:00
|
|
|
v1 "k8s.io/api/core/v1"
|
2020-05-18 09:16:51 +00:00
|
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
2018-10-10 18:09:38 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
2016-12-13 14:48:12 +00:00
|
|
|
)
|
|
|
|
|
2018-12-06 03:52:30 +00:00
|
|
|
var version = "master@git"
|
|
|
|
var commit = "unknown commit"
|
|
|
|
var date = "unknown date"
|
|
|
|
|
2020-02-18 20:15:44 +00:00
|
|
|
var pollDuration = 1000 * time.Millisecond
|
|
|
|
var pollTimeout = 45 * time.Second
|
2018-10-10 18:09:38 +00:00
|
|
|
|
2018-12-06 03:52:30 +00:00
|
|
|
func printVersionString() string {
|
|
|
|
return fmt.Sprintf("multus-cni version:%s, commit:%s, date:%s",
|
|
|
|
version, commit, date)
|
|
|
|
}
|
|
|
|
|
2016-12-13 14:48:12 +00:00
|
|
|
func saveScratchNetConf(containerID, dataDir string, netconf []byte) error {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("saveScratchNetConf: %s, %s, %s", containerID, dataDir, string(netconf))
|
2016-12-13 14:48:12 +00:00
|
|
|
if err := os.MkdirAll(dataDir, 0700); err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("saveScratchNetConf: failed to create the multus data directory(%q): %v", dataDir, err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
path := filepath.Join(dataDir, containerID)
|
|
|
|
|
|
|
|
err := ioutil.WriteFile(path, netconf, 0600)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("saveScratchNetConf: failed to write container data in the path(%q): %v", path, err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
func consumeScratchNetConf(containerID, dataDir string) ([]byte, string, error) {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("consumeScratchNetConf: %s, %s", containerID, dataDir)
|
2016-12-13 14:48:12 +00:00
|
|
|
path := filepath.Join(dataDir, containerID)
|
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
b, err := ioutil.ReadFile(path)
|
|
|
|
return b, path, err
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func getIfname(delegate *types.DelegateNetConf, argif string, idx int) string {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("getIfname: %v, %s, %d", delegate, argif, idx)
|
2018-05-01 18:08:39 +00:00
|
|
|
if delegate.IfnameRequest != "" {
|
|
|
|
return delegate.IfnameRequest
|
|
|
|
}
|
|
|
|
if delegate.MasterPlugin {
|
|
|
|
// master plugin always uses the CNI-provided interface name
|
|
|
|
return argif
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
// Otherwise construct a unique interface name from the delegate's
|
|
|
|
// position in the delegate list
|
|
|
|
return fmt.Sprintf("net%d", idx)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func saveDelegates(containerID, dataDir string, delegates []*types.DelegateNetConf) error {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("saveDelegates: %s, %s, %v", containerID, dataDir, delegates)
|
2016-12-13 14:48:12 +00:00
|
|
|
delegatesBytes, err := json.Marshal(delegates)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("saveDelegates: error serializing delegate netconf: %v", err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err = saveScratchNetConf(containerID, dataDir, delegatesBytes); err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("saveDelegates: error in saving the delegates : %v", err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
func deleteDelegates(containerID, dataDir string) error {
|
|
|
|
logging.Debugf("deleteDelegates: %s, %s", containerID, dataDir)
|
|
|
|
|
|
|
|
path := filepath.Join(dataDir, containerID)
|
|
|
|
if err := os.Remove(path); err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("deleteDelegates: error in deleting the delegates : %v", err)
|
2019-01-25 08:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-05-09 06:33:44 +00:00
|
|
|
func validateIfName(nsname string, ifname string) error {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("validateIfName: %s, %s", nsname, ifname)
|
2018-05-09 06:33:44 +00:00
|
|
|
podNs, err := ns.GetNS(nsname)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("validateIfName: no net namespace %s found: %v", nsname, err)
|
2018-05-09 06:33:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = podNs.Do(func(_ ns.NetNS) error {
|
|
|
|
_, err := netlink.LinkByName(ifname)
|
|
|
|
if err != nil {
|
|
|
|
if err.Error() == "Link not found" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("validateIfName: interface name %s already exists", ifname)
|
2018-05-09 06:33:44 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-16 09:55:12 +00:00
|
|
|
func confAdd(rt *libcni.RuntimeConf, rawNetconf []byte, binDir string, exec invoke.Exec) (cnitypes.Result, error) {
|
2020-01-13 14:57:22 +00:00
|
|
|
logging.Debugf("confAdd: %v, %s, %s", rt, string(rawNetconf), binDir)
|
2019-08-16 09:55:12 +00:00
|
|
|
// In part, adapted from K8s pkg/kubelet/dockershim/network/cni/cni.go
|
|
|
|
binDirs := filepath.SplitList(os.Getenv("CNI_PATH"))
|
|
|
|
binDirs = append([]string{binDir}, binDirs...)
|
|
|
|
cniNet := libcni.NewCNIConfig(binDirs, exec)
|
|
|
|
|
|
|
|
conf, err := libcni.ConfFromBytes(rawNetconf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, logging.Errorf("error in converting the raw bytes to conf: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := cniNet.AddNetwork(context.Background(), conf, rt)
|
|
|
|
if err != nil {
|
2020-04-30 08:38:49 +00:00
|
|
|
return nil, err
|
2019-08-16 09:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2020-01-13 14:57:22 +00:00
|
|
|
func confCheck(rt *libcni.RuntimeConf, rawNetconf []byte, binDir string, exec invoke.Exec) error {
|
|
|
|
logging.Debugf("confCheck: %v, %s, %s", rt, string(rawNetconf), binDir)
|
|
|
|
|
|
|
|
binDirs := filepath.SplitList(os.Getenv("CNI_PATH"))
|
|
|
|
binDirs = append([]string{binDir}, binDirs...)
|
|
|
|
cniNet := libcni.NewCNIConfig(binDirs, exec)
|
|
|
|
|
|
|
|
conf, err := libcni.ConfFromBytes(rawNetconf)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("error in converting the raw bytes to conf: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cniNet.CheckNetwork(context.Background(), conf, rt)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("error in getting result from DelNetwork: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-16 09:55:12 +00:00
|
|
|
func confDel(rt *libcni.RuntimeConf, rawNetconf []byte, binDir string, exec invoke.Exec) error {
|
|
|
|
logging.Debugf("conflistDel: %v, %s, %s", rt, string(rawNetconf), binDir)
|
|
|
|
// In part, adapted from K8s pkg/kubelet/dockershim/network/cni/cni.go
|
|
|
|
binDirs := filepath.SplitList(os.Getenv("CNI_PATH"))
|
|
|
|
binDirs = append([]string{binDir}, binDirs...)
|
|
|
|
cniNet := libcni.NewCNIConfig(binDirs, exec)
|
|
|
|
|
|
|
|
conf, err := libcni.ConfFromBytes(rawNetconf)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("error in converting the raw bytes to conf: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cniNet.DelNetwork(context.Background(), conf, rt)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("error in getting result from DelNetwork: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-09-26 07:52:37 +00:00
|
|
|
func conflistAdd(rt *libcni.RuntimeConf, rawnetconflist []byte, binDir string, exec invoke.Exec) (cnitypes.Result, error) {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("conflistAdd: %v, %s, %s", rt, string(rawnetconflist), binDir)
|
2018-07-26 23:04:52 +00:00
|
|
|
// In part, adapted from K8s pkg/kubelet/dockershim/network/cni/cni.go
|
2018-09-26 07:52:37 +00:00
|
|
|
binDirs := filepath.SplitList(os.Getenv("CNI_PATH"))
|
2019-08-16 09:55:12 +00:00
|
|
|
binDirs = append([]string{binDir}, binDirs...)
|
2018-09-26 07:52:37 +00:00
|
|
|
cniNet := libcni.NewCNIConfig(binDirs, exec)
|
2018-07-26 23:04:52 +00:00
|
|
|
|
|
|
|
confList, err := libcni.ConfListFromBytes(rawnetconflist)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return nil, logging.Errorf("conflistAdd: error converting the raw bytes into a conflist: %v", err)
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2019-05-15 08:06:26 +00:00
|
|
|
result, err := cniNet.AddNetworkList(context.Background(), confList, rt)
|
2018-07-26 23:04:52 +00:00
|
|
|
if err != nil {
|
2020-04-30 08:38:49 +00:00
|
|
|
return nil, err
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2020-01-13 14:57:22 +00:00
|
|
|
func conflistCheck(rt *libcni.RuntimeConf, rawnetconflist []byte, binDir string, exec invoke.Exec) error {
|
|
|
|
logging.Debugf("conflistCheck: %v, %s, %s", rt, string(rawnetconflist), binDir)
|
|
|
|
|
|
|
|
binDirs := filepath.SplitList(os.Getenv("CNI_PATH"))
|
|
|
|
binDirs = append([]string{binDir}, binDirs...)
|
|
|
|
cniNet := libcni.NewCNIConfig(binDirs, exec)
|
|
|
|
|
|
|
|
confList, err := libcni.ConfListFromBytes(rawnetconflist)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("conflistCheck: error converting the raw bytes into a conflist: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cniNet.CheckNetworkList(context.Background(), confList, rt)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("conflistCheck: error in getting result from CheckNetworkList: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-01 16:55:39 +00:00
|
|
|
func conflistDel(rt *libcni.RuntimeConf, rawnetconflist []byte, binDir string, exec invoke.Exec) error {
|
2018-08-10 05:00:51 +00:00
|
|
|
logging.Debugf("conflistDel: %v, %s, %s", rt, string(rawnetconflist), binDir)
|
2018-07-26 23:04:52 +00:00
|
|
|
// In part, adapted from K8s pkg/kubelet/dockershim/network/cni/cni.go
|
2018-11-01 16:55:39 +00:00
|
|
|
binDirs := filepath.SplitList(os.Getenv("CNI_PATH"))
|
2019-08-16 09:55:12 +00:00
|
|
|
binDirs = append([]string{binDir}, binDirs...)
|
2018-11-01 16:55:39 +00:00
|
|
|
cniNet := libcni.NewCNIConfig(binDirs, exec)
|
2018-07-26 23:04:52 +00:00
|
|
|
|
|
|
|
confList, err := libcni.ConfListFromBytes(rawnetconflist)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("conflistDel: error converting the raw bytes into a conflist: %v", err)
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2019-05-15 08:06:26 +00:00
|
|
|
err = cniNet.DelNetworkList(context.Background(), confList, rt)
|
2018-07-26 23:04:52 +00:00
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("conflistDel: error in getting result from DelNetworkList: %v", err)
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-04 07:42:29 +00:00
|
|
|
func delegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, ifName string, delegate *types.DelegateNetConf, rt *libcni.RuntimeConf, binDir string, cniArgs string) (cnitypes.Result, error) {
|
2018-08-06 06:55:30 +00:00
|
|
|
logging.Debugf("delegateAdd: %v, %s, %v, %v, %s", exec, ifName, delegate, rt, binDir)
|
2018-05-01 18:08:39 +00:00
|
|
|
if os.Setenv("CNI_IFNAME", ifName) != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return nil, logging.Errorf("delegateAdd: error setting envionment variable CNI_IFNAME")
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
if err := validateIfName(os.Getenv("CNI_NETNS"), ifName); err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return nil, logging.Errorf("delegateAdd: cannot set %q interface name to %q: %v", delegate.Conf.Type, ifName, err)
|
2018-05-09 06:33:44 +00:00
|
|
|
}
|
|
|
|
|
2019-08-16 09:55:12 +00:00
|
|
|
// Deprecated in ver 3.5.
|
|
|
|
if delegate.MacRequest != "" || delegate.IPRequest != nil {
|
2018-11-28 11:27:49 +00:00
|
|
|
if cniArgs != "" {
|
|
|
|
cniArgs = fmt.Sprintf("%s;IgnoreUnknown=true", cniArgs)
|
|
|
|
} else {
|
|
|
|
cniArgs = "IgnoreUnknown=true"
|
2018-08-28 10:21:50 +00:00
|
|
|
}
|
2018-11-28 11:27:49 +00:00
|
|
|
if delegate.MacRequest != "" {
|
|
|
|
// validate Mac address
|
|
|
|
_, err := net.ParseMAC(delegate.MacRequest)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return nil, logging.Errorf("delegateAdd: failed to parse mac address %q", delegate.MacRequest)
|
2018-11-28 11:27:49 +00:00
|
|
|
}
|
2018-08-28 10:21:50 +00:00
|
|
|
|
2018-11-28 11:27:49 +00:00
|
|
|
cniArgs = fmt.Sprintf("%s;MAC=%s", cniArgs, delegate.MacRequest)
|
2019-10-02 09:02:26 +00:00
|
|
|
logging.Debugf("delegateAdd: set MAC address %q to %q", delegate.MacRequest, ifName)
|
2019-10-23 15:40:44 +00:00
|
|
|
rt.Args = append(rt.Args, [2]string{"MAC", delegate.MacRequest})
|
2018-11-28 11:27:49 +00:00
|
|
|
}
|
|
|
|
|
2019-08-16 09:55:12 +00:00
|
|
|
if delegate.IPRequest != nil {
|
2018-11-28 11:27:49 +00:00
|
|
|
// validate IP address
|
2019-08-16 09:55:12 +00:00
|
|
|
for _, ip := range delegate.IPRequest {
|
|
|
|
if strings.Contains(ip, "/") {
|
|
|
|
_, _, err := net.ParseCIDR(ip)
|
|
|
|
if err != nil {
|
|
|
|
return nil, logging.Errorf("delegateAdd: failed to parse IP address %q", ip)
|
|
|
|
}
|
|
|
|
} else if net.ParseIP(ip) == nil {
|
|
|
|
return nil, logging.Errorf("delegateAdd: failed to parse IP address %q", ip)
|
2018-11-28 11:27:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-16 09:55:12 +00:00
|
|
|
ips := strings.Join(delegate.IPRequest, ",")
|
|
|
|
cniArgs = fmt.Sprintf("%s;IP=%s", cniArgs, ips)
|
|
|
|
logging.Debugf("delegateAdd: set IP address %q to %q", ips, ifName)
|
2019-10-23 15:40:44 +00:00
|
|
|
rt.Args = append(rt.Args, [2]string{"IP", ips})
|
2018-08-28 10:21:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 16:00:46 +00:00
|
|
|
var result cnitypes.Result
|
|
|
|
var err error
|
|
|
|
if delegate.ConfListPlugin {
|
|
|
|
result, err = conflistAdd(rt, delegate.Bytes, binDir, exec)
|
2018-07-26 23:04:52 +00:00
|
|
|
if err != nil {
|
2020-04-30 08:38:49 +00:00
|
|
|
return nil, err
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
2019-03-07 16:00:46 +00:00
|
|
|
} else {
|
2019-08-16 09:55:12 +00:00
|
|
|
result, err = confAdd(rt, delegate.Bytes, binDir, exec)
|
2019-03-07 16:00:46 +00:00
|
|
|
if err != nil {
|
2020-04-30 08:38:49 +00:00
|
|
|
return nil, err
|
2019-03-07 16:00:46 +00:00
|
|
|
}
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2019-03-07 16:00:46 +00:00
|
|
|
if logging.GetLoggingLevel() >= logging.VerboseLevel {
|
|
|
|
data, _ := json.Marshal(result)
|
2020-03-18 08:21:43 +00:00
|
|
|
var cniConfName string
|
2019-03-07 16:00:46 +00:00
|
|
|
if delegate.ConfListPlugin {
|
2020-03-18 08:21:43 +00:00
|
|
|
cniConfName = delegate.ConfList.Name
|
2019-03-07 16:00:46 +00:00
|
|
|
} else {
|
2020-03-18 08:21:43 +00:00
|
|
|
cniConfName = delegate.Conf.Name
|
2019-03-07 16:00:46 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 08:21:43 +00:00
|
|
|
podUID := "unknownUID"
|
|
|
|
if pod != nil {
|
|
|
|
podUID = string(pod.ObjectMeta.UID)
|
|
|
|
}
|
|
|
|
logging.Verbosef("Add: %s:%s:%s:%s(%s):%s %s", rt.Args[1][1], rt.Args[2][1], podUID, delegate.Name, cniConfName, rt.IfName, string(data))
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2020-03-04 07:42:29 +00:00
|
|
|
// get IP addresses from result
|
|
|
|
ips := []string{}
|
|
|
|
res, err := cnicurrent.NewResultFromResult(result)
|
|
|
|
if err != nil {
|
|
|
|
logging.Errorf("delegateAdd: error converting result: %v", err)
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
for _, ip := range res.IPs {
|
|
|
|
ips = append(ips, ip.Address.String())
|
|
|
|
}
|
|
|
|
|
2020-04-17 02:10:30 +00:00
|
|
|
if pod != nil {
|
|
|
|
// send kubernetes events
|
|
|
|
if delegate.Name != "" {
|
|
|
|
kubeClient.Eventf(pod, v1.EventTypeNormal, "AddedInterface", "Add %s %v from %s", rt.IfName, ips, delegate.Name)
|
|
|
|
} else {
|
|
|
|
kubeClient.Eventf(pod, v1.EventTypeNormal, "AddedInterface", "Add %s %v", rt.IfName, ips)
|
|
|
|
}
|
2020-04-20 15:45:40 +00:00
|
|
|
} else {
|
|
|
|
// for further debug https://github.com/intel/multus-cni/issues/481
|
|
|
|
logging.Errorf("delegateAdd: pod nil pointer: namespace: %s, name: %s, container id: %s, pod: %v", rt.Args[1][1], rt.Args[2][1], rt.Args[3][1], pod)
|
2020-03-04 07:42:29 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
return result, nil
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 14:57:22 +00:00
|
|
|
func delegateCheck(exec invoke.Exec, ifName string, delegateConf *types.DelegateNetConf, rt *libcni.RuntimeConf, binDir string) error {
|
|
|
|
logging.Debugf("delegateCheck: %v, %s, %v, %v, %s", exec, ifName, delegateConf, rt, binDir)
|
|
|
|
if os.Setenv("CNI_IFNAME", ifName) != nil {
|
|
|
|
return logging.Errorf("delegateCheck: error setting envionment variable CNI_IFNAME")
|
|
|
|
}
|
|
|
|
|
|
|
|
if logging.GetLoggingLevel() >= logging.VerboseLevel {
|
2020-03-18 08:21:43 +00:00
|
|
|
var cniConfName string
|
2020-01-13 14:57:22 +00:00
|
|
|
if delegateConf.ConfListPlugin {
|
2020-03-18 08:21:43 +00:00
|
|
|
cniConfName = delegateConf.ConfList.Name
|
2020-01-13 14:57:22 +00:00
|
|
|
} else {
|
2020-03-18 08:21:43 +00:00
|
|
|
cniConfName = delegateConf.Conf.Name
|
2020-01-13 14:57:22 +00:00
|
|
|
}
|
2020-03-18 08:21:43 +00:00
|
|
|
logging.Verbosef("Check: %s:%s:%s(%s):%s %s", rt.Args[1][1], rt.Args[2][1], delegateConf.Name, cniConfName, rt.IfName, string(delegateConf.Bytes))
|
2020-01-13 14:57:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
if delegateConf.ConfListPlugin {
|
|
|
|
err = conflistCheck(rt, delegateConf.Bytes, binDir, exec)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("delegateCheck: error invoking ConflistCheck - %q: %v", delegateConf.ConfList.Name, err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = confCheck(rt, delegateConf.Bytes, binDir, exec)
|
|
|
|
if err != nil {
|
|
|
|
return logging.Errorf("delegateCheck: error invoking DelegateCheck - %q: %v", delegateConf.Conf.Type, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-18 08:21:43 +00:00
|
|
|
func delegateDel(exec invoke.Exec, pod *v1.Pod, ifName string, delegateConf *types.DelegateNetConf, rt *libcni.RuntimeConf, binDir string) error {
|
|
|
|
logging.Debugf("delegateDel: %v, %v, %s, %v, %v, %s", exec, pod, ifName, delegateConf, rt, binDir)
|
2018-05-01 18:08:39 +00:00
|
|
|
if os.Setenv("CNI_IFNAME", ifName) != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("delegateDel: error setting envionment variable CNI_IFNAME")
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2019-03-07 16:00:46 +00:00
|
|
|
if logging.GetLoggingLevel() >= logging.VerboseLevel {
|
|
|
|
var confName string
|
|
|
|
if delegateConf.ConfListPlugin {
|
|
|
|
confName = delegateConf.ConfList.Name
|
|
|
|
} else {
|
|
|
|
confName = delegateConf.Conf.Name
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
2020-03-18 08:21:43 +00:00
|
|
|
podUID := "unknownUID"
|
|
|
|
if pod != nil {
|
|
|
|
podUID = string(pod.ObjectMeta.UID)
|
|
|
|
}
|
|
|
|
logging.Verbosef("Del: %s:%s:%s:%s:%s %s", rt.Args[1][1], rt.Args[2][1], podUID, confName, rt.IfName, string(delegateConf.Bytes))
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2019-03-07 16:00:46 +00:00
|
|
|
var err error
|
|
|
|
if delegateConf.ConfListPlugin {
|
|
|
|
err = conflistDel(rt, delegateConf.Bytes, binDir, exec)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("delegateDel: error invoking ConflistDel - %q: %v", delegateConf.ConfList.Name, err)
|
2019-03-07 16:00:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-08-16 09:55:12 +00:00
|
|
|
err = confDel(rt, delegateConf.Bytes, binDir, exec)
|
|
|
|
if err != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("delegateDel: error invoking DelegateDel - %q: %v", delegateConf.Conf.Type, err)
|
2019-03-07 16:00:46 +00:00
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2019-03-07 16:00:46 +00:00
|
|
|
return err
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 08:21:43 +00:00
|
|
|
func delPlugins(exec invoke.Exec, pod *v1.Pod, argIfname string, delegates []*types.DelegateNetConf, lastIdx int, rt *libcni.RuntimeConf, binDir string) error {
|
|
|
|
logging.Debugf("delPlugins: %v, %v, %s, %v, %d, %v, %s", exec, pod, argIfname, delegates, lastIdx, rt, binDir)
|
2017-02-21 19:01:58 +00:00
|
|
|
if os.Setenv("CNI_COMMAND", "DEL") != nil {
|
2019-10-02 09:02:26 +00:00
|
|
|
return logging.Errorf("delPlugins: error setting envionment variable CNI_COMMAND to a value of DEL")
|
2017-02-21 19:01:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-29 18:49:55 +00:00
|
|
|
var errorstrings []string
|
2018-05-01 18:08:39 +00:00
|
|
|
for idx := lastIdx; idx >= 0; idx-- {
|
|
|
|
ifName := getIfname(delegates[idx], argIfname, idx)
|
2018-07-26 23:04:52 +00:00
|
|
|
rt.IfName = ifName
|
2018-11-29 18:49:55 +00:00
|
|
|
// Attempt to delete all but do not error out, instead, collect all errors.
|
2020-03-18 08:21:43 +00:00
|
|
|
if err := delegateDel(exec, pod, ifName, delegates[idx], rt, binDir); err != nil {
|
2018-11-29 18:49:55 +00:00
|
|
|
errorstrings = append(errorstrings, err.Error())
|
2017-02-21 19:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-29 18:49:55 +00:00
|
|
|
// Check if we had any errors, and send them all back.
|
|
|
|
if len(errorstrings) > 0 {
|
|
|
|
return fmt.Errorf(strings.Join(errorstrings, " / "))
|
|
|
|
}
|
|
|
|
|
2017-02-21 19:01:58 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-11-05 22:55:45 +00:00
|
|
|
func cmdErr(k8sArgs *types.K8sArgs, format string, args ...interface{}) error {
|
|
|
|
prefix := "Multus: "
|
|
|
|
if k8sArgs != nil {
|
|
|
|
prefix += fmt.Sprintf("[%s/%s]: ", k8sArgs.K8S_POD_NAMESPACE, k8sArgs.K8S_POD_NAME)
|
|
|
|
}
|
|
|
|
return logging.Errorf(prefix+format, args...)
|
|
|
|
}
|
|
|
|
|
2020-04-30 08:38:49 +00:00
|
|
|
func cmdPluginErr(k8sArgs *types.K8sArgs, confName string, format string, args ...interface{}) error {
|
|
|
|
msg := ""
|
|
|
|
if k8sArgs != nil {
|
|
|
|
msg += fmt.Sprintf("[%s/%s:%s]: ", k8sArgs.K8S_POD_NAMESPACE, k8sArgs.K8S_POD_NAME, confName)
|
|
|
|
}
|
|
|
|
return logging.Errorf(msg+format, args...)
|
|
|
|
}
|
|
|
|
|
2019-12-04 09:21:06 +00:00
|
|
|
func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) (cnitypes.Result, error) {
|
2018-07-19 14:02:49 +00:00
|
|
|
n, err := types.LoadNetConf(args.StdinData)
|
2019-01-25 08:49:16 +00:00
|
|
|
logging.Debugf("cmdAdd: %v, %v, %v", args, exec, kubeClient)
|
2018-07-19 14:02:49 +00:00
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(nil, "error loading netconf: %v", err)
|
2018-07-19 14:02:49 +00:00
|
|
|
}
|
|
|
|
|
2020-03-04 07:42:29 +00:00
|
|
|
kubeClient, err = k8s.GetK8sClient(n.Kubeconfig, kubeClient)
|
|
|
|
if err != nil {
|
|
|
|
return nil, cmdErr(nil, "error getting k8s client: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-07-26 23:04:52 +00:00
|
|
|
k8sArgs, err := k8s.GetK8sArgs(args)
|
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(nil, "error getting k8s args: %v", err)
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2020-02-10 18:44:12 +00:00
|
|
|
if n.ReadinessIndicatorFile != "" {
|
2020-02-18 20:15:44 +00:00
|
|
|
err := wait.PollImmediate(pollDuration, pollTimeout, func() (bool, error) {
|
2020-02-10 18:44:12 +00:00
|
|
|
_, err := os.Stat(n.ReadinessIndicatorFile)
|
|
|
|
return err == nil, nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
2020-02-18 20:15:44 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "PollImmediate error waiting for ReadinessIndicatorFile: %v", err)
|
2018-10-10 18:09:38 +00:00
|
|
|
}
|
2020-02-10 18:44:12 +00:00
|
|
|
}
|
2018-10-10 18:09:38 +00:00
|
|
|
|
2020-05-18 09:16:51 +00:00
|
|
|
pod := (*v1.Pod)(nil)
|
|
|
|
if kubeClient != nil {
|
|
|
|
pod, err = kubeClient.GetPod(string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))
|
|
|
|
if err != nil {
|
2020-05-28 14:54:51 +00:00
|
|
|
var waitErr error
|
|
|
|
// in case of ServiceUnavailable, retry 10 times with 0.5 sec interval
|
|
|
|
if errors.IsServiceUnavailable(err) {
|
|
|
|
pollDuration := 500 * time.Millisecond
|
|
|
|
pollTimeout := 5 * time.Second
|
|
|
|
waitErr = wait.PollImmediate(pollDuration, pollTimeout, func() (bool, error) {
|
|
|
|
pod, err = kubeClient.GetPod(string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))
|
|
|
|
return pod != nil, err
|
|
|
|
})
|
|
|
|
// retry failed, then return error with retry out
|
|
|
|
if waitErr != nil {
|
|
|
|
return nil, cmdErr(k8sArgs, "error getting pod by service unavailable: %v", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Other case, return error
|
2020-05-18 09:16:51 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error getting pod: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// resourceMap holds Pod device allocation information; only initizized if CRD contains 'resourceName' annotation.
|
|
|
|
// This will only be initialized once and all delegate objects can reference this to look up device info.
|
|
|
|
var resourceMap map[string]*types.ResourceInfo
|
|
|
|
|
2018-10-11 08:57:20 +00:00
|
|
|
if n.ClusterNetwork != "" {
|
2020-05-18 09:16:51 +00:00
|
|
|
resourceMap, err = k8s.GetDefaultNetworks(pod, n, kubeClient, resourceMap)
|
2018-10-11 08:57:20 +00:00
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "failed to get clusterNetwork/defaultNetworks: %v", err)
|
2018-10-11 08:57:20 +00:00
|
|
|
}
|
|
|
|
// First delegate is always the master plugin
|
|
|
|
n.Delegates[0].MasterPlugin = true
|
|
|
|
}
|
|
|
|
|
2020-05-18 09:16:51 +00:00
|
|
|
_, kc, err := k8s.TryLoadPodDelegates(pod, n, kubeClient, resourceMap)
|
2018-07-19 14:02:49 +00:00
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error loading k8s delegates k8s args: %v", err)
|
2018-07-19 14:02:49 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
// cache the multus config
|
|
|
|
if err := saveDelegates(args.ContainerID, n.CNIDir, n.Delegates); err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error saving the delegates: %v", err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
var result, tmpResult cnitypes.Result
|
2019-12-05 06:43:27 +00:00
|
|
|
var netStatus []nettypes.NetworkStatus
|
2018-11-28 11:27:49 +00:00
|
|
|
cniArgs := os.Getenv("CNI_ARGS")
|
2018-05-01 18:08:39 +00:00
|
|
|
for idx, delegate := range n.Delegates {
|
|
|
|
ifName := getIfname(delegate, args.IfName, idx)
|
2019-08-16 09:55:12 +00:00
|
|
|
|
|
|
|
runtimeConfig := types.MergeCNIRuntimeConfig(n.RuntimeConfig, delegate)
|
|
|
|
rt := types.CreateCNIRuntimeConf(args, k8sArgs, ifName, runtimeConfig)
|
2020-03-04 07:42:29 +00:00
|
|
|
tmpResult, err = delegateAdd(exec, kubeClient, pod, ifName, delegate, rt, n.BinDir, cniArgs)
|
2018-05-01 18:08:39 +00:00
|
|
|
if err != nil {
|
2019-02-04 15:33:47 +00:00
|
|
|
// If the add failed, tear down all networks we already added
|
|
|
|
netName := delegate.Conf.Name
|
|
|
|
if netName == "" {
|
|
|
|
netName = delegate.ConfList.Name
|
|
|
|
}
|
|
|
|
// Ignore errors; DEL must be idempotent anyway
|
2020-03-18 08:21:43 +00:00
|
|
|
_ = delPlugins(exec, nil, args.IfName, n.Delegates, idx, rt, n.BinDir)
|
2020-04-30 08:38:49 +00:00
|
|
|
return nil, cmdPluginErr(k8sArgs, netName, "error adding container to network %q: %v", netName, err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2019-08-27 07:52:58 +00:00
|
|
|
// Remove gateway from routing table if the gateway is not used
|
2019-10-23 15:40:44 +00:00
|
|
|
deletegateway := false
|
|
|
|
adddefaultgateway := false
|
2019-08-27 07:52:58 +00:00
|
|
|
if delegate.IsFilterGateway {
|
2019-10-23 15:40:44 +00:00
|
|
|
deletegateway = true
|
|
|
|
logging.Debugf("Marked interface %v for gateway deletion", ifName)
|
|
|
|
} else {
|
|
|
|
// Otherwise, determine if this interface now gets our default route.
|
|
|
|
if delegate.GatewayRequest != nil {
|
|
|
|
deletegateway = true
|
|
|
|
adddefaultgateway = true
|
|
|
|
logging.Debugf("Detected gateway override on interface %v to %v", ifName, delegate.GatewayRequest)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if deletegateway {
|
2019-08-27 07:52:58 +00:00
|
|
|
tmpResult, err = netutils.DeleteDefaultGW(args, ifName, &tmpResult)
|
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error deleting default gateway: %v", err)
|
2019-08-27 07:52:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-23 15:40:44 +00:00
|
|
|
// Here we'll set the default gateway
|
|
|
|
if adddefaultgateway {
|
|
|
|
tmpResult, err = netutils.SetDefaultGW(args, ifName, delegate.GatewayRequest, &tmpResult)
|
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error setting default gateway: %v", err)
|
2019-10-23 15:40:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
// Master plugin result is always used if present
|
|
|
|
if delegate.MasterPlugin || result == nil {
|
|
|
|
result = tmpResult
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
2018-07-30 10:59:13 +00:00
|
|
|
|
|
|
|
//create the network status, only in case Multus as kubeconfig
|
2018-08-01 14:56:46 +00:00
|
|
|
if n.Kubeconfig != "" && kc != nil {
|
2019-12-04 09:21:06 +00:00
|
|
|
if !types.CheckSystemNamespaces(string(k8sArgs.K8S_POD_NAME), n.SystemNamespaces) {
|
2020-06-09 03:43:49 +00:00
|
|
|
delegateNetStatus, err := nadutils.CreateNetworkStatus(tmpResult, delegate.Name, delegate.MasterPlugin)
|
2018-08-01 14:56:46 +00:00
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error setting network status: %v", err)
|
2018-08-01 14:56:46 +00:00
|
|
|
}
|
|
|
|
|
2019-12-05 06:43:27 +00:00
|
|
|
netStatus = append(netStatus, *delegateNetStatus)
|
2018-07-30 10:59:13 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
2018-06-14 14:35:23 +00:00
|
|
|
|
2018-07-30 10:59:13 +00:00
|
|
|
//set the network status annotation in apiserver, only in case Multus as kubeconfig
|
2018-08-01 13:54:10 +00:00
|
|
|
if n.Kubeconfig != "" && kc != nil {
|
2019-12-04 09:21:06 +00:00
|
|
|
if !types.CheckSystemNamespaces(string(k8sArgs.K8S_POD_NAME), n.SystemNamespaces) {
|
2019-03-20 12:08:48 +00:00
|
|
|
err = k8s.SetNetworkStatus(kubeClient, k8sArgs, netStatus, n)
|
2018-08-01 13:54:10 +00:00
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return nil, cmdErr(k8sArgs, "error setting the networks status: %v", err)
|
2018-08-01 13:54:10 +00:00
|
|
|
}
|
2018-07-30 10:59:13 +00:00
|
|
|
}
|
2018-05-01 18:08:39 +00:00
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
|
2018-06-14 14:35:23 +00:00
|
|
|
return result, nil
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 14:57:22 +00:00
|
|
|
func cmdCheck(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) error {
|
2018-06-13 20:14:02 +00:00
|
|
|
in, err := types.LoadNetConf(args.StdinData)
|
2020-02-27 16:03:48 +00:00
|
|
|
logging.Debugf("cmdCheck: %v, %v, %v", args, exec, kubeClient)
|
2018-06-13 20:14:02 +00:00
|
|
|
if err != nil {
|
2020-01-13 14:57:22 +00:00
|
|
|
return err
|
2018-06-13 20:14:02 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 14:57:22 +00:00
|
|
|
k8sArgs, err := k8s.GetK8sArgs(args)
|
|
|
|
if err != nil {
|
|
|
|
return cmdErr(nil, "error getting k8s args: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for idx, delegate := range in.Delegates {
|
|
|
|
ifName := getIfname(delegate, args.IfName, idx)
|
|
|
|
|
|
|
|
runtimeConfig := types.MergeCNIRuntimeConfig(in.RuntimeConfig, delegate)
|
|
|
|
rt := types.CreateCNIRuntimeConf(args, k8sArgs, ifName, runtimeConfig)
|
|
|
|
err = delegateCheck(exec, ifName, delegate, rt, in.BinDir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-06-13 20:14:02 +00:00
|
|
|
|
2020-01-13 14:57:22 +00:00
|
|
|
return nil
|
2018-06-13 20:14:02 +00:00
|
|
|
}
|
|
|
|
|
2019-12-04 09:21:06 +00:00
|
|
|
func cmdDel(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) error {
|
2019-05-30 05:34:23 +00:00
|
|
|
in, err := types.LoadNetConf(args.StdinData)
|
2020-02-27 16:03:48 +00:00
|
|
|
logging.Debugf("cmdDel: %v, %v, %v", args, exec, kubeClient)
|
2016-12-13 14:48:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-05-03 13:23:43 +00:00
|
|
|
netnsfound := true
|
2018-08-02 10:10:19 +00:00
|
|
|
netns, err := ns.GetNS(args.Netns)
|
|
|
|
if err != nil {
|
2019-01-25 08:49:16 +00:00
|
|
|
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
2018-08-16 22:37:59 +00:00
|
|
|
// so don't return an error if the device is already removed.
|
|
|
|
// https://github.com/kubernetes/kubernetes/issues/43014#issuecomment-287164444
|
|
|
|
_, ok := err.(ns.NSPathNotExistErr)
|
|
|
|
if ok {
|
2019-05-03 13:23:43 +00:00
|
|
|
netnsfound = false
|
2019-05-30 05:34:23 +00:00
|
|
|
logging.Debugf("cmdDel: WARNING netns may not exist, netns: %s, err: %s", args.Netns, err)
|
2019-02-21 19:33:03 +00:00
|
|
|
} else {
|
2019-11-05 22:55:45 +00:00
|
|
|
return cmdErr(nil, "failed to open netns %q: %v", netns, err)
|
2018-08-02 10:10:19 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-21 19:33:03 +00:00
|
|
|
|
|
|
|
if netns != nil {
|
|
|
|
defer netns.Close()
|
|
|
|
}
|
2018-08-02 10:10:19 +00:00
|
|
|
|
2018-07-26 23:04:52 +00:00
|
|
|
k8sArgs, err := k8s.GetK8sArgs(args)
|
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return cmdErr(nil, "error getting k8s args: %v", err)
|
2018-07-26 23:04:52 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 12:19:31 +00:00
|
|
|
if in.ReadinessIndicatorFile != "" {
|
|
|
|
err := wait.PollImmediate(pollDuration, pollTimeout, func() (bool, error) {
|
|
|
|
_, err := os.Stat(in.ReadinessIndicatorFile)
|
|
|
|
return err == nil, nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return cmdErr(k8sArgs, "PollImmediate error waiting for ReadinessIndicatorFile (on del): %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 04:04:20 +00:00
|
|
|
kubeClient, err = k8s.GetK8sClient(in.Kubeconfig, kubeClient)
|
|
|
|
if err != nil {
|
|
|
|
return cmdErr(nil, "error getting k8s client: %v", err)
|
|
|
|
}
|
|
|
|
|
2020-05-18 09:16:51 +00:00
|
|
|
pod := (*v1.Pod)(nil)
|
|
|
|
if kubeClient != nil {
|
|
|
|
pod, err = kubeClient.GetPod(string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))
|
|
|
|
if err != nil {
|
2020-06-11 04:04:20 +00:00
|
|
|
var waitErr error
|
|
|
|
// in case of ServiceUnavailable, retry 10 times with 0.5 sec interval
|
|
|
|
if errors.IsServiceUnavailable(err) {
|
|
|
|
pollDuration := 500 * time.Millisecond
|
|
|
|
pollTimeout := 5 * time.Second
|
|
|
|
waitErr = wait.PollImmediate(pollDuration, pollTimeout, func() (bool, error) {
|
|
|
|
pod, err = kubeClient.GetPod(string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))
|
|
|
|
return pod != nil, err
|
|
|
|
})
|
|
|
|
// retry failed, then return error with retry out
|
|
|
|
if waitErr != nil {
|
|
|
|
return cmdErr(k8sArgs, "error getting pod by service unavailable: %v", err)
|
|
|
|
}
|
|
|
|
} else if errors.IsNotFound(err) {
|
|
|
|
// If not found, proceed to remove interface with cache
|
|
|
|
pod = nil
|
|
|
|
} else {
|
|
|
|
// Other case, return error
|
2020-05-18 09:16:51 +00:00
|
|
|
return cmdErr(k8sArgs, "error getting pod: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
// Read the cache to get delegates json for the pod
|
|
|
|
netconfBytes, path, err := consumeScratchNetConf(args.ContainerID, in.CNIDir)
|
2018-07-19 14:02:49 +00:00
|
|
|
if err != nil {
|
2020-06-11 04:04:20 +00:00
|
|
|
// Fetch delegates again if cache is not exist and pod info can be read
|
|
|
|
if os.IsNotExist(err) && pod != nil {
|
2019-01-25 08:49:16 +00:00
|
|
|
if in.ClusterNetwork != "" {
|
2020-05-18 09:16:51 +00:00
|
|
|
_, err = k8s.GetDefaultNetworks(pod, in, kubeClient, nil)
|
2019-01-25 08:49:16 +00:00
|
|
|
if err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return cmdErr(k8sArgs, "failed to get clusterNetwork/defaultNetworks: %v", err)
|
2019-01-25 08:49:16 +00:00
|
|
|
}
|
|
|
|
// First delegate is always the master plugin
|
|
|
|
in.Delegates[0].MasterPlugin = true
|
|
|
|
}
|
2017-06-29 16:19:09 +00:00
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
// Get pod annotation and so on
|
2020-05-18 09:16:51 +00:00
|
|
|
_, _, err := k8s.TryLoadPodDelegates(pod, in, kubeClient, nil)
|
2019-01-25 08:49:16 +00:00
|
|
|
if err != nil {
|
|
|
|
if len(in.Delegates) == 0 {
|
|
|
|
// No delegate available so send error
|
2019-11-05 22:55:45 +00:00
|
|
|
return cmdErr(k8sArgs, "failed to get delegates: %v", err)
|
2019-01-25 08:49:16 +00:00
|
|
|
}
|
|
|
|
// Get clusterNetwork before, so continue to delete
|
|
|
|
logging.Errorf("Multus: failed to get delegates: %v, but continue to delete clusterNetwork", err)
|
2017-11-09 17:55:37 +00:00
|
|
|
}
|
2019-01-25 08:49:16 +00:00
|
|
|
} else {
|
2019-11-05 22:55:45 +00:00
|
|
|
return cmdErr(k8sArgs, "error reading the delegates: %v", err)
|
2017-06-29 16:19:09 +00:00
|
|
|
}
|
2019-01-25 08:49:16 +00:00
|
|
|
} else {
|
|
|
|
defer os.Remove(path)
|
2017-09-28 14:42:56 +00:00
|
|
|
if err := json.Unmarshal(netconfBytes, &in.Delegates); err != nil {
|
2019-11-05 22:55:45 +00:00
|
|
|
return cmdErr(k8sArgs, "failed to load netconf: %v", err)
|
2017-06-29 16:19:09 +00:00
|
|
|
}
|
2019-03-29 12:31:49 +00:00
|
|
|
// check plugins field and enable ConfListPlugin if there is
|
|
|
|
for _, v := range in.Delegates {
|
|
|
|
if len(v.ConfList.Plugins) != 0 {
|
|
|
|
v.ConfListPlugin = true
|
|
|
|
}
|
|
|
|
}
|
2019-01-25 08:49:16 +00:00
|
|
|
// First delegate is always the master plugin
|
|
|
|
in.Delegates[0].MasterPlugin = true
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2019-05-30 07:36:13 +00:00
|
|
|
// set CNIVersion in delegate CNI config if there is no CNIVersion and multus conf have CNIVersion.
|
|
|
|
for _, v := range in.Delegates {
|
|
|
|
if v.ConfListPlugin == true && v.ConfList.CNIVersion == "" && in.CNIVersion != "" {
|
|
|
|
v.ConfList.CNIVersion = in.CNIVersion
|
|
|
|
v.Bytes, err = json.Marshal(v.ConfList)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-25 08:49:16 +00:00
|
|
|
// unset the network status annotation in apiserver, only in case Multus as kubeconfig
|
|
|
|
if in.Kubeconfig != "" {
|
2019-05-03 13:23:43 +00:00
|
|
|
if netnsfound {
|
|
|
|
if !types.CheckSystemNamespaces(string(k8sArgs.K8S_POD_NAMESPACE), in.SystemNamespaces) {
|
|
|
|
err := k8s.SetNetworkStatus(kubeClient, k8sArgs, nil, in)
|
|
|
|
if err != nil {
|
|
|
|
// error happen but continue to delete
|
2019-10-02 09:02:26 +00:00
|
|
|
logging.Errorf("Multus: error unsetting the networks status: %v", err)
|
2019-05-03 13:23:43 +00:00
|
|
|
}
|
2018-08-01 13:54:10 +00:00
|
|
|
}
|
2019-05-03 13:23:43 +00:00
|
|
|
} else {
|
|
|
|
logging.Debugf("WARNING: Unset SetNetworkStatus skipped due to netns not found.")
|
2018-07-30 10:59:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-04 15:33:47 +00:00
|
|
|
rt := types.CreateCNIRuntimeConf(args, k8sArgs, "", in.RuntimeConfig)
|
2020-03-18 08:21:43 +00:00
|
|
|
return delPlugins(exec, pod, args.IfName, in.Delegates, len(in.Delegates)-1, rt, in.BinDir)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2018-12-06 03:52:30 +00:00
|
|
|
|
|
|
|
// Init command line flags to clear vendored packages' one, especially in init()
|
|
|
|
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
|
|
|
|
|
|
|
// add version flag
|
|
|
|
versionOpt := false
|
|
|
|
flag.BoolVar(&versionOpt, "version", false, "Show application version")
|
|
|
|
flag.BoolVar(&versionOpt, "v", false, "Show application version")
|
|
|
|
flag.Parse()
|
|
|
|
if versionOpt == true {
|
|
|
|
fmt.Printf("%s\n", printVersionString())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-14 03:47:31 +00:00
|
|
|
skel.PluginMain(
|
2018-06-14 14:35:23 +00:00
|
|
|
func(args *skel.CmdArgs) error {
|
2018-06-14 18:15:02 +00:00
|
|
|
result, err := cmdAdd(args, nil, nil)
|
2018-06-14 14:35:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return result.Print()
|
|
|
|
},
|
|
|
|
func(args *skel.CmdArgs) error {
|
2020-01-13 14:57:22 +00:00
|
|
|
return cmdCheck(args, nil, nil)
|
2018-06-14 14:35:23 +00:00
|
|
|
},
|
2018-06-14 18:15:02 +00:00
|
|
|
func(args *skel.CmdArgs) error { return cmdDel(args, nil, nil) },
|
2018-12-06 03:52:30 +00:00
|
|
|
cniversion.All, "meta-plugin that delegates to other CNI plugins")
|
2018-11-29 18:49:55 +00:00
|
|
|
}
|