mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-09-24 19:07:54 +00:00
Merge pull request #51 from redhat-nfvpe/develop
Network Plumbing Working Group CRD Spec Changes from Dough and Tomo
This commit is contained in:
31
.travis.yml
Normal file
31
.travis.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
language: go
|
||||
# see https://docs.travis-ci.com/user/reference/overview/#Virtualization-environments
|
||||
# for the detail
|
||||
# sudo: requried
|
||||
dist: trusty
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
|
||||
install:
|
||||
- go get github.com/golang/lint/golint
|
||||
|
||||
before_script:
|
||||
- golint ./multus/... | grep -v ALL_CAPS | xargs -r false
|
||||
- go fmt ./multus/...
|
||||
- go vet ./multus/...
|
||||
# - gocyclo -over 15 ./multus
|
||||
|
||||
script:
|
||||
- ./build
|
||||
- mkdir -p ${TRAVIS_BUILD_DIR}/dist
|
||||
- tar cvfz ${TRAVIS_BUILD_DIR}/dist/multus-cni_amd64.tar.gz --warning=no-file-changed --exclude="dist" --exclude="vendor" .
|
||||
|
||||
after_success:
|
||||
# put build tgz to bintray
|
||||
- curl -T ${TRAVIS_BUILD_DIR}/dist/multus-cni_amd64.tar.gz -u${BINTRAY_USER}:${BINTRAY_APIKEY} https://api.bintray.com/content/redhat-nfvpe/multus-cni-crd-snapshots/snapshot/snapshot-${TRAVIS_COMMIT}/multus-cni_amd64-${TRAVIS_COMMIT}.tar.gz
|
||||
# publish uploaded file
|
||||
- curl -X POST -u${BINTRAY_USER}:${BINTRAY_APIKEY} https://api.bintray.com/content/redhat-nfvpe/multus-cni-crd-snapshots/snapshot/snapshot-${TRAVIS_COMMIT}/publish
|
||||
# put it in bintray download list
|
||||
- sleep 20
|
||||
- "curl -X PUT -H 'Accept: application/json' -H 'Content-type: application/json' -u${BINTRAY_USER}:${BINTRAY_APIKEY} https://api.bintray.com/file_metadata/redhat-nfvpe/multus-cni-crd-snapshots/multus-cni_amd64-${TRAVIS_COMMIT}.tar.gz -d '{\"list_in_downloads\":true}'"
|
23
README.md
23
README.md
@@ -280,10 +280,10 @@ sriov-vlanid-l2enable-conf Network.v1.kubernetes-network.cni.cncf.io
|
||||
sriov-conf Network.v1.kubernetes-network.cni.cncf.io
|
||||
```
|
||||
### Configuring Multus to use the kubeconfig
|
||||
1. Create Multus CNI configuration file /etc/cni/net.d/multus-cni.conf with below content in minions. Use only the absolute path to point to the kubeconfig file (it may change depending upon your cluster env) and make sure all CNI binary files are in `\opt\cni\bin` dir
|
||||
1. Create Multus CNI configuration file /etc/cni/net.d/multus-cni.conf with below content on the nodes. Use only the absolute path to point to the kubeconfig file (it may change depending upon your cluster env) and make sure all CNI binary files are in `\opt\cni\bin` dir
|
||||
```
|
||||
{
|
||||
"name": "minion-cni-network",
|
||||
"name": "node-cni-network",
|
||||
"type": "multus",
|
||||
"kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml"
|
||||
}
|
||||
@@ -296,7 +296,7 @@ sriov-conf Network.v1.kubernetes-network.cni.cncf.io
|
||||
1. Many user want default networking feature along with Network object. Refer [#14](https://github.com/Intel-Corp/multus-cni/issues/14) & [#17](https://github.com/Intel-Corp/multus-cni/issues/17) issues for more information. In this following config, Weave act as the default network in the absence of network field in the pod metadata annotation.
|
||||
```
|
||||
{
|
||||
"name": "minion-cni-network",
|
||||
"name": "node-cni-network",
|
||||
"type": "multus",
|
||||
"kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml",
|
||||
"delegates": [{
|
||||
@@ -451,6 +451,23 @@ Given the following network configuration:
|
||||
EOF
|
||||
|
||||
```
|
||||
|
||||
### Further options for CNI configuration file.
|
||||
|
||||
One may also specify `always_use_default` as a boolean value. This option requires that you're using the CRD method (and therefore requires that you must also specify both the `kubeconfig` and the `delegates` option as well, or Multus will present an error message). In the case that `always_use_default` is true, the `delegates` network will always be applied, along with those specified in the annotations.
|
||||
|
||||
For example, a valid configuration using the `always_use_default` may look like:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "multus-cni-network",
|
||||
"type": "multus",
|
||||
"delegates": [{"type": "flannel", "isDefaultGateway": true, "masterplugin": true}],
|
||||
"always_use_default": true,
|
||||
"kubeconfig": "/etc/kubernetes/kubelet.conf"
|
||||
}
|
||||
```
|
||||
|
||||
## Testing the Multus CNI ##
|
||||
### Multiple Flannel Network
|
||||
Github user [YYGCui](https://github.com/YYGCui) has used Multiple flannel network to work with Multus CNI plugin. Please refer this [closed issue](https://github.com/Intel-Corp/multus-cni/issues/7) for Multiple overlay network support with Multus CNI.
|
||||
|
134
multus/multus.go
134
multus/multus.go
@@ -43,15 +43,13 @@ const defaultCNIDir = "/var/lib/cni/multus"
|
||||
var masterpluginEnabled bool
|
||||
var defaultcninetwork bool
|
||||
|
||||
// NetConf for cni config file written in json
|
||||
type NetConf struct {
|
||||
types.NetConf
|
||||
CNIDir string `json:"cniDir"`
|
||||
Delegates []map[string]interface{} `json:"delegates"`
|
||||
Kubeconfig string `json:"kubeconfig"`
|
||||
}
|
||||
|
||||
type PodNet struct {
|
||||
Networkname string `json:"name"`
|
||||
UseDefault bool `json:"always_use_default"`
|
||||
}
|
||||
|
||||
type netplugin struct {
|
||||
@@ -91,10 +89,17 @@ func loadNetConf(bytes []byte) (*NetConf, error) {
|
||||
defaultcninetwork = true
|
||||
}
|
||||
|
||||
if netconf.Kubeconfig != "" && !defaultcninetwork {
|
||||
if netconf.UseDefault {
|
||||
if netconf.Kubeconfig == "" || !defaultcninetwork {
|
||||
return nil, fmt.Errorf(`If you have set always_use_default, you must also set the delegates & the kubeconfig, refer to the README`)
|
||||
}
|
||||
return netconf, nil
|
||||
}
|
||||
|
||||
if !netconf.UseDefault && (netconf.Kubeconfig != "" && !defaultcninetwork) {
|
||||
return netconf, nil
|
||||
}
|
||||
|
||||
if len(netconf.Delegates) == 0 && !defaultcninetwork {
|
||||
return nil, fmt.Errorf(`delegates or kubeconfig option is must, refer README.md`)
|
||||
}
|
||||
@@ -209,6 +214,12 @@ func delegateAdd(podif func() string, argif string, netconf map[string]interface
|
||||
}
|
||||
}
|
||||
|
||||
if netconf["ifnameRequest"] != nil {
|
||||
if os.Setenv("CNI_IFNAME", netconf["ifnameRequest"].(string)) != nil {
|
||||
return true, fmt.Errorf("Multus: error in setting CNI_IFNAME")
|
||||
}
|
||||
}
|
||||
|
||||
result, err := invoke.DelegateAdd(netconf["type"].(string), netconfBytes)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("Multus: error in invoke Delegate add - %q: %v", netconf["type"].(string), err)
|
||||
@@ -288,7 +299,32 @@ func getPodNetworkAnnotation(client *kubernetes.Clientset, k8sArgs K8sArgs) (str
|
||||
return annot, fmt.Errorf("getPodNetworkAnnotation: failed to query the pod %v in out of cluster comm", string(k8sArgs.K8S_POD_NAME))
|
||||
}
|
||||
|
||||
return pod.Annotations["networks"], nil
|
||||
return pod.Annotations["kubernetes.cni.cncf.io/networks"], nil
|
||||
}
|
||||
|
||||
func parsePodNetworkObjectName(podnetwork string) (string, string, string, error) {
|
||||
var netNsName string
|
||||
var netIfName string
|
||||
var networkName string
|
||||
|
||||
slashItems := strings.Split(podnetwork, "/")
|
||||
if len(slashItems) == 2 {
|
||||
netNsName = strings.TrimSpace(slashItems[0])
|
||||
networkName = slashItems[1]
|
||||
} else if len(slashItems) == 1 {
|
||||
networkName = slashItems[0]
|
||||
} else {
|
||||
return "", "", "", fmt.Errorf("Invalid network object (failed at '/')")
|
||||
}
|
||||
|
||||
atItems := strings.Split(networkName, "@")
|
||||
networkName = strings.TrimSpace(atItems[0])
|
||||
if len(atItems) == 2 {
|
||||
netIfName = strings.TrimSpace(atItems[1])
|
||||
} else if len(atItems) != 1 {
|
||||
return "", "", "", fmt.Errorf("Invalid network object (failed at '@')")
|
||||
}
|
||||
return netNsName, networkName, netIfName, nil
|
||||
}
|
||||
|
||||
func parsePodNetworkObject(podnetwork string) ([]map[string]interface{}, error) {
|
||||
@@ -298,14 +334,39 @@ func parsePodNetworkObject(podnetwork string) ([]map[string]interface{}, error)
|
||||
return nil, fmt.Errorf("parsePodNetworkObject: pod annotation not having \"network\" as key, refer Multus README.md for the usage guide")
|
||||
}
|
||||
|
||||
// Parse the podnetwork string, and assume it is JSON.
|
||||
if err := json.Unmarshal([]byte(podnetwork), &podNet); err != nil {
|
||||
return nil, fmt.Errorf("parsePodNetworkObject: failed to load pod network err: %v | pod network: %v", err, podnetwork)
|
||||
// If the JSON parsing fails, assume it is comma delimited.
|
||||
commaItems := strings.Split(podnetwork, ",")
|
||||
// Build a map from the comma delimited items.
|
||||
for i := range commaItems {
|
||||
// Parse network name (i.e. <namespace>/<network name>@<ifname>)
|
||||
netNsName, networkName, netIfName, err := parsePodNetworkObjectName(commaItems[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsePodNetworkObject: %v", err)
|
||||
}
|
||||
m := make(map[string]interface{})
|
||||
m["name"] = networkName
|
||||
if netNsName != "" {
|
||||
m["namespace"] = netNsName
|
||||
}
|
||||
if netIfName != "" {
|
||||
m["interfaceRequest"] = netIfName
|
||||
}
|
||||
|
||||
podNet = append(podNet, m)
|
||||
}
|
||||
}
|
||||
|
||||
return podNet, nil
|
||||
}
|
||||
|
||||
func getpluginargs(name string, args string, primary bool) (string, error) {
|
||||
func isJSON(str string) bool {
|
||||
var js json.RawMessage
|
||||
return json.Unmarshal([]byte(str), &js) == nil
|
||||
}
|
||||
|
||||
func getpluginargs(name string, args string, primary bool, ifname string) (string, error) {
|
||||
var netconf string
|
||||
var tmpargs []string
|
||||
|
||||
@@ -314,11 +375,16 @@ func getpluginargs(name string, args string, primary bool) (string, error) {
|
||||
}
|
||||
|
||||
if primary != false {
|
||||
tmpargs = []string{`{"type": "`, name, `","masterplugin": true,`, args[strings.Index(args, "\"") : len(args)-1]}
|
||||
tmpargs = []string{`{"type": "`, name, `","masterplugin": true,`}
|
||||
} else {
|
||||
tmpargs = []string{`{"type": "`, name, `",`, args[strings.Index(args, "\"") : len(args)-1]}
|
||||
tmpargs = []string{`{"type": "`, name, `",`}
|
||||
}
|
||||
|
||||
if ifname != "" {
|
||||
tmpargs = append(tmpargs, fmt.Sprintf(`"ifnameRequest": "%s",`, ifname))
|
||||
}
|
||||
tmpargs = append(tmpargs, args[strings.Index(args, "\""):len(args)-1])
|
||||
|
||||
var str bytes.Buffer
|
||||
|
||||
for _, a := range tmpargs {
|
||||
@@ -330,12 +396,18 @@ func getpluginargs(name string, args string, primary bool) (string, error) {
|
||||
|
||||
}
|
||||
|
||||
func getnetplugin(client *kubernetes.Clientset, networkname string, primary bool) (string, error) {
|
||||
func getnetplugin(client *kubernetes.Clientset, networkinfo map[string]interface{}, primary bool) (string, error) {
|
||||
networkname := networkinfo["name"].(string)
|
||||
if networkname == "" {
|
||||
return "", fmt.Errorf("getnetplugin: network name can't be empty")
|
||||
}
|
||||
|
||||
tprclient := fmt.Sprintf("/apis/cni.cncf.io/v1/namespaces/default/kubernetes-network/%s", networkname)
|
||||
netNsName := "default"
|
||||
if networkinfo["namespace"] != nil {
|
||||
netNsName = networkinfo["namespace"].(string)
|
||||
}
|
||||
|
||||
tprclient := fmt.Sprintf("/apis/cni.cncf.io/v1/namespaces/%s/networks/%s", netNsName, networkname)
|
||||
|
||||
netobjdata, err := client.ExtensionsV1beta1().RESTClient().Get().AbsPath(tprclient).DoRaw()
|
||||
if err != nil {
|
||||
@@ -347,7 +419,12 @@ func getnetplugin(client *kubernetes.Clientset, networkname string, primary bool
|
||||
return "", fmt.Errorf("getnetplugin: failed to get the netplugin data: %v", err)
|
||||
}
|
||||
|
||||
netargs, err := getpluginargs(np.Plugin, np.Args, primary)
|
||||
ifnameRequest := ""
|
||||
if networkinfo["interfaceRequest"] != nil {
|
||||
ifnameRequest = networkinfo["interfaceRequest"].(string)
|
||||
}
|
||||
|
||||
netargs, err := getpluginargs(np.Plugin, np.Args, primary, ifnameRequest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -370,7 +447,7 @@ func getPodNetworkObj(client *kubernetes.Clientset, netObjs []map[string]interfa
|
||||
primary = true
|
||||
}
|
||||
|
||||
np, err = getnetplugin(client, net["name"].(string), primary)
|
||||
np, err = getnetplugin(client, net, primary)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getPodNetworkObj: failed in getting the netplugin: %v", err)
|
||||
}
|
||||
@@ -405,8 +482,10 @@ func getMultusDelegates(delegate string) ([]map[string]interface{}, error) {
|
||||
return tmpNetconf.Delegates, nil
|
||||
}
|
||||
|
||||
// NoK8sNetworkError indicates error, no network in kubernetes
|
||||
type NoK8sNetworkError string
|
||||
func (e NoK8sNetworkError) Error() string { return string(e) }
|
||||
|
||||
func (e NoK8sNetworkError) Error() string { return string(e) }
|
||||
|
||||
func getK8sNetwork(args *skel.CmdArgs, kubeconfig string) ([]map[string]interface{}, error) {
|
||||
k8sArgs := K8sArgs{}
|
||||
@@ -470,8 +549,20 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
|
||||
// If it's empty just leave it as the netconfig states (e.g. just default)
|
||||
if len(podDelegate) != 0 {
|
||||
n.Delegates = podDelegate
|
||||
if n.UseDefault {
|
||||
// In the case that we force the default
|
||||
// We add the found configs from CRD
|
||||
for _, eachDelegate := range podDelegate {
|
||||
eachDelegate["masterplugin"] = false
|
||||
n.Delegates = append(n.Delegates,eachDelegate)
|
||||
}
|
||||
|
||||
} else {
|
||||
// Otherwise, only the CRD delegates are used.
|
||||
n.Delegates = podDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +629,16 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
if len(podDelegate) != 0 {
|
||||
in.Delegates = podDelegate
|
||||
if in.UseDefault {
|
||||
// In the case that we force the default
|
||||
// We add the found configs from CRD (in reverse order)
|
||||
for i := len(podDelegate)-1; i >= 0; i-- {
|
||||
podDelegate[i]["masterplugin"] = false
|
||||
in.Delegates = append(in.Delegates,podDelegate[i])
|
||||
}
|
||||
} else {
|
||||
in.Delegates = podDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user