Skip to content

Commit 85a4eb0

Browse files
committed
WIP
Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
1 parent 35efceb commit 85a4eb0

11 files changed

Lines changed: 929 additions & 101 deletions

File tree

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ go 1.18
44

55
require (
66
github.com/containerd/containerd v1.6.8
7+
github.com/containernetworking/cni v1.1.1
8+
github.com/gogo/protobuf v1.3.2
79
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.3.0
810
github.com/onsi/ginkgo v1.16.5
911
github.com/onsi/gomega v1.17.0
12+
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
1013
k8s.io/api v0.24.4
1114
k8s.io/apimachinery v0.24.4
1215
k8s.io/client-go v0.24.4
@@ -33,7 +36,6 @@ require (
3336
github.com/go-openapi/jsonreference v0.19.5 // indirect
3437
github.com/go-openapi/swag v0.19.14 // indirect
3538
github.com/gogo/googleapis v1.4.0 // indirect
36-
github.com/gogo/protobuf v1.3.2 // indirect
3739
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
3840
github.com/golang/protobuf v1.5.2 // indirect
3941
github.com/google/gnostic v0.5.7-v3refs // indirect
@@ -55,7 +57,6 @@ require (
5557
github.com/opencontainers/go-digest v1.0.0 // indirect
5658
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
5759
github.com/opencontainers/runc v1.1.2 // indirect
58-
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
5960
github.com/opencontainers/selinux v1.10.1 // indirect
6061
github.com/pkg/errors v0.9.1 // indirect
6162
github.com/sirupsen/logrus v1.8.1 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNR
226226
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
227227
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
228228
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
229+
github.com/containernetworking/cni v1.1.1 h1:ky20T7c0MvKvbMOwS/FrlbNwjEoqJEUUYfsL4b0mc4k=
230+
github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
229231
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
230232
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
231233
github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
@@ -431,6 +433,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
431433
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
432434
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
433435
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
436+
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
434437
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
435438
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
436439
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -577,6 +580,8 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
577580
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
578581
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
579582
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
583+
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
584+
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
580585
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
581586
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
582587
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -1218,6 +1223,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
12181223
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
12191224
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
12201225
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
1226+
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
12211227
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
12221228
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
12231229
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,66 @@
11
package annotations
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
corev1 "k8s.io/api/core/v1"
8+
9+
nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
10+
)
11+
12+
const DynamicNetworksAnnotation = "cni.mutato.maiqueb.io/network-status"
13+
14+
func AddDynamicIfaceStatus(currentPod *corev1.Pod, netName string, ifaceName string, ips ...string) (string, error) {
15+
newIfaceStatus := nettypes.NetworkStatus{
16+
Name: netName,
17+
Interface: ifaceName,
18+
IPs: ips,
19+
}
20+
21+
currentIfaceStatus, err := podDynamicNetworkStatus(currentPod)
22+
if err != nil {
23+
return "", err
24+
}
25+
26+
newIfaceString, err := json.Marshal(append(currentIfaceStatus, newIfaceStatus))
27+
if err != nil {
28+
return "", fmt.Errorf("failed to marshall the dynamic networks status")
29+
}
30+
return string(newIfaceString), nil
31+
}
32+
33+
func DeleteDynamicIfaceStatus(currentPod *corev1.Pod, netName string, ifaceName string) (string, error) {
34+
currentIfaceStatus, err := podDynamicNetworkStatus(currentPod)
35+
if err != nil {
36+
return "", err
37+
}
38+
39+
var newIfaceStatus []nettypes.NetworkStatus
40+
for i := range currentIfaceStatus {
41+
if currentIfaceStatus[i].Name == netName && currentIfaceStatus[i].Interface == ifaceName {
42+
continue
43+
}
44+
newIfaceStatus = append(newIfaceStatus, currentIfaceStatus[i])
45+
}
46+
47+
newIfaceString, err := json.Marshal(newIfaceStatus)
48+
if err != nil {
49+
return "", fmt.Errorf("failed to marshall the dynamic networks status")
50+
}
51+
return string(newIfaceString), nil
52+
}
53+
54+
func podDynamicNetworkStatus(currentPod *corev1.Pod) ([]nettypes.NetworkStatus, error) {
55+
var currentIfaceStatus []nettypes.NetworkStatus
56+
if currentIfaceStatusString, wasFound := currentPod.Annotations[DynamicNetworksAnnotation]; wasFound {
57+
if err := json.Unmarshal([]byte(currentIfaceStatusString), &currentIfaceStatus); err != nil {
58+
return nil, fmt.Errorf("could not unmarshall the current dynamic annotations for pod %s: %v", podNameAndNs(currentPod), err)
59+
}
60+
}
61+
return currentIfaceStatus, nil
62+
}
63+
64+
func podNameAndNs(currentPod *corev1.Pod) string {
65+
return fmt.Sprintf("%s/%s", currentPod.GetNamespace(), currentPod.GetName())
66+
}

pkg/controller/pod.go

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package controller
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"reflect"
78
"strings"
89
"time"
910

1011
corev1 "k8s.io/api/core/v1"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113
"k8s.io/apimachinery/pkg/runtime"
1214
"k8s.io/apimachinery/pkg/util/wait"
1315
v1coreinformerfactory "k8s.io/client-go/informers"
@@ -26,6 +28,7 @@ import (
2628
"github.com/maiqueb/multus-dynamic-networks-controller/pkg/annotations"
2729
"github.com/maiqueb/multus-dynamic-networks-controller/pkg/cri"
2830
"github.com/maiqueb/multus-dynamic-networks-controller/pkg/logging"
31+
"github.com/maiqueb/multus-dynamic-networks-controller/pkg/multuscni"
2932
)
3033

3134
const (
@@ -150,13 +153,13 @@ func (pnc *PodNetworksController) handleDynamicInterfaceRequest(dynamicAttachmen
150153
if err != nil {
151154
return err
152155
}
153-
return pnc.addNetworks(dynamicAttachmentRequest.AttachmentNames, pod)
156+
return pnc.addNetworks(dynamicAttachmentRequest.AttachmentNames, pod, dynamicAttachmentRequest.PodNetNS)
154157
} else if dynamicAttachmentRequest.Type == "remove" {
155158
pod, err := pnc.podsLister.Pods(dynamicAttachmentRequest.PodNamespace).Get(dynamicAttachmentRequest.PodName)
156159
if err != nil {
157160
return err
158161
}
159-
return pnc.removeNetworks(dynamicAttachmentRequest.AttachmentNames, pod)
162+
return pnc.removeNetworks(dynamicAttachmentRequest.AttachmentNames, pod, dynamicAttachmentRequest.PodNetNS)
160163
} else {
161164
klog.Infof("very weird attachment request: %+v", dynamicAttachmentRequest)
162165
}
@@ -169,7 +172,7 @@ func (pnc *PodNetworksController) handleResult(err error, dynamicAttachmentReque
169172
pnc.workqueue.Forget(dynamicAttachmentRequest)
170173
return
171174
}
172-
175+
klog.Warningf("attachment failed for %v: %v", *dynamicAttachmentRequest, err)
173176
currentRetries := pnc.workqueue.NumRequeues(dynamicAttachmentRequest)
174177
if currentRetries <= maxRetries {
175178
klog.Errorf("re-queued request for: %v", dynamicAttachmentRequest)
@@ -245,19 +248,73 @@ func namespacedName(podNamespace string, podName string) string {
245248
return fmt.Sprintf("%s/%s", podNamespace, podName)
246249
}
247250

248-
func (pnc *PodNetworksController) addNetworks(netsToAdd []*nadv1.NetworkSelectionElement, pod *corev1.Pod) error {
251+
func (pnc *PodNetworksController) addNetworks(netsToAdd []*nadv1.NetworkSelectionElement, pod *corev1.Pod, netnsPath string) error {
249252
for i := range netsToAdd {
250253
klog.Infof("network to add: %v", netsToAdd[i])
254+
255+
netAttachDef, err := pnc.netAttachDefLister.NetworkAttachmentDefinitions(netsToAdd[i].Namespace).Get(netsToAdd[i].Name)
256+
if err != nil {
257+
klog.Errorf("failed to access the network-attachment-definition %s/%s: %v", netsToAdd[i].Namespace, netsToAdd[i].Name, err)
258+
return err
259+
}
260+
response, err := multuscni.DoCNI(
261+
multuscni.MultusDelegateURL(),
262+
delegateRequest("ADD", netsToAdd[i], netAttachDef, pod, netnsPath),
263+
pnc.multusSocketPath,
264+
)
265+
if err != nil {
266+
return fmt.Errorf("failed to ADD delegate: %v", err)
267+
}
268+
klog.Infof("response: %s", string(response))
269+
270+
newIfaceStatus, err := annotations.AddDynamicIfaceStatus(pod, netsToAdd[0].Name, netsToAdd[0].InterfaceRequest)
271+
if err != nil {
272+
return fmt.Errorf("failed to create the new dynamic network status annotation: %v", err)
273+
}
274+
pod.Annotations[annotations.DynamicNetworksAnnotation] = newIfaceStatus
275+
276+
_, err = pnc.k8sClientSet.CoreV1().Pods(pod.GetNamespace()).Update(context.Background(), pod, metav1.UpdateOptions{})
277+
if err != nil {
278+
return fmt.Errorf("failed to add pod's dynamic annotations for %s: %v", pod.GetName(), err)
279+
}
280+
251281
pnc.Eventf(pod, corev1.EventTypeNormal, "AddedInterface", "add network: %s", netsToAdd[i].Name)
252282
}
253283

254284
return nil
255285
}
256286

257-
func (pnc *PodNetworksController) removeNetworks(netsToRemove []*nadv1.NetworkSelectionElement, pod *corev1.Pod) error {
287+
func (pnc *PodNetworksController) removeNetworks(netsToRemove []*nadv1.NetworkSelectionElement, pod *corev1.Pod, netnsPath string) error {
258288
for i := range netsToRemove {
259289
klog.Infof("network to remove: %v", netsToRemove[i])
290+
291+
netAttachDef, err := pnc.netAttachDefLister.NetworkAttachmentDefinitions(netsToRemove[i].Namespace).Get(netsToRemove[i].Name)
292+
if err != nil {
293+
klog.Errorf("failed to access the network-attachment-definition %s/%s: %v", netsToRemove[i].Namespace, netsToRemove[i].Name, err)
294+
return err
295+
}
296+
297+
response, err := multuscni.DoCNI(
298+
multuscni.MultusDelegateURL(),
299+
delegateRequest("DEL", netsToRemove[i], netAttachDef, pod, netnsPath),
300+
pnc.multusSocketPath,
301+
)
302+
if err != nil {
303+
return fmt.Errorf("failed to remove delegate: %v", err)
304+
}
305+
306+
newPodIfaceStatus, err := annotations.DeleteDynamicIfaceStatus(pod, netsToRemove[0].Name, netsToRemove[0].InterfaceRequest)
307+
if err != nil {
308+
return fmt.Errorf("failed to compute the dynamic network attachments after deleting network: %s, iface: %s: %v", netsToRemove[0].Name, netsToRemove[0].InterfaceRequest, err)
309+
}
310+
pod.Annotations[annotations.DynamicNetworksAnnotation] = newPodIfaceStatus
311+
312+
_, err = pnc.k8sClientSet.CoreV1().Pods(pod.GetNamespace()).Update(context.Background(), pod, metav1.UpdateOptions{})
313+
if err != nil {
314+
return fmt.Errorf("failed to add pod's dynamic annotations for %s: %v", pod.GetName(), err)
315+
}
260316
pnc.Eventf(pod, corev1.EventTypeNormal, "RemovedInterface", "removed network: %s", netsToRemove[i].Name)
317+
klog.Infof("response: %s", string(response))
261318
}
262319

263320
return nil
@@ -354,3 +411,19 @@ func podContainerID(pod *corev1.Pod) string {
354411
}
355412
return cidURI
356413
}
414+
415+
func delegateRequest(command string, network *nadv1.NetworkSelectionElement, netAttachDef *nadv1.NetworkAttachmentDefinition, pod *corev1.Pod, netns string) interface{} {
416+
klog.V(logging.Debug).Infof("the net-attach-def config: %v", netAttachDef.Spec.Config)
417+
addRequest := &multuscni.Request{
418+
Env: map[string]string{
419+
"CNI_COMMAND": command,
420+
"CNI_CONTAINERID": podContainerID(pod),
421+
"CNI_NETNS": netns,
422+
"CNI_IFNAME": network.InterfaceRequest,
423+
"CNI_ARGS": fmt.Sprintf("K8S_POD_NAMESPACE=%s;K8S_POD_NAME=%s;K8S_POD_UID=%s", pod.GetNamespace(), pod.GetName(), string(pod.UID)),
424+
},
425+
Config: []byte(netAttachDef.Spec.Config),
426+
}
427+
428+
return addRequest
429+
}

pkg/multuscni/client.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package multuscni
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"io/ioutil"
10+
"k8s.io/klog/v2"
11+
"net"
12+
"net/http"
13+
)
14+
15+
func MultusDelegateURL() string {
16+
return "http://dummy/delegate"
17+
}
18+
19+
func DoCNI(url string, req interface{}, socketPath string) ([]byte, error) {
20+
data, err := json.Marshal(req)
21+
if err != nil {
22+
return nil, fmt.Errorf("failed to marshal CNI request %v: %v", req, err)
23+
}
24+
25+
client := &http.Client{
26+
Transport: &http.Transport{
27+
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
28+
return net.Dial("unix", socketPath)
29+
},
30+
},
31+
}
32+
33+
resp, err := client.Post(url, "application/json", bytes.NewReader(data))
34+
if err != nil {
35+
return nil, fmt.Errorf("failed to send CNI request: %v", err)
36+
}
37+
defer func(respBody io.ReadCloser) {
38+
if err := respBody.Close(); err != nil {
39+
klog.Errorf("failed closing the connection to the multus-server: %v", err)
40+
}
41+
}(resp.Body)
42+
43+
body, err := ioutil.ReadAll(resp.Body)
44+
if err != nil {
45+
return nil, fmt.Errorf("failed to read CNI result: %v", err)
46+
}
47+
48+
if resp.StatusCode != http.StatusOK {
49+
return nil, fmt.Errorf("CNI request failed with status %v: '%s'", resp.StatusCode, string(body))
50+
}
51+
52+
return body, nil
53+
}

0 commit comments

Comments
 (0)