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.
2020-05-28 20:43:59 +00:00
package multus
2016-12-13 14:48:12 +00:00
import (
2019-05-15 08:06:26 +00:00
"context"
2016-12-13 14:48:12 +00:00
"encoding/json"
"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-06-13 19:51:29 +00:00
"github.com/containernetworking/plugins/pkg/ns"
2021-03-10 19:14:57 +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"
2021-03-16 07:08:53 +00:00
k8s "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/k8sclient"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/netutils"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/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"
2021-06-24 11:35:41 +00:00
k8snet "k8s.io/apimachinery/pkg/util/net"
2018-10-10 18:09:38 +00:00
"k8s.io/apimachinery/pkg/util/wait"
2016-12-13 14:48:12 +00:00
)
2021-06-25 14:26:50 +00:00
const (
shortPollDuration = 250 * time . Millisecond
2021-09-10 12:50:23 +00:00
shortPollTimeout = 2500 * time . Millisecond
2021-06-25 14:26:50 +00:00
)
2020-11-19 09:30:12 +00:00
var (
version = "master@git"
commit = "unknown commit"
date = "unknown date"
)
2018-12-06 03:52:30 +00:00
2020-11-19 09:30:12 +00:00
var (
pollDuration = 1000 * time . Millisecond
pollTimeout = 45 * time . Second
)
2018-10-10 18:09:38 +00:00
2021-02-22 22:57:26 +00:00
//PrintVersionString ...
2020-05-28 20:43:59 +00:00
func PrintVersionString ( ) string {
2018-12-06 03:52:30 +00:00
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
}
2020-11-03 20:40:30 +00:00
func getDelegateDeviceInfo ( delegate * types . DelegateNetConf , runtimeConf * libcni . RuntimeConf ) ( * nettypes . DeviceInfo , error ) {
// If the DPDeviceInfoFile was created, it was copied to the CNIDeviceInfoFile.
// If the DPDeviceInfoFile was not created, CNI might have created it. So
// either way, load CNIDeviceInfoFile.
if info , ok := runtimeConf . CapabilityArgs [ "CNIDeviceInfoFile" ] ; ok {
if infostr , ok := info . ( string ) ; ok {
return nadutils . LoadDeviceInfoFromCNI ( infostr )
}
} else {
logging . Debugf ( "getDelegateDeviceInfo(): No CapArgs - info=%v ok=%v" , info , ok )
}
return nil , nil
}
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
}
2021-03-26 19:12:10 +00:00
func confAdd ( rt * libcni . RuntimeConf , rawNetconf [ ] byte , multusNetconf * types . NetConf , exec invoke . Exec ) ( cnitypes . Result , error ) {
logging . Debugf ( "confAdd: %v, %s" , rt , string ( rawNetconf ) )
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" ) )
2021-03-26 19:12:10 +00:00
binDirs = append ( [ ] string { multusNetconf . BinDir } , binDirs ... )
cniNet := libcni . NewCNIConfigWithCacheDir ( binDirs , multusNetconf . CNIDir , exec )
2019-08-16 09:55:12 +00:00
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
}
2021-03-26 19:12:10 +00:00
func confCheck ( rt * libcni . RuntimeConf , rawNetconf [ ] byte , multusNetconf * types . NetConf , exec invoke . Exec ) error {
logging . Debugf ( "confCheck: %v, %s" , rt , string ( rawNetconf ) )
2020-01-13 14:57:22 +00:00
binDirs := filepath . SplitList ( os . Getenv ( "CNI_PATH" ) )
2021-03-26 19:12:10 +00:00
binDirs = append ( [ ] string { multusNetconf . BinDir } , binDirs ... )
cniNet := libcni . NewCNIConfigWithCacheDir ( binDirs , multusNetconf . CNIDir , exec )
2020-01-13 14:57:22 +00:00
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
}
2021-03-26 19:12:10 +00:00
func confDel ( rt * libcni . RuntimeConf , rawNetconf [ ] byte , multusNetconf * types . NetConf , exec invoke . Exec ) error {
logging . Debugf ( "conflistDel: %v, %s" , rt , string ( rawNetconf ) )
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" ) )
2021-03-26 19:12:10 +00:00
binDirs = append ( [ ] string { multusNetconf . BinDir } , binDirs ... )
cniNet := libcni . NewCNIConfigWithCacheDir ( binDirs , multusNetconf . CNIDir , exec )
2019-08-16 09:55:12 +00:00
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
}
2021-03-26 19:12:10 +00:00
func conflistAdd ( rt * libcni . RuntimeConf , rawnetconflist [ ] byte , multusNetconf * types . NetConf , exec invoke . Exec ) ( cnitypes . Result , error ) {
logging . Debugf ( "conflistAdd: %v, %s" , rt , string ( rawnetconflist ) )
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" ) )
2021-03-26 19:12:10 +00:00
binDirs = append ( [ ] string { multusNetconf . BinDir } , binDirs ... )
cniNet := libcni . NewCNIConfigWithCacheDir ( binDirs , multusNetconf . CNIDir , 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
}
2021-03-26 19:12:10 +00:00
func conflistCheck ( rt * libcni . RuntimeConf , rawnetconflist [ ] byte , multusNetconf * types . NetConf , exec invoke . Exec ) error {
logging . Debugf ( "conflistCheck: %v, %s" , rt , string ( rawnetconflist ) )
2020-01-13 14:57:22 +00:00
binDirs := filepath . SplitList ( os . Getenv ( "CNI_PATH" ) )
2021-03-26 19:12:10 +00:00
binDirs = append ( [ ] string { multusNetconf . BinDir } , binDirs ... )
cniNet := libcni . NewCNIConfigWithCacheDir ( binDirs , multusNetconf . CNIDir , exec )
2020-01-13 14:57:22 +00:00
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
}
2021-03-26 19:12:10 +00:00
func conflistDel ( rt * libcni . RuntimeConf , rawnetconflist [ ] byte , multusNetconf * types . NetConf , exec invoke . Exec ) error {
logging . Debugf ( "conflistDel: %v, %s" , rt , string ( rawnetconflist ) )
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" ) )
2021-03-26 19:12:10 +00:00
binDirs = append ( [ ] string { multusNetconf . BinDir } , binDirs ... )
cniNet := libcni . NewCNIConfigWithCacheDir ( binDirs , multusNetconf . CNIDir , 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
}
2021-03-26 19:12:10 +00:00
func delegateAdd ( exec invoke . Exec , kubeClient * k8s . ClientInfo , pod * v1 . Pod , ifName string , delegate * types . DelegateNetConf , rt * libcni . RuntimeConf , multusNetconf * types . NetConf , cniArgs string ) ( cnitypes . Result , error ) {
logging . Debugf ( "delegateAdd: %v, %s, %v, %v" , exec , ifName , delegate , rt )
2018-05-01 18:08:39 +00:00
if os . Setenv ( "CNI_IFNAME" , ifName ) != nil {
2021-09-10 12:50:23 +00:00
return nil , logging . Errorf ( "delegateAdd: error setting environment 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 {
2021-03-26 19:12:10 +00:00
result , err = conflistAdd ( rt , delegate . Bytes , multusNetconf , 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 {
2021-03-26 19:12:10 +00:00
result , err = confAdd ( rt , delegate . Bytes , multusNetconf , 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 {
2021-03-16 07:08:53 +00:00
// for further debug https://github.com/k8snetworkplumbingwg/multus-cni/issues/481
2020-04-20 15:45:40 +00:00
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
}
2021-03-26 19:12:10 +00:00
func delegateCheck ( exec invoke . Exec , ifName string , delegateConf * types . DelegateNetConf , rt * libcni . RuntimeConf , multusNetconf * types . NetConf ) error {
logging . Debugf ( "delegateCheck: %v, %s, %v, %v" , exec , ifName , delegateConf , rt )
2020-01-13 14:57:22 +00:00
if os . Setenv ( "CNI_IFNAME" , ifName ) != nil {
2021-09-10 12:50:23 +00:00
return logging . Errorf ( "delegateCheck: error setting environment variable CNI_IFNAME" )
2020-01-13 14:57:22 +00:00
}
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 {
2021-03-26 19:12:10 +00:00
err = conflistCheck ( rt , delegateConf . Bytes , multusNetconf , exec )
2020-01-13 14:57:22 +00:00
if err != nil {
return logging . Errorf ( "delegateCheck: error invoking ConflistCheck - %q: %v" , delegateConf . ConfList . Name , err )
}
} else {
2021-03-26 19:12:10 +00:00
err = confCheck ( rt , delegateConf . Bytes , multusNetconf , exec )
2020-01-13 14:57:22 +00:00
if err != nil {
return logging . Errorf ( "delegateCheck: error invoking DelegateCheck - %q: %v" , delegateConf . Conf . Type , err )
}
}
return err
}
2021-03-26 19:12:10 +00:00
func delegateDel ( exec invoke . Exec , pod * v1 . Pod , ifName string , delegateConf * types . DelegateNetConf , rt * libcni . RuntimeConf , multusNetconf * types . NetConf ) error {
logging . Debugf ( "delegateDel: %v, %v, %s, %v, %v" , exec , pod , ifName , delegateConf , rt )
2018-05-01 18:08:39 +00:00
if os . Setenv ( "CNI_IFNAME" , ifName ) != nil {
2021-09-10 12:50:23 +00:00
return logging . Errorf ( "delegateDel: error setting environment 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 {
2021-03-26 19:12:10 +00:00
err = conflistDel ( rt , delegateConf . Bytes , multusNetconf , exec )
2019-03-07 16:00:46 +00:00
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 {
2021-03-26 19:12:10 +00:00
err = confDel ( rt , delegateConf . Bytes , multusNetconf , exec )
2019-08-16 09:55:12 +00:00
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-10-27 21:21:28 +00:00
// delPlugins deletes plugins in reverse order from lastdIdx
// Uses netRt as base RuntimeConf (coming from NetConf) but merges it
// with each of the delegates' configuration
2021-03-26 19:12:10 +00:00
func delPlugins ( exec invoke . Exec , pod * v1 . Pod , args * skel . CmdArgs , k8sArgs * types . K8sArgs , delegates [ ] * types . DelegateNetConf , lastIdx int , netRt * types . RuntimeConfig , multusNetconf * types . NetConf ) error {
logging . Debugf ( "delPlugins: %v, %v, %v, %v, %v, %d, %v" , exec , pod , args , k8sArgs , delegates , lastIdx , netRt )
2017-02-21 19:01:58 +00:00
if os . Setenv ( "CNI_COMMAND" , "DEL" ) != nil {
2020-10-27 21:21:28 +00:00
return logging . Errorf ( "delPlugins: error setting environment 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 -- {
2020-10-27 21:21:28 +00:00
ifName := getIfname ( delegates [ idx ] , args . IfName , idx )
2020-11-03 14:42:30 +00:00
rt , cniDeviceInfoPath := types . CreateCNIRuntimeConf ( args , k8sArgs , ifName , netRt , delegates [ idx ] )
2018-11-29 18:49:55 +00:00
// Attempt to delete all but do not error out, instead, collect all errors.
2021-03-26 19:12:10 +00:00
if err := delegateDel ( exec , pod , ifName , delegates [ idx ] , rt , multusNetconf ) ; err != nil {
2018-11-29 18:49:55 +00:00
errorstrings = append ( errorstrings , err . Error ( ) )
2017-02-21 19:01:58 +00:00
}
2020-11-03 14:42:30 +00:00
if cniDeviceInfoPath != "" {
err := nadutils . CleanDeviceInfoForCNI ( cniDeviceInfoPath )
// Even if the filename is set, file may not be present. Ignore error,
// but log and in the future may need to filter on specific errors.
if err != nil {
logging . Debugf ( "delPlugins: CleanDeviceInfoForCNI returned an error - err=%v" , err )
}
}
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 {
2021-10-21 15:44:29 +00:00
prefix += fmt . Sprintf ( "[%s/%s/%s]: " , k8sArgs . K8S_POD_NAMESPACE , k8sArgs . K8S_POD_NAME , k8sArgs . K8S_POD_UID )
2019-11-05 22:55:45 +00:00
}
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 {
2021-10-21 15:44:29 +00:00
msg += fmt . Sprintf ( "[%s/%s/%s:%s]: " , k8sArgs . K8S_POD_NAMESPACE , k8sArgs . K8S_POD_NAME , k8sArgs . K8S_POD_UID , confName )
2020-04-30 08:38:49 +00:00
}
return logging . Errorf ( msg + format , args ... )
}
2021-06-24 11:35:41 +00:00
func isCriticalRequestRetriable ( err error ) bool {
logging . Debugf ( "isCriticalRequestRetriable: %v" , err )
errorTypesAllowingRetry := [ ] func ( error ) bool {
errors . IsServiceUnavailable , errors . IsInternalError , k8snet . IsConnectionReset , k8snet . IsConnectionRefused }
for _ , f := range errorTypesAllowingRetry {
if f ( err ) {
return true
}
}
return false
}
2021-11-23 08:52:45 +00:00
func getPod ( kubeClient * k8s . ClientInfo , k8sArgs * types . K8sArgs , warnOnly bool ) ( * v1 . Pod , error ) {
2021-10-21 15:44:29 +00:00
if kubeClient == nil {
return nil , nil
}
podNamespace := string ( k8sArgs . K8S_POD_NAMESPACE )
podName := string ( k8sArgs . K8S_POD_NAME )
podUID := string ( k8sArgs . K8S_POD_UID )
pod , err := kubeClient . GetPod ( podNamespace , podName )
if err != nil {
// in case of a retriable error, retry 10 times with 0.25 sec interval
if isCriticalRequestRetriable ( err ) {
waitErr := wait . PollImmediate ( shortPollDuration , shortPollTimeout , func ( ) ( bool , error ) {
pod , err = kubeClient . GetPod ( podNamespace , podName )
return pod != nil , err
} )
// retry failed, then return error with retry out
if waitErr != nil {
return nil , cmdErr ( k8sArgs , "error waiting for pod: %v" , err )
}
2021-11-23 08:52:45 +00:00
} else if warnOnly && errors . IsNotFound ( err ) {
2021-10-21 15:44:29 +00:00
// If not found, proceed to remove interface with cache
return nil , nil
} else {
// Other case, return error
return nil , cmdErr ( k8sArgs , "error getting pod: %v" , err )
}
}
if podUID != "" && string ( pod . UID ) != podUID {
2021-11-23 08:52:45 +00:00
msg := fmt . Sprintf ( "expected pod UID %q but got %q from Kube API" , podUID , pod . UID )
if warnOnly {
// On CNI DEL we just operate on the cache when these mismatch, we don't error out.
// For example: stateful sets namespace/name can remain the same while podUID changes.
logging . Verbosef ( "warning: %s" , msg )
return nil , nil
}
return nil , cmdErr ( k8sArgs , msg )
2021-10-21 15:44:29 +00:00
}
return pod , nil
}
2021-02-22 22:57:26 +00:00
//CmdAdd ...
2020-05-28 20:43:59 +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 )
2020-05-28 20:43:59 +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 {
2021-03-22 21:26:40 +00:00
return nil , cmdErr ( k8sArgs , "have you checked that your default network is ready? still waiting for readinessindicatorfile @ %v. pollimmediate error: %v" , n . ReadinessIndicatorFile , 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
2021-10-21 15:44:29 +00:00
pod , err := getPod ( kubeClient , k8sArgs , false )
if err != nil {
return nil , err
2020-05-18 09:16:51 +00:00
}
// 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 )
2020-11-03 14:42:30 +00:00
rt , cniDeviceInfoPath := types . CreateCNIRuntimeConf ( args , k8sArgs , ifName , n . RuntimeConfig , delegate )
2021-03-31 17:22:54 +00:00
if cniDeviceInfoPath != "" && delegate . ResourceName != "" && delegate . DeviceID != "" {
2020-11-03 14:42:30 +00:00
err = nadutils . CopyDeviceInfoForCNIFromDP ( cniDeviceInfoPath , delegate . ResourceName , delegate . DeviceID )
// Even if the filename is set, file may not be present. Ignore error,
// but log and in the future may need to filter on specific errors.
if err != nil {
logging . Debugf ( "cmdAdd: CopyDeviceInfoForCNIFromDP returned an error - err=%v" , err )
}
}
2019-08-16 09:55:12 +00:00
2021-12-03 15:48:50 +00:00
netName := ""
2021-03-26 19:12:10 +00:00
tmpResult , err = delegateAdd ( exec , kubeClient , pod , ifName , delegate , rt , n , 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
2021-12-03 15:48:50 +00:00
netName = delegate . Conf . Name
2019-02-04 15:33:47 +00:00
if netName == "" {
netName = delegate . ConfList . Name
}
// Ignore errors; DEL must be idempotent anyway
2021-03-26 19:12:10 +00:00
_ = delPlugins ( exec , nil , args , k8sArgs , n . Delegates , idx , n . RuntimeConfig , n )
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
2021-12-03 15:48:50 +00:00
deleteV4gateway := false
deleteV6gateway := false
2019-10-23 15:40:44 +00:00
adddefaultgateway := false
2021-12-03 15:48:50 +00:00
if delegate . IsFilterV4Gateway {
deleteV4gateway = true
logging . Debugf ( "Marked interface %v for v4 gateway deletion" , ifName )
2019-10-23 15:40:44 +00:00
} else {
// Otherwise, determine if this interface now gets our default route.
2021-03-10 19:14:57 +00:00
// According to
2020-09-08 21:53:25 +00:00
// https://docs.google.com/document/d/1Ny03h6IDVy_e_vmElOqR7UdTPAG_RNydhVE1Kx54kFQ (4.1.2.1.9)
// the list can be empty; if it is, we'll assume the CNI's config for the default gateway holds,
// else we'll update the defaultgateway to the one specified.
if delegate . GatewayRequest != nil && delegate . GatewayRequest [ 0 ] != nil {
2021-12-03 15:48:50 +00:00
deleteV4gateway = true
2019-10-23 15:40:44 +00:00
adddefaultgateway = true
logging . Debugf ( "Detected gateway override on interface %v to %v" , ifName , delegate . GatewayRequest )
}
}
2021-12-03 15:48:50 +00:00
if delegate . IsFilterV6Gateway {
deleteV6gateway = true
logging . Debugf ( "Marked interface %v for v6 gateway deletion" , ifName )
} else {
// Otherwise, determine if this interface now gets our default route.
// According to
// https://docs.google.com/document/d/1Ny03h6IDVy_e_vmElOqR7UdTPAG_RNydhVE1Kx54kFQ (4.1.2.1.9)
// the list can be empty; if it is, we'll assume the CNI's config for the default gateway holds,
// else we'll update the defaultgateway to the one specified.
if delegate . GatewayRequest != nil && delegate . GatewayRequest [ 0 ] != nil {
deleteV6gateway = true
adddefaultgateway = true
logging . Debugf ( "Detected gateway override on interface %v to %v" , ifName , delegate . GatewayRequest )
}
}
// Remove namespace from delegate.Name for Add/Del CNI cache
nameSlice := strings . Split ( delegate . Name , "/" )
2022-01-04 16:33:58 +00:00
netName = nameSlice [ len ( nameSlice ) - 1 ]
2021-12-03 15:48:50 +00:00
// Remove gateway if `default-route` network selection is specified
2022-01-04 16:33:58 +00:00
if deleteV4gateway || deleteV6gateway {
2021-12-03 15:48:50 +00:00
err = netutils . DeleteDefaultGW ( args , ifName )
2019-08-27 07:52:58 +00:00
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
}
2021-12-03 15:48:50 +00:00
err = netutils . DeleteDefaultGWCache ( n . CNIDir , rt , netName , ifName , deleteV4gateway , deleteV6gateway )
if err != nil {
return nil , cmdErr ( k8sArgs , "error deleting default gateway in cache: %v" , err )
}
2019-08-27 07:52:58 +00:00
}
2021-12-03 15:48:50 +00:00
// Here we'll set the default gateway which specified in `default-route` network selection
2019-10-23 15:40:44 +00:00
if adddefaultgateway {
2021-12-03 15:48:50 +00:00
err = netutils . SetDefaultGW ( args , ifName , delegate . GatewayRequest )
2019-10-23 15:40:44 +00:00
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
}
2021-12-03 15:48:50 +00:00
err = netutils . AddDefaultGWCache ( n . CNIDir , rt , netName , ifName , delegate . GatewayRequest )
if err != nil {
return nil , cmdErr ( k8sArgs , "error setting default gateway in cache: %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
2020-11-03 20:40:30 +00:00
// Read devInfo from CNIDeviceInfoFile if it exists so
// it can be copied to the NetworkStatus.
devinfo , err := getDelegateDeviceInfo ( delegate , rt )
if err != nil {
// Even if the filename is set, file may not be present. Ignore error,
// but log and in the future may need to filter on specific errors.
logging . Debugf ( "cmdAdd: getDelegateDeviceInfo returned an error - err=%v" , err )
}
2020-11-19 09:30:12 +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-11-03 20:40:30 +00:00
delegateNetStatus , err := nadutils . CreateNetworkStatus ( tmpResult , delegate . Name , delegate . MasterPlugin , devinfo )
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
}
2020-11-03 20:40:30 +00:00
} else if devinfo != nil {
// Warn that devinfo exists but could not add it to downwards API
logging . Errorf ( "devinfo available, but no kubeConfig so NetworkStatus not modified." )
2018-07-30 10:59:13 +00:00
}
2016-12-13 14:48:12 +00:00
}
2018-06-14 14:35:23 +00:00
2020-11-19 09:30:12 +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 {
2020-11-19 09:30:12 +00:00
if strings . Contains ( err . Error ( ) , "failed to query the pod" ) {
return nil , cmdErr ( k8sArgs , "error setting the networks status, pod was already deleted: %v" , err )
}
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
}
2021-02-22 22:57:26 +00:00
//CmdCheck ...
2020-05-28 20:43:59 +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-05-28 20:43:59 +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 )
2020-11-03 14:42:30 +00:00
rt , _ := types . CreateCNIRuntimeConf ( args , k8sArgs , ifName , in . RuntimeConfig , delegate )
2021-03-26 19:12:10 +00:00
err = delegateCheck ( exec , ifName , delegate , rt , in )
2020-01-13 14:57:22 +00:00
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
}
2021-02-22 22:57:26 +00:00
//CmdDel ...
2020-05-28 20:43:59 +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-05-28 20:43:59 +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
2020-05-28 20:43:59 +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 )
}
2021-10-21 15:44:29 +00:00
pod , err := getPod ( kubeClient , k8sArgs , true )
if err != nil {
return err
2020-05-18 09:16:51 +00:00
}
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 {
2020-11-24 18:18:34 +00:00
// The options to continue with a delete have been exhausted (cachefile + API query didn't work)
// We cannot exit with an error as this may cause a sandbox to never get deleted.
logging . Errorf ( "Multus: failed to get the cached delegates file: %v, cannot properly delete" , err )
return nil
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 )
2021-10-21 18:22:04 +00:00
if err != nil {
// error happen but continue to delete
logging . Errorf ( "Multus: failed to marshal delegate %q config: %v" , v . Name , err )
}
2019-05-30 07:36:13 +00:00
}
}
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
}
}
2021-03-26 19:12:10 +00:00
return delPlugins ( exec , pod , args , k8sArgs , in . Delegates , len ( in . Delegates ) - 1 , in . RuntimeConfig , in )
2016-12-13 14:48:12 +00:00
}