forked from github/multus-cni
Add delegate API in multus-daemon (#890)
This changes introduce delegate API function in multus-daemon. This API will be consumed from other programs for hot-plug interface into running pod. This change also cleanups server code to split into client code and server code to easy to import from other golang code.
This commit is contained in:
parent
8dee74d7b9
commit
505ab4567c
@ -32,6 +32,7 @@ import (
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/multus"
|
||||
srv "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server/api"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server/config"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/types"
|
||||
|
||||
@ -251,9 +252,9 @@ func startMultusDaemon(configFilePath string) error {
|
||||
}, 0)
|
||||
}
|
||||
|
||||
l, err := srv.GetListener(srv.SocketPath(daemonConfig.MultusSocketDir))
|
||||
l, err := srv.GetListener(api.SocketPath(daemonConfig.MultusSocketDir))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start the CNI server using socket %s. Reason: %+v", srv.SocketPath(daemonConfig.MultusSocketDir), err)
|
||||
return fmt.Errorf("failed to start the CNI server using socket %s. Reason: %+v", api.SocketPath(daemonConfig.MultusSocketDir), err)
|
||||
}
|
||||
|
||||
server.SetKeepAlivesEnabled(false)
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
cniversion "github.com/containernetworking/cni/pkg/version"
|
||||
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/multus"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server/api"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -46,13 +46,13 @@ func main() {
|
||||
|
||||
skel.PluginMain(
|
||||
func(args *skel.CmdArgs) error {
|
||||
return server.CmdAdd(args)
|
||||
return api.CmdAdd(args)
|
||||
},
|
||||
func(args *skel.CmdArgs) error {
|
||||
return server.CmdCheck(args)
|
||||
return api.CmdCheck(args)
|
||||
},
|
||||
func(args *skel.CmdArgs) error {
|
||||
return server.CmdDel(args)
|
||||
return api.CmdDel(args)
|
||||
},
|
||||
cniversion.All, "meta-plugin that delegates to other CNI plugins")
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ The server configuration is encoded in JSON, and allows the following keys:
|
||||
|
||||
- `"chrootDir"`: Specify the directory which points to host root from the pod. See 'Chroot configuration' section for the details.
|
||||
- `"socketDir"`: Specify the location where the unix domain socket used for
|
||||
client/server communication will be located. Defaults to `"/run/multus-cni"`.
|
||||
client/server communication will be located. Defaults to `"/run/multus"`.
|
||||
|
||||
In addition, you can add any configuration which is in [configuration reference](https://github.com/k8snetworkplumbingwg/multus-cni/blob/master/docs/configuration.md#multus-cni-configuration-reference). Server configuration override multus CNI configuration (e.g. `/etc/cni/net.d/00-multus.conf`)
|
||||
|
||||
|
@ -287,11 +287,12 @@ func conflistDel(rt *libcni.RuntimeConf, rawnetconflist []byte, multusNetconf *t
|
||||
return err
|
||||
}
|
||||
|
||||
func delegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, delegate *types.DelegateNetConf, rt *libcni.RuntimeConf, multusNetconf *types.NetConf) (cnitypes.Result, error) {
|
||||
logging.Debugf("delegateAdd: %v, %v, %v", exec, delegate, rt)
|
||||
// DelegateAdd ...
|
||||
func DelegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, delegate *types.DelegateNetConf, rt *libcni.RuntimeConf, multusNetconf *types.NetConf) (cnitypes.Result, error) {
|
||||
logging.Debugf("DelegateAdd: %v, %v, %v", exec, delegate, rt)
|
||||
|
||||
if err := validateIfName(rt.NetNS, rt.IfName); err != nil {
|
||||
return nil, logging.Errorf("delegateAdd: cannot set %q interface name to %q: %v", delegate.Conf.Type, rt.IfName, err)
|
||||
return nil, logging.Errorf("DelegateAdd: cannot set %q interface name to %q: %v", delegate.Conf.Type, rt.IfName, err)
|
||||
}
|
||||
|
||||
// Deprecated in ver 3.5.
|
||||
@ -300,10 +301,10 @@ func delegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, dele
|
||||
// validate Mac address
|
||||
_, err := net.ParseMAC(delegate.MacRequest)
|
||||
if err != nil {
|
||||
return nil, logging.Errorf("delegateAdd: failed to parse mac address %q", delegate.MacRequest)
|
||||
return nil, logging.Errorf("DelegateAdd: failed to parse mac address %q", delegate.MacRequest)
|
||||
}
|
||||
|
||||
logging.Debugf("delegateAdd: set MAC address %q to %q", delegate.MacRequest, rt.IfName)
|
||||
logging.Debugf("DelegateAdd: set MAC address %q to %q", delegate.MacRequest, rt.IfName)
|
||||
rt.Args = append(rt.Args, [2]string{"MAC", delegate.MacRequest})
|
||||
}
|
||||
|
||||
@ -313,15 +314,15 @@ func delegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, dele
|
||||
if strings.Contains(ip, "/") {
|
||||
_, _, err := net.ParseCIDR(ip)
|
||||
if err != nil {
|
||||
return nil, logging.Errorf("delegateAdd: failed to parse IP address %q", ip)
|
||||
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)
|
||||
return nil, logging.Errorf("DelegateAdd: failed to parse IP address %q", ip)
|
||||
}
|
||||
}
|
||||
|
||||
ips := strings.Join(delegate.IPRequest, ",")
|
||||
logging.Debugf("delegateAdd: set IP address %q to %q", ips, rt.IfName)
|
||||
logging.Debugf("DelegateAdd: set IP address %q to %q", ips, rt.IfName)
|
||||
rt.Args = append(rt.Args, [2]string{"IP", ips})
|
||||
}
|
||||
}
|
||||
@ -360,7 +361,7 @@ func delegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, dele
|
||||
ips := []string{}
|
||||
res, err := cni100.NewResultFromResult(result)
|
||||
if err != nil {
|
||||
logging.Errorf("delegateAdd: error converting result: %v", err)
|
||||
logging.Errorf("DelegateAdd: error converting result: %v", err)
|
||||
return result, nil
|
||||
}
|
||||
for _, ip := range res.IPs {
|
||||
@ -376,13 +377,14 @@ func delegateAdd(exec invoke.Exec, kubeClient *k8s.ClientInfo, pod *v1.Pod, dele
|
||||
}
|
||||
} else {
|
||||
// for further debug https://github.com/k8snetworkplumbingwg/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)
|
||||
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)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func delegateCheck(exec invoke.Exec, delegateConf *types.DelegateNetConf, rt *libcni.RuntimeConf, multusNetconf *types.NetConf) error {
|
||||
logging.Debugf("delegateCheck: %v, %v, %v", exec, delegateConf, rt)
|
||||
// DelegateCheck ...
|
||||
func DelegateCheck(exec invoke.Exec, delegateConf *types.DelegateNetConf, rt *libcni.RuntimeConf, multusNetconf *types.NetConf) error {
|
||||
logging.Debugf("DelegateCheck: %v, %v, %v", exec, delegateConf, rt)
|
||||
|
||||
if logging.GetLoggingLevel() >= logging.VerboseLevel {
|
||||
var cniConfName string
|
||||
@ -398,20 +400,21 @@ func delegateCheck(exec invoke.Exec, delegateConf *types.DelegateNetConf, rt *li
|
||||
if delegateConf.ConfListPlugin {
|
||||
err = conflistCheck(rt, delegateConf.Bytes, multusNetconf, exec)
|
||||
if err != nil {
|
||||
return logging.Errorf("delegateCheck: error invoking ConflistCheck - %q: %v", delegateConf.ConfList.Name, err)
|
||||
return logging.Errorf("DelegateCheck: error invoking ConflistCheck - %q: %v", delegateConf.ConfList.Name, err)
|
||||
}
|
||||
} else {
|
||||
err = confCheck(rt, delegateConf.Bytes, multusNetconf, exec)
|
||||
if err != nil {
|
||||
return logging.Errorf("delegateCheck: error invoking DelegateCheck - %q: %v", delegateConf.Conf.Type, err)
|
||||
return logging.Errorf("DelegateCheck: error invoking DelegateCheck - %q: %v", delegateConf.Conf.Type, err)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func delegateDel(exec invoke.Exec, pod *v1.Pod, delegateConf *types.DelegateNetConf, rt *libcni.RuntimeConf, multusNetconf *types.NetConf) error {
|
||||
logging.Debugf("delegateDel: %v, %v, %v, %v", exec, pod, delegateConf, rt)
|
||||
// DelegateDel ...
|
||||
func DelegateDel(exec invoke.Exec, pod *v1.Pod, delegateConf *types.DelegateNetConf, rt *libcni.RuntimeConf, multusNetconf *types.NetConf) error {
|
||||
logging.Debugf("DelegateDel: %v, %v, %v, %v", exec, pod, delegateConf, rt)
|
||||
|
||||
if logging.GetLoggingLevel() >= logging.VerboseLevel {
|
||||
var confName string
|
||||
@ -431,12 +434,12 @@ func delegateDel(exec invoke.Exec, pod *v1.Pod, delegateConf *types.DelegateNetC
|
||||
if delegateConf.ConfListPlugin {
|
||||
err = conflistDel(rt, delegateConf.Bytes, multusNetconf, exec)
|
||||
if err != nil {
|
||||
return logging.Errorf("delegateDel: error invoking ConflistDel - %q: %v", delegateConf.ConfList.Name, err)
|
||||
return logging.Errorf("DelegateDel: error invoking ConflistDel - %q: %v", delegateConf.ConfList.Name, err)
|
||||
}
|
||||
} else {
|
||||
err = confDel(rt, delegateConf.Bytes, multusNetconf, exec)
|
||||
if err != nil {
|
||||
return logging.Errorf("delegateDel: error invoking DelegateDel - %q: %v", delegateConf.Conf.Type, err)
|
||||
return logging.Errorf("DelegateDel: error invoking DelegateDel - %q: %v", delegateConf.Conf.Type, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,7 +457,7 @@ func delPlugins(exec invoke.Exec, pod *v1.Pod, args *skel.CmdArgs, k8sArgs *type
|
||||
ifName := getIfname(delegates[idx], args.IfName, idx)
|
||||
rt, cniDeviceInfoPath := types.CreateCNIRuntimeConf(args, k8sArgs, ifName, netRt, delegates[idx])
|
||||
// Attempt to delete all but do not error out, instead, collect all errors.
|
||||
if err := delegateDel(exec, pod, delegates[idx], rt, multusNetconf); err != nil {
|
||||
if err := DelegateDel(exec, pod, delegates[idx], rt, multusNetconf); err != nil {
|
||||
errorstrings = append(errorstrings, err.Error())
|
||||
}
|
||||
if cniDeviceInfoPath != "" {
|
||||
@ -503,7 +506,9 @@ func isCriticalRequestRetriable(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func getPod(kubeClient *k8s.ClientInfo, k8sArgs *types.K8sArgs, warnOnly bool) (*v1.Pod, error) {
|
||||
// GetPod retrieves Kubernetes Pod object from given namespace/name in k8sArgs (i.e. cni args)
|
||||
// GetPod also get pod UID, but it is not used to retrieve, but it is used for double check
|
||||
func GetPod(kubeClient *k8s.ClientInfo, k8sArgs *types.K8sArgs, warnOnly bool) (*v1.Pod, error) {
|
||||
if kubeClient == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@ -576,7 +581,7 @@ func CmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) (c
|
||||
}
|
||||
}
|
||||
|
||||
pod, err := getPod(kubeClient, k8sArgs, false)
|
||||
pod, err := GetPod(kubeClient, k8sArgs, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -623,7 +628,7 @@ func CmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) (c
|
||||
if netName == "" {
|
||||
netName = delegate.ConfList.Name
|
||||
}
|
||||
tmpResult, err = delegateAdd(exec, kubeClient, pod, delegate, rt, n)
|
||||
tmpResult, err = DelegateAdd(exec, kubeClient, pod, delegate, rt, n)
|
||||
if err != nil {
|
||||
// If the add failed, tear down all networks we already added
|
||||
// Ignore errors; DEL must be idempotent anyway
|
||||
@ -754,7 +759,7 @@ func CmdCheck(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo)
|
||||
ifName := getIfname(delegate, args.IfName, idx)
|
||||
|
||||
rt, _ := types.CreateCNIRuntimeConf(args, k8sArgs, ifName, in.RuntimeConfig, delegate)
|
||||
err = delegateCheck(exec, delegate, rt, in)
|
||||
err = DelegateCheck(exec, delegate, rt, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -810,10 +815,10 @@ func CmdDel(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) er
|
||||
return cmdErr(nil, "error getting k8s client: %v", err)
|
||||
}
|
||||
|
||||
pod, err := getPod(kubeClient, k8sArgs, true)
|
||||
pod, err := GetPod(kubeClient, k8sArgs, true)
|
||||
if err != nil {
|
||||
// getPod may be failed but just do print error in its log and continue to delete
|
||||
logging.Errorf("Multus: getPod failed: %v, but continue to delete", err)
|
||||
// GetPod may be failed but just do print error in its log and continue to delete
|
||||
logging.Errorf("Multus: GetPod failed: %v, but continue to delete", err)
|
||||
// skip status update because k8s api seems to be stucked
|
||||
skipStatusUpdate = true
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ var _ = Describe("multus operations cniVersion 0.2.0 config", func() {
|
||||
fExec.addPlugin020(nil, "net1", expectedConf2, expectedResult2, nil)
|
||||
|
||||
_, err := CmdAdd(args, fExec, nil)
|
||||
Expect(err).To(MatchError("[//:weave1]: error adding container to network \"weave1\": delegateAdd: cannot set \"weave-net\" interface name to \"eth0\": validateIfName: no net namespace fsdadfad found: failed to Statfs \"fsdadfad\": no such file or directory"))
|
||||
Expect(err).To(MatchError("[//:weave1]: error adding container to network \"weave1\": DelegateAdd: cannot set \"weave-net\" interface name to \"eth0\": validateIfName: no net namespace fsdadfad found: failed to Statfs \"fsdadfad\": no such file or directory"))
|
||||
})
|
||||
|
||||
It("fails to load NetConf with bad json in CmdAdd/Del", func() {
|
||||
|
@ -705,7 +705,7 @@ var _ = Describe("multus operations cniVersion 0.4.0 config", func() {
|
||||
fExec.addPlugin040(nil, "net1", expectedConf2, expectedResult2, nil)
|
||||
|
||||
_, err := CmdAdd(args, fExec, nil)
|
||||
Expect(err).To(MatchError("[//:weave1]: error adding container to network \"weave1\": delegateAdd: cannot set \"weave-net\" interface name to \"eth0\": validateIfName: no net namespace fsdadfad found: failed to Statfs \"fsdadfad\": no such file or directory"))
|
||||
Expect(err).To(MatchError("[//:weave1]: error adding container to network \"weave1\": DelegateAdd: cannot set \"weave-net\" interface name to \"eth0\": validateIfName: no net namespace fsdadfad found: failed to Statfs \"fsdadfad\": no such file or directory"))
|
||||
})
|
||||
|
||||
It("returns the previous result using CmdCheck", func() {
|
||||
|
@ -191,7 +191,7 @@ var _ = Describe("multus operations cniVersion 1.0.0 config", func() {
|
||||
fExec.addPlugin100(nil, "net1", expectedConf2, expectedResult2, nil)
|
||||
|
||||
_, err := CmdAdd(args, fExec, nil)
|
||||
Expect(err).To(MatchError("[//:weave1]: error adding container to network \"weave1\": delegateAdd: cannot set \"weave-net\" interface name to \"eth0\": validateIfName: no net namespace fsdadfad found: failed to Statfs \"fsdadfad\": no such file or directory"))
|
||||
Expect(err).To(MatchError("[//:weave1]: error adding container to network \"weave1\": DelegateAdd: cannot set \"weave-net\" interface name to \"eth0\": validateIfName: no net namespace fsdadfad found: failed to Statfs \"fsdadfad\": no such file or directory"))
|
||||
})
|
||||
|
||||
It("returns the previous result using CmdCheck", func() {
|
||||
|
87
pkg/server/api/api.go
Normal file
87
pkg/server/api/api.go
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2022 Multus 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 api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// MultusCNIAPIEndpoint is an endpoint for multus CNI request (for multus-shim)
|
||||
MultusCNIAPIEndpoint = "/cni"
|
||||
// MultusDelegateAPIEndpoint is an endpoint for multus delegate request (for hotplug)
|
||||
MultusDelegateAPIEndpoint = "/delegate"
|
||||
defaultMultusRunDir = "/run/multus/"
|
||||
)
|
||||
|
||||
// DoCNI sends a CNI request to the CNI server via JSON + HTTP over a root-owned unix socket,
|
||||
// and returns the result
|
||||
func DoCNI(url string, req interface{}, socketPath string) ([]byte, error) {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal CNI request %v: %v", req, err)
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: func(proto, addr string) (net.Conn, error) {
|
||||
return net.Dial("unix", socketPath)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.Post(url, "application/json", bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send CNI request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CNI result: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("CNI request failed with status %v: '%s'", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// GetAPIEndpoint returns endpoint URL for multus-daemon
|
||||
func GetAPIEndpoint(endpoint string) string {
|
||||
return fmt.Sprintf("http://dummy/%s", endpoint)
|
||||
}
|
||||
|
||||
// CreateDelegateRequest creates Request for delegate API request
|
||||
func CreateDelegateRequest(cniCommand, cniContainerID, cniNetNS, cniIFName, podNamespace, podName, podUID string, cniConfig []byte) *Request {
|
||||
return &Request{
|
||||
Env: map[string]string{
|
||||
"CNI_COMMAND": strings.ToUpper(cniCommand),
|
||||
"CNI_CONTAINERID": cniContainerID,
|
||||
"CNI_NETNS": cniNetNS,
|
||||
"CNI_IFNAME": cniIFName,
|
||||
"CNI_ARGS": fmt.Sprintf("K8S_POD_NAMESPACE=%s;K8S_POD_NAME=%s;K8S_POD_UID=%s", podNamespace, podName, podUID),
|
||||
},
|
||||
Config: cniConfig,
|
||||
}
|
||||
}
|
16
pkg/server/api/doc.go
Normal file
16
pkg/server/api/doc.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2022 Multus 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 api is the package that contains thick pluigin's server apis.
|
||||
package api
|
@ -1,12 +1,23 @@
|
||||
package server
|
||||
// Copyright (c) 2022 Multus 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 api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -14,12 +25,21 @@ import (
|
||||
cnitypes "github.com/containernetworking/cni/pkg/types"
|
||||
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/types"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMultusRunDir = "/run/multus/"
|
||||
)
|
||||
// ShimNetConf for the SHIM cni config file written in json
|
||||
type ShimNetConf struct {
|
||||
// Note: This struct contains NetConf in pkg/types, but this struct is only used to parse
|
||||
// following fields, so we skip to include NetConf here. Other fields are directly send to
|
||||
// multus-daemon as a part of skel.CmdArgs, StdinData.
|
||||
// types.NetConf
|
||||
|
||||
CNIVersion string `json:"cniVersion,omitempty"`
|
||||
MultusSocketDir string `json:"socketDir"`
|
||||
LogFile string `json:"logFile,omitempty"`
|
||||
LogLevel string `json:"logLevel,omitempty"`
|
||||
LogToStderr bool `json:"logToStderr,omitempty"`
|
||||
}
|
||||
|
||||
// CmdAdd implements the CNI spec ADD command handler
|
||||
func CmdAdd(args *skel.CmdArgs) error {
|
||||
@ -98,8 +118,8 @@ func newCNIRequest(args *skel.CmdArgs) (*Request, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func shimConfig(cniConfig []byte) (*types.ShimNetConf, error) {
|
||||
multusConfig := &types.ShimNetConf{}
|
||||
func shimConfig(cniConfig []byte) (*ShimNetConf, error) {
|
||||
multusConfig := &ShimNetConf{}
|
||||
if err := json.Unmarshal(cniConfig, multusConfig); err != nil {
|
||||
return nil, fmt.Errorf("failed to gather the multus configuration: %w", err)
|
||||
}
|
||||
@ -116,37 +136,3 @@ func shimConfig(cniConfig []byte) (*types.ShimNetConf, error) {
|
||||
}
|
||||
return multusConfig, nil
|
||||
}
|
||||
|
||||
// DoCNI sends a CNI request to the CNI server via JSON + HTTP over a root-owned unix socket,
|
||||
// and returns the result
|
||||
func DoCNI(url string, req interface{}, socketPath string) ([]byte, error) {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal CNI request %v: %v", req, err)
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: func(proto, addr string) (net.Conn, error) {
|
||||
return net.Dial("unix", socketPath)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.Post(url, "application/json", bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send CNI request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CNI result: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("CNI request failed with status %v: '%s'", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
@ -13,32 +13,16 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package server
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
serverSocketName = "multus.sock"
|
||||
fullReadWriteExecutePermissions = 0777
|
||||
thickPluginSocketRunDirPermissions = 0700
|
||||
serverSocketName = "multus.sock"
|
||||
)
|
||||
|
||||
// FilesystemPreRequirements ensures the target `rundir` features the correct
|
||||
// permissions.
|
||||
func FilesystemPreRequirements(rundir string) error {
|
||||
if err := os.RemoveAll(rundir); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to remove old pod info socket directory %s: %v", rundir, err)
|
||||
}
|
||||
if err := os.MkdirAll(rundir, thickPluginSocketRunDirPermissions); err != nil {
|
||||
return fmt.Errorf("failed to create pod info socket directory %s: %v", rundir, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SocketPath returns the path of the multus CNI socket
|
||||
func SocketPath(rundir string) string {
|
||||
return filepath.Join(rundir, serverSocketName)
|
33
pkg/server/api/types.go
Normal file
33
pkg/server/api/types.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2022 Multus 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 api
|
||||
|
||||
import (
|
||||
cni100 "github.com/containernetworking/cni/pkg/types/100"
|
||||
)
|
||||
|
||||
// Request sent to the Server by the multus-shim
|
||||
type Request struct {
|
||||
// CNI environment variables, like CNI_COMMAND and CNI_NETNS
|
||||
Env map[string]string `json:"env,omitempty"`
|
||||
// CNI configuration passed via stdin to the CNI plugin
|
||||
Config []byte `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
// Response represents the response (computed in the CNI server) for
|
||||
// ADD / DEL / CHECK for a Pod.
|
||||
type Response struct {
|
||||
Result *cni100.Result
|
||||
}
|
@ -37,13 +37,31 @@ import (
|
||||
k8s "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/k8sclient"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/multus"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server/api"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server/config"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/types"
|
||||
)
|
||||
|
||||
const (
|
||||
fullReadWriteExecutePermissions = 0777
|
||||
thickPluginSocketRunDirPermissions = 0700
|
||||
)
|
||||
|
||||
// FilesystemPreRequirements ensures the target `rundir` features the correct
|
||||
// permissions.
|
||||
func FilesystemPreRequirements(rundir string) error {
|
||||
if err := os.RemoveAll(rundir); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to remove old pod info socket directory %s: %v", rundir, err)
|
||||
}
|
||||
if err := os.MkdirAll(rundir, thickPluginSocketRunDirPermissions); err != nil {
|
||||
return fmt.Errorf("failed to create pod info socket directory %s: %v", rundir, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleCNIRequest is the CNI server handler function; it is invoked whenever
|
||||
// a CNI request is processed.
|
||||
func HandleCNIRequest(cmd string, k8sArgs *types.K8sArgs, cniCmdArgs *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) ([]byte, error) {
|
||||
func (s *Server) HandleCNIRequest(cmd string, k8sArgs *types.K8sArgs, cniCmdArgs *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) ([]byte, error) {
|
||||
var result []byte
|
||||
var err error
|
||||
|
||||
@ -52,7 +70,7 @@ func HandleCNIRequest(cmd string, k8sArgs *types.K8sArgs, cniCmdArgs *skel.CmdAr
|
||||
case "ADD":
|
||||
result, err = cmdAdd(cniCmdArgs, k8sArgs, exec, kubeClient)
|
||||
case "DEL":
|
||||
err = cmdDelete(cniCmdArgs, k8sArgs, exec, kubeClient)
|
||||
err = cmdDel(cniCmdArgs, k8sArgs, exec, kubeClient)
|
||||
case "CHECK":
|
||||
err = cmdCheck(cniCmdArgs, k8sArgs, exec, kubeClient)
|
||||
default:
|
||||
@ -66,6 +84,38 @@ func HandleCNIRequest(cmd string, k8sArgs *types.K8sArgs, cniCmdArgs *skel.CmdAr
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// HandleDelegateRequest is the CNI server handler function; it is invoked whenever
|
||||
// a CNI request is processed as delegate CNI request.
|
||||
func (s *Server) HandleDelegateRequest(cmd string, k8sArgs *types.K8sArgs, cniCmdArgs *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) ([]byte, error) {
|
||||
var result []byte
|
||||
var err error
|
||||
var multusConfByte []byte
|
||||
|
||||
multusConfByte = bytes.Replace(s.serverConfig, []byte(","), []byte("{"), 1)
|
||||
multusConfig := types.GetDefaultNetConf()
|
||||
if err = json.Unmarshal(multusConfByte, multusConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logging.Verbosef("%s starting delegate request %+v", cmd, cniCmdArgs)
|
||||
switch cmd {
|
||||
case "ADD":
|
||||
result, err = cmdDelegateAdd(cniCmdArgs, k8sArgs, exec, kubeClient, multusConfig)
|
||||
case "DEL":
|
||||
err = cmdDelegateDel(cniCmdArgs, k8sArgs, exec, kubeClient, multusConfig)
|
||||
case "CHECK":
|
||||
err = cmdDelegateCheck(cniCmdArgs, k8sArgs, exec, kubeClient, multusConfig)
|
||||
default:
|
||||
return []byte(""), fmt.Errorf("unknown cmd type: %s", cmd)
|
||||
}
|
||||
logging.Verbosef("%s finished Delegate request %+v, result: %q, err: %v", cmd, *cniCmdArgs, string(result), err)
|
||||
if err != nil {
|
||||
// Prefix errors with request info for easier failure debugging
|
||||
return nil, fmt.Errorf("%+v ERRORED: %v", *cniCmdArgs, err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetListener creates a listener to a unix socket located in `socketPath`
|
||||
func GetListener(socketPath string) (net.Listener, error) {
|
||||
l, err := net.Listen("unix", socketPath)
|
||||
@ -112,7 +162,6 @@ func newCNIServer(rundir string, kubeClient *k8s.ClientInfo, exec invoke.Exec, s
|
||||
Handler: router,
|
||||
},
|
||||
rundir: rundir,
|
||||
requestFunc: HandleCNIRequest,
|
||||
kubeclient: kubeClient,
|
||||
exec: exec,
|
||||
serverConfig: servConfig,
|
||||
@ -135,7 +184,7 @@ func newCNIServer(rundir string, kubeClient *k8s.ClientInfo, exec invoke.Exec, s
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}))
|
||||
|
||||
router.HandleFunc("/cni", promhttp.InstrumentHandlerCounter(s.metrics.requestCounter.MustCurryWith(prometheus.Labels{"handler": "/cni"}),
|
||||
router.HandleFunc(api.MultusCNIAPIEndpoint, promhttp.InstrumentHandlerCounter(s.metrics.requestCounter.MustCurryWith(prometheus.Labels{"handler": api.MultusCNIAPIEndpoint}),
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
result, err := s.handleCNIRequest(r)
|
||||
if err != nil {
|
||||
@ -151,11 +200,27 @@ func newCNIServer(rundir string, kubeClient *k8s.ClientInfo, exec invoke.Exec, s
|
||||
}
|
||||
}))).Methods("POST")
|
||||
|
||||
router.HandleFunc(api.MultusDelegateAPIEndpoint, promhttp.InstrumentHandlerCounter(s.metrics.requestCounter.MustCurryWith(prometheus.Labels{"handler": api.MultusDelegateAPIEndpoint}),
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
result, err := s.handleDelegateRequest(r)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("%v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// Empty response JSON means success with no body
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if _, err := w.Write(result); err != nil {
|
||||
_ = logging.Errorf("Error writing HTTP response: %v", err)
|
||||
}
|
||||
}))).Methods("POST")
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) handleCNIRequest(r *http.Request) ([]byte, error) {
|
||||
var cr Request
|
||||
var cr api.Request
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -173,7 +238,7 @@ func (s *Server) handleCNIRequest(r *http.Request) ([]byte, error) {
|
||||
return nil, fmt.Errorf("could not extract the kubernetes runtime args: %w", err)
|
||||
}
|
||||
|
||||
result, err := s.requestFunc(cmdType, k8sArgs, cniCmdArgs, s.exec, s.kubeclient)
|
||||
result, err := s.HandleCNIRequest(cmdType, k8sArgs, cniCmdArgs, s.exec, s.kubeclient)
|
||||
if err != nil {
|
||||
// Prefix error with request information for easier debugging
|
||||
return nil, fmt.Errorf("%+v %v", cniCmdArgs, err)
|
||||
@ -181,7 +246,34 @@ func (s *Server) handleCNIRequest(r *http.Request) ([]byte, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func extractCniData(cniRequest *Request, overrideConf []byte) (string, *skel.CmdArgs, error) {
|
||||
func (s *Server) handleDelegateRequest(r *http.Request) ([]byte, error) {
|
||||
var cr api.Request
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &cr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmdType, cniCmdArgs, err := extractCniData(&cr, s.serverConfig) // not override config
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not extract the CNI command args: %w", err)
|
||||
}
|
||||
|
||||
k8sArgs, err := kubernetesRuntimeArgs(cr.Env, s.kubeclient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not extract the kubernetes runtime args: %w", err)
|
||||
}
|
||||
|
||||
result, err := s.HandleDelegateRequest(cmdType, k8sArgs, cniCmdArgs, s.exec, s.kubeclient)
|
||||
if err != nil {
|
||||
// Prefix error with request information for easier debugging
|
||||
return nil, fmt.Errorf("%+v %v", cniCmdArgs, err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func extractCniData(cniRequest *api.Request, overrideConf []byte) (string, *skel.CmdArgs, error) {
|
||||
cmd, ok := cniRequest.Env["CNI_COMMAND"]
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("unexpected or missing CNI_COMMAND")
|
||||
@ -271,6 +363,7 @@ func gatherCNIArgs(env map[string]string) (map[string]string, error) {
|
||||
}
|
||||
return mapArgs, nil
|
||||
}
|
||||
|
||||
func podUID(kubeclient *k8s.ClientInfo, cniArgs map[string]string, podNamespace, podName string) (string, error) {
|
||||
// UID may not be passed by all runtimes yet. Will be passed
|
||||
// by CRIO 1.20+ and containerd 1.5+ soon.
|
||||
@ -306,7 +399,7 @@ func cmdAdd(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs, exec invoke.Exec, kub
|
||||
return serializeResult(result)
|
||||
}
|
||||
|
||||
func cmdDelete(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) error {
|
||||
func cmdDel(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) error {
|
||||
namespace := string(k8sArgs.K8S_POD_NAMESPACE)
|
||||
podName := string(k8sArgs.K8S_POD_NAME)
|
||||
if namespace == "" || podName == "" {
|
||||
@ -335,9 +428,69 @@ func serializeResult(result cnitypes.Result) ([]byte, error) {
|
||||
return nil, fmt.Errorf("failed to generate the CNI result: %w", err)
|
||||
}
|
||||
|
||||
responseBytes, err := json.Marshal(&Response{Result: realResult})
|
||||
responseBytes, err := json.Marshal(&api.Response{Result: realResult})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal pod request response: %v", err)
|
||||
}
|
||||
return responseBytes, nil
|
||||
}
|
||||
|
||||
func cmdDelegateAdd(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo, multusConfig *types.NetConf) ([]byte, error) {
|
||||
namespace := string(k8sArgs.K8S_POD_NAMESPACE)
|
||||
podName := string(k8sArgs.K8S_POD_NAME)
|
||||
if namespace == "" || podName == "" {
|
||||
return nil, fmt.Errorf("required CNI variable missing. pod name: %s; pod namespace: %s", podName, namespace)
|
||||
}
|
||||
pod, err := multus.GetPod(kubeClient, k8sArgs, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delegateCNIConf := &types.DelegateNetConf{}
|
||||
if err := json.Unmarshal(cmdArgs.StdinData, delegateCNIConf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delegateCNIConf.Bytes = cmdArgs.StdinData
|
||||
|
||||
logging.Debugf("CmdDelegateAdd for [%s/%s]. CNI conf: %+v", namespace, podName, *cmdArgs)
|
||||
rt, _ := types.CreateCNIRuntimeConf(cmdArgs, k8sArgs, cmdArgs.IfName, nil, delegateCNIConf)
|
||||
result, err := multus.DelegateAdd(exec, kubeClient, pod, delegateCNIConf, rt, multusConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error configuring pod [%s/%s] networking: %v", namespace, podName, err)
|
||||
}
|
||||
|
||||
return serializeResult(result)
|
||||
}
|
||||
|
||||
func cmdDelegateCheck(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo, multusConfig *types.NetConf) error {
|
||||
delegateCNIConf := &types.DelegateNetConf{}
|
||||
if err := json.Unmarshal(cmdArgs.StdinData, delegateCNIConf); err != nil {
|
||||
return err
|
||||
}
|
||||
delegateCNIConf.Bytes = cmdArgs.StdinData
|
||||
rt, _ := types.CreateCNIRuntimeConf(cmdArgs, k8sArgs, cmdArgs.IfName, nil, delegateCNIConf)
|
||||
return multus.DelegateCheck(exec, delegateCNIConf, rt, multusConfig)
|
||||
}
|
||||
|
||||
// note: this function may send back error to the client. In cni spec, command DEL should NOT send any error
|
||||
// because container deletion follows cni DEL command. But in delegateDel case, container is not removed by
|
||||
// this delegateDel, hence we decide to send error message to the request sender.
|
||||
func cmdDelegateDel(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo, multusConfig *types.NetConf) error {
|
||||
namespace := string(k8sArgs.K8S_POD_NAMESPACE)
|
||||
podName := string(k8sArgs.K8S_POD_NAME)
|
||||
if namespace == "" || podName == "" {
|
||||
return fmt.Errorf("required CNI variable missing. pod name: %s; pod namespace: %s", podName, namespace)
|
||||
}
|
||||
pod, err := multus.GetPod(kubeClient, k8sArgs, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delegateCNIConf := &types.DelegateNetConf{}
|
||||
if err := json.Unmarshal(cmdArgs.StdinData, delegateCNIConf); err != nil {
|
||||
return err
|
||||
}
|
||||
delegateCNIConf.Bytes = cmdArgs.StdinData
|
||||
rt, _ := types.CreateCNIRuntimeConf(cmdArgs, k8sArgs, cmdArgs.IfName, nil, delegateCNIConf)
|
||||
return multus.DelegateDel(exec, pod, delegateCNIConf, rt, multusConfig)
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import (
|
||||
|
||||
netfake "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/fake"
|
||||
k8s "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/k8sclient"
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/server/api"
|
||||
testhelpers "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/testing"
|
||||
)
|
||||
|
||||
@ -131,13 +132,13 @@ var _ = Describe(suiteName, func() {
|
||||
|
||||
It("ADD/CHECK/DEL works successfully", func() {
|
||||
Expect(os.Setenv("CNI_COMMAND", "ADD")).NotTo(HaveOccurred())
|
||||
Expect(CmdAdd(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
Expect(api.CmdAdd(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
|
||||
Expect(os.Setenv("CNI_COMMAND", "CHECK")).NotTo(HaveOccurred())
|
||||
Expect(CmdCheck(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
Expect(api.CmdCheck(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
|
||||
Expect(os.Setenv("CNI_COMMAND", "DEL")).NotTo(HaveOccurred())
|
||||
Expect(CmdDel(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
Expect(api.CmdDel(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
@ -185,13 +186,13 @@ var _ = Describe(suiteName, func() {
|
||||
|
||||
It("ADD/CHECK/DEL works successfully", func() {
|
||||
Expect(os.Setenv("CNI_COMMAND", "ADD")).NotTo(HaveOccurred())
|
||||
Expect(CmdAdd(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
Expect(api.CmdAdd(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
|
||||
Expect(os.Setenv("CNI_COMMAND", "CHECK")).NotTo(HaveOccurred())
|
||||
Expect(CmdCheck(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
Expect(api.CmdCheck(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
|
||||
Expect(os.Setenv("CNI_COMMAND", "DEL")).NotTo(HaveOccurred())
|
||||
Expect(CmdDel(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
Expect(api.CmdDel(cniCmdArgs(containerID, netns.Path(), ifaceName, referenceConfig(thickPluginRunDir)))).To(Succeed())
|
||||
|
||||
})
|
||||
})
|
||||
@ -260,9 +261,9 @@ func startCNIServer(runDir string, k8sClient *k8s.ClientInfo, servConfig []byte)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := GetListener(SocketPath(runDir))
|
||||
l, err := GetListener(api.SocketPath(runDir))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start the CNI server using socket %s. Reason: %+v", SocketPath(runDir), err)
|
||||
return nil, fmt.Errorf("failed to start the CNI server using socket %s. Reason: %+v", api.SocketPath(runDir), err)
|
||||
}
|
||||
|
||||
cniServer.SetKeepAlivesEnabled(false)
|
||||
|
@ -4,8 +4,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/invoke"
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
cni100 "github.com/containernetworking/cni/pkg/types/100"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
@ -13,16 +11,6 @@ import (
|
||||
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/types"
|
||||
)
|
||||
|
||||
type cniRequestFunc func(cmd string, k8sArgs *types.K8sArgs, cniCmdArgs *skel.CmdArgs, exec invoke.Exec, kubeClient *k8sclient.ClientInfo) ([]byte, error)
|
||||
|
||||
// Request sent to the Server by the multus-shim
|
||||
type Request struct {
|
||||
// CNI environment variables, like CNI_COMMAND and CNI_NETNS
|
||||
Env map[string]string `json:"env,omitempty"`
|
||||
// CNI configuration passed via stdin to the CNI plugin
|
||||
Config []byte `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
// Metrics represents server's metrics.
|
||||
type Metrics struct {
|
||||
requestCounter *prometheus.CounterVec
|
||||
@ -32,7 +20,6 @@ type Metrics struct {
|
||||
// the CNI shim requests issued when a pod is added / removed.
|
||||
type Server struct {
|
||||
http.Server
|
||||
requestFunc cniRequestFunc
|
||||
rundir string
|
||||
kubeclient *k8sclient.ClientInfo
|
||||
exec invoke.Exec
|
||||
@ -40,12 +27,6 @@ type Server struct {
|
||||
metrics *Metrics
|
||||
}
|
||||
|
||||
// Response represents the response (computed in the CNI server) for
|
||||
// ADD / DEL / CHECK for a Pod.
|
||||
type Response struct {
|
||||
Result *cni100.Result
|
||||
}
|
||||
|
||||
// ShimNetConf for the shim cni config file written in json
|
||||
type ShimNetConf struct {
|
||||
types.NetConf
|
||||
|
@ -197,16 +197,16 @@ func CreateCNIRuntimeConf(args *skel.CmdArgs, k8sArgs *K8sArgs, ifName string, r
|
||||
podNamespace := string(k8sArgs.K8S_POD_NAMESPACE)
|
||||
podUID := string(k8sArgs.K8S_POD_UID)
|
||||
sandboxID := string(k8sArgs.K8S_POD_INFRA_CONTAINER_ID)
|
||||
return NewCNIRuntimeConf(args.ContainerID, sandboxID, podName, podNamespace, podUID, args.Netns, ifName, rc, delegate)
|
||||
return newCNIRuntimeConf(args.ContainerID, sandboxID, podName, podNamespace, podUID, args.Netns, ifName, rc, delegate)
|
||||
}
|
||||
|
||||
// NewCNIRuntimeConf creates the CNI `RuntimeConf` for the given ADD / DEL request.
|
||||
func NewCNIRuntimeConf(containerID, sandboxID, podName, podNamespace, podUID, netNs, ifName string, rc *RuntimeConfig, delegate *DelegateNetConf) (*libcni.RuntimeConf, string) {
|
||||
// newCNIRuntimeConf creates the CNI `RuntimeConf` for the given ADD / DEL request.
|
||||
func newCNIRuntimeConf(containerID, sandboxID, podName, podNamespace, podUID, netNs, ifName string, rc *RuntimeConfig, delegate *DelegateNetConf) (*libcni.RuntimeConf, string) {
|
||||
logging.Debugf("LoadCNIRuntimeConf: %s, %v %v", ifName, rc, delegate)
|
||||
|
||||
delegateRc := DelegateRuntimeConfig(containerID, delegate, rc, ifName)
|
||||
delegateRc := delegateRuntimeConfig(containerID, delegate, rc, ifName)
|
||||
// In part, adapted from K8s pkg/kubelet/dockershim/network/cni/cni.go#buildCNIRuntimeConf
|
||||
rt := CreateRuntimeConf(netNs, podNamespace, podName, containerID, sandboxID, podUID, ifName)
|
||||
rt := createRuntimeConf(netNs, podNamespace, podName, containerID, sandboxID, podUID, ifName)
|
||||
|
||||
var cniDeviceInfoFile string
|
||||
|
||||
@ -270,8 +270,8 @@ func NewCNIRuntimeConf(containerID, sandboxID, podName, podNamespace, podUID, ne
|
||||
return rt, cniDeviceInfoFile
|
||||
}
|
||||
|
||||
// CreateRuntimeConf creates the CNI `RuntimeConf` for the given ADD / DEL request.
|
||||
func CreateRuntimeConf(netNs, podNamespace, podName, containerID, sandboxID, podUID, ifName string) *libcni.RuntimeConf {
|
||||
// createRuntimeConf creates the CNI `RuntimeConf` for the given ADD / DEL request.
|
||||
func createRuntimeConf(netNs, podNamespace, podName, containerID, sandboxID, podUID, ifName string) *libcni.RuntimeConf {
|
||||
return &libcni.RuntimeConf{
|
||||
ContainerID: containerID,
|
||||
NetNS: netNs,
|
||||
@ -287,8 +287,8 @@ func CreateRuntimeConf(netNs, podNamespace, podName, containerID, sandboxID, pod
|
||||
}
|
||||
}
|
||||
|
||||
// DelegateRuntimeConfig creates the CNI `RuntimeConf` for the given ADD / DEL request.
|
||||
func DelegateRuntimeConfig(containerID string, delegate *DelegateNetConf, rc *RuntimeConfig, ifName string) *RuntimeConfig {
|
||||
// delegateRuntimeConfig creates the CNI `RuntimeConf` for the given ADD / DEL request.
|
||||
func delegateRuntimeConfig(containerID string, delegate *DelegateNetConf, rc *RuntimeConfig, ifName string) *RuntimeConfig {
|
||||
var delegateRc *RuntimeConfig
|
||||
|
||||
if delegate != nil {
|
||||
@ -319,10 +319,25 @@ func GetGatewayFromResult(result *cni100.Result) []net.IP {
|
||||
return gateways
|
||||
}
|
||||
|
||||
// GetDefaultNetConf returns NetConf with default variables
|
||||
func GetDefaultNetConf() *NetConf {
|
||||
// LogToStderr's default value set to true
|
||||
return &NetConf{
|
||||
BinDir: defaultBinDir,
|
||||
ConfDir: defaultConfDir,
|
||||
CNIDir: defaultCNIDir,
|
||||
LogToStderr: true,
|
||||
MultusNamespace: defaultMultusNamespace,
|
||||
NonIsolatedNamespaces: []string{defaultNonIsolatedNamespace},
|
||||
ReadinessIndicatorFile: defaultReadinessIndicatorFile,
|
||||
SystemNamespaces: []string{"kube-system"},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// LoadNetConf converts inputs (i.e. stdin) to NetConf
|
||||
func LoadNetConf(bytes []byte) (*NetConf, error) {
|
||||
// LogToStderr's default value set to true
|
||||
netconf := &NetConf{LogToStderr: true}
|
||||
netconf := GetDefaultNetConf()
|
||||
|
||||
logging.Debugf("LoadNetConf: %s", string(bytes))
|
||||
if err := json.Unmarshal(bytes, netconf); err != nil {
|
||||
@ -366,34 +381,8 @@ func LoadNetConf(bytes []byte) (*NetConf, error) {
|
||||
return nil, logging.Errorf("LoadNetConf: at least one delegate/clusterNetwork must be specified")
|
||||
}
|
||||
|
||||
if netconf.CNIDir == "" {
|
||||
netconf.CNIDir = defaultCNIDir
|
||||
}
|
||||
|
||||
if netconf.ConfDir == "" {
|
||||
netconf.ConfDir = defaultConfDir
|
||||
}
|
||||
|
||||
if netconf.BinDir == "" {
|
||||
netconf.BinDir = defaultBinDir
|
||||
}
|
||||
|
||||
if netconf.ReadinessIndicatorFile == "" {
|
||||
netconf.ReadinessIndicatorFile = defaultReadinessIndicatorFile
|
||||
}
|
||||
|
||||
if len(netconf.SystemNamespaces) == 0 {
|
||||
netconf.SystemNamespaces = []string{"kube-system"}
|
||||
}
|
||||
|
||||
if netconf.MultusNamespace == "" {
|
||||
netconf.MultusNamespace = defaultMultusNamespace
|
||||
}
|
||||
|
||||
// setup namespace isolation
|
||||
if netconf.RawNonIsolatedNamespaces == "" {
|
||||
netconf.NonIsolatedNamespaces = []string{defaultNonIsolatedNamespace}
|
||||
} else {
|
||||
if netconf.RawNonIsolatedNamespaces != "" {
|
||||
// Parse the comma separated list
|
||||
nonisolated := strings.Split(netconf.RawNonIsolatedNamespaces, ",")
|
||||
// Cleanup the whitespace
|
||||
|
@ -178,16 +178,6 @@ type ResourceClient interface {
|
||||
GetPodResourceMap(*v1.Pod) (map[string]*ResourceInfo, error)
|
||||
}
|
||||
|
||||
// ShimNetConf for the SHIM cni config file written in json
|
||||
type ShimNetConf struct {
|
||||
types.NetConf
|
||||
|
||||
MultusSocketDir string `json:"socketDir"`
|
||||
LogFile string `json:"logFile,omitempty"`
|
||||
LogLevel string `json:"logLevel,omitempty"`
|
||||
LogToStderr bool `json:"logToStderr,omitempty"`
|
||||
}
|
||||
|
||||
// ControllerNetConf for the controller cni configuration
|
||||
type ControllerNetConf struct {
|
||||
ChrootDir string `json:"chrootDir,omitempty"`
|
||||
|
Loading…
Reference in New Issue
Block a user