network: support network isolate
Add new crd to convert kubesphere network policy to k8s network policy, and then other network plugin will do the rest work. Use cache.go from calico project's kube-controller, it aim to sync nsnp with k8s np, delete unused np, and relieve the pressure on k8s restful client. If you want higher performance, you can implement interface NsNetworkPolicyProvider in pkg/controller/provider/namespace_np.go. Signed-off-by: Duan Jiong <djduanjiong@gmail.com>
This commit is contained in:
@@ -1,90 +1,285 @@
|
||||
package nsnetworkpolicy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"kubesphere.io/kubesphere/pkg/apis/network/v1alpha1"
|
||||
nsnplister "kubesphere.io/kubesphere/pkg/client/listers/network/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/controller/network/controllerapi"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
netv1 "k8s.io/api/networking/v1"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
informerv1 "k8s.io/client-go/informers/core/v1"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
netv1alpha1 "kubesphere.io/kubesphere/pkg/apis/network/v1alpha1"
|
||||
wkspv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
ksfake "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
|
||||
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
nsnppolicyinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/network/v1alpha1"
|
||||
workspaceinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/controller/network/provider"
|
||||
controllertesting "kubesphere.io/kubesphere/pkg/controller/network/testing"
|
||||
)
|
||||
|
||||
var (
|
||||
fakeControllerBuilder *controllertesting.FakeControllerBuilder
|
||||
c controllerapi.Controller
|
||||
stopCh chan struct{}
|
||||
calicoProvider *provider.FakeCalicoNetworkProvider
|
||||
nsnpLister nsnplister.NamespaceNetworkPolicyLister
|
||||
c *NSNetworkPolicyController
|
||||
stopCh chan struct{}
|
||||
nsnpInformer nsnppolicyinformer.NamespaceNetworkPolicyInformer
|
||||
serviceInformer informerv1.ServiceInformer
|
||||
workspaceInformer workspaceinformer.WorkspaceInformer
|
||||
namespaceInformer informerv1.NamespaceInformer
|
||||
alwaysReady = func() bool { return true }
|
||||
)
|
||||
|
||||
const (
|
||||
workspaceNP = `
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: "NetworkPolicy"
|
||||
metadata:
|
||||
name: networkisolate
|
||||
namespace: %s
|
||||
spec:
|
||||
podSelector: {}
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
%s: %s
|
||||
Egress:
|
||||
- To:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
%s: %s
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress`
|
||||
|
||||
serviceTmp = `
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myservice
|
||||
namespace: testns
|
||||
spec:
|
||||
selector:
|
||||
app: mylbapp
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
`
|
||||
|
||||
workspaceTmp = `
|
||||
apiVersion: tenant.kubesphere.io/v1alpha1
|
||||
kind: Workspace
|
||||
metadata:
|
||||
annotations:
|
||||
kubesphere.io/creator: admin
|
||||
name: testworkspace
|
||||
spec:
|
||||
manager: admin
|
||||
networkIsolation: true
|
||||
status: {}
|
||||
`
|
||||
|
||||
nsTmp = `
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
kubesphere.io/workspace: testworkspace
|
||||
name: testns
|
||||
spec:
|
||||
finalizers:
|
||||
- kubernetes
|
||||
`
|
||||
)
|
||||
|
||||
func StringToObject(data string, obj interface{}) error {
|
||||
reader := strings.NewReader(data)
|
||||
return yaml.NewYAMLOrJSONDecoder(reader, 10).Decode(obj)
|
||||
}
|
||||
|
||||
var _ = Describe("Nsnetworkpolicy", func() {
|
||||
BeforeEach(func() {
|
||||
fakeControllerBuilder = controllertesting.NewFakeControllerBuilder()
|
||||
stopCh = make(chan struct{})
|
||||
informer, _ := fakeControllerBuilder.NewControllerInformer()
|
||||
calicoProvider = provider.NewFakeCalicoNetworkProvider()
|
||||
c = NewController(fakeControllerBuilder.KubeClient, fakeControllerBuilder.KsClient, informer.Network().V1alpha1().NamespaceNetworkPolicies(), calicoProvider)
|
||||
go informer.Network().V1alpha1().NamespaceNetworkPolicies().Informer().Run(stopCh)
|
||||
originalController := c.(*controller)
|
||||
originalController.recorder = &record.FakeRecorder{}
|
||||
go c.Run(1, stopCh)
|
||||
nsnpLister = informer.Network().V1alpha1().NamespaceNetworkPolicies().Lister()
|
||||
calicoProvider := provider.NewFakeNetworkProvider()
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset()
|
||||
ksClient := ksfake.NewSimpleClientset()
|
||||
kubeInformer := kubeinformers.NewSharedInformerFactory(kubeClient, 0)
|
||||
ksInformer := ksinformers.NewSharedInformerFactory(ksClient, 0)
|
||||
|
||||
nsnpInformer := ksInformer.Network().V1alpha1().NamespaceNetworkPolicies()
|
||||
serviceInformer := kubeInformer.Core().V1().Services()
|
||||
workspaceInformer := ksInformer.Tenant().V1alpha1().Workspaces()
|
||||
namespaceInformer := kubeInformer.Core().V1().Namespaces()
|
||||
|
||||
c = NewNSNetworkPolicyController(kubeClient, ksClient.NetworkV1alpha1(), nsnpInformer, serviceInformer, workspaceInformer, namespaceInformer, calicoProvider)
|
||||
|
||||
serviceObj := &corev1.Service{}
|
||||
Expect(StringToObject(serviceTmp, serviceObj)).ShouldNot(HaveOccurred())
|
||||
Expect(serviceInformer.Informer().GetIndexer().Add(serviceObj)).ShouldNot(HaveOccurred())
|
||||
nsObj := &corev1.Namespace{}
|
||||
Expect(StringToObject(nsTmp, nsObj)).ShouldNot(HaveOccurred())
|
||||
namespaceInformer.Informer().GetIndexer().Add(nsObj)
|
||||
workspaceObj := &wkspv1alpha1.Workspace{}
|
||||
Expect(StringToObject(workspaceTmp, workspaceObj)).ShouldNot(HaveOccurred())
|
||||
workspaceInformer.Informer().GetIndexer().Add(workspaceObj)
|
||||
|
||||
c.namespaceInformerSynced = alwaysReady
|
||||
c.serviceInformerSynced = alwaysReady
|
||||
c.workspaceInformerSynced = alwaysReady
|
||||
c.informerSynced = alwaysReady
|
||||
|
||||
go c.Start(stopCh)
|
||||
})
|
||||
|
||||
It("Should create a new calico object", func() {
|
||||
objSrt := `{
|
||||
"apiVersion": "network.kubesphere.io/v1alpha1",
|
||||
"kind": "NetworkPolicy",
|
||||
"metadata": {
|
||||
"name": "allow-tcp-6379",
|
||||
"namespace": "production"
|
||||
},
|
||||
"spec": {
|
||||
"selector": "color == 'red'",
|
||||
"ingress": [
|
||||
{
|
||||
"action": "Allow",
|
||||
"protocol": "TCP",
|
||||
"source": {
|
||||
"selector": "color == 'blue'"
|
||||
},
|
||||
"destination": {
|
||||
"ports": [
|
||||
6379
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
obj := &v1alpha1.NamespaceNetworkPolicy{}
|
||||
Expect(controllertesting.StringToObject(objSrt, obj)).ShouldNot(HaveOccurred())
|
||||
_, err := fakeControllerBuilder.KsClient.NetworkV1alpha1().NamespaceNetworkPolicies(obj.Namespace).Create(obj)
|
||||
It("Should create ns networkisolate np correctly in workspace", func() {
|
||||
objSrt := fmt.Sprintf(workspaceNP, "testns", constants.WorkspaceLabelKey, "testworkspace", constants.WorkspaceLabelKey, "testworkspace")
|
||||
obj := &netv1.NetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj)).ShouldNot(HaveOccurred())
|
||||
|
||||
policy := generateNSNP("testworkspace", "testns", true)
|
||||
Expect(reflect.DeepEqual(obj.Spec, policy.Spec)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("Should create ns networkisolate np correctly in ns", func() {
|
||||
objSrt := fmt.Sprintf(workspaceNP, "testns", constants.NamespaceLabelKey, "testns", constants.NamespaceLabelKey, "testns")
|
||||
obj := &netv1.NetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj)).ShouldNot(HaveOccurred())
|
||||
|
||||
policy := generateNSNP("testworkspace", "testns", false)
|
||||
Expect(reflect.DeepEqual(obj.Spec, policy.Spec)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("test func convertToK8sNP", func() {
|
||||
objSrt := `
|
||||
apiVersion: network.kubesphere.io/v1alpha1
|
||||
kind: NamespaceNetworkPolicy
|
||||
metadata:
|
||||
name: namespaceIPblockNP
|
||||
namespace: testns
|
||||
spec:
|
||||
ingress:
|
||||
- from:
|
||||
- ipBlock:
|
||||
cidr: 172.0.0.1/16
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
`
|
||||
obj := &netv1alpha1.NamespaceNetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj)).ShouldNot(HaveOccurred())
|
||||
policy, err := c.convertToK8sNP(obj)
|
||||
|
||||
objSrt = `
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: "NetworkPolicy"
|
||||
metadata:
|
||||
name: IPblockNP
|
||||
namespace: testns
|
||||
spec:
|
||||
ingress:
|
||||
- from:
|
||||
- ipBlock:
|
||||
cidr: 172.0.0.1/16
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
policyTypes:
|
||||
- Ingress
|
||||
`
|
||||
obj2 := &netv1.NetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj2)).ShouldNot(HaveOccurred())
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(func() bool {
|
||||
exist, _ := calicoProvider.CheckExist(obj)
|
||||
return exist
|
||||
}).Should(BeTrue())
|
||||
obj, _ = fakeControllerBuilder.KsClient.NetworkV1alpha1().NamespaceNetworkPolicies(obj.Namespace).Get(obj.Name, metav1.GetOptions{})
|
||||
Expect(obj.Finalizers).To(HaveLen(1))
|
||||
// TestUpdate
|
||||
newStr := "color == 'green'"
|
||||
obj.Spec.Selector = newStr
|
||||
_, err = fakeControllerBuilder.KsClient.NetworkV1alpha1().NamespaceNetworkPolicies(obj.Namespace).Update(obj)
|
||||
Expect(reflect.DeepEqual(obj2.Spec, policy.Spec)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("test func convertToK8sNP with namespace", func() {
|
||||
objSrt := `
|
||||
apiVersion: network.kubesphere.io/v1alpha1
|
||||
kind: NamespaceNetworkPolicy
|
||||
metadata:
|
||||
name: testnamespace
|
||||
namespace: testns2
|
||||
spec:
|
||||
ingress:
|
||||
- from:
|
||||
- namespace:
|
||||
name: testns
|
||||
`
|
||||
obj := &netv1alpha1.NamespaceNetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj)).ShouldNot(HaveOccurred())
|
||||
|
||||
np, err := c.convertToK8sNP(obj)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(func() string {
|
||||
o, err := calicoProvider.Get(obj)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
n := o.(*v1alpha1.NamespaceNetworkPolicy)
|
||||
return n.Spec.Selector
|
||||
}).Should(Equal(newStr))
|
||||
// TestDelete
|
||||
Expect(fakeControllerBuilder.KsClient.NetworkV1alpha1().NamespaceNetworkPolicies(obj.Namespace).Delete(obj.Name, &metav1.DeleteOptions{})).ShouldNot(HaveOccurred())
|
||||
|
||||
objTmp := `
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: "NetworkPolicy"
|
||||
metadata:
|
||||
name: testnamespace
|
||||
namespace: testns2
|
||||
spec:
|
||||
podSelector: {}
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
%s: %s
|
||||
policyTypes:
|
||||
- Ingress`
|
||||
objSrt = fmt.Sprintf(objTmp, constants.NamespaceLabelKey, "testns")
|
||||
obj2 := &netv1.NetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj2)).ShouldNot(HaveOccurred())
|
||||
Expect(reflect.DeepEqual(np.Spec, obj2.Spec)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("test func convertToK8sNP with service", func() {
|
||||
objSrt := `
|
||||
apiVersion: network.kubesphere.io/v1alpha1
|
||||
kind: NamespaceNetworkPolicy
|
||||
metadata:
|
||||
name: testnamespace
|
||||
namespace: testns2
|
||||
spec:
|
||||
ingress:
|
||||
- from:
|
||||
- service:
|
||||
name: myservice
|
||||
namespace: testns
|
||||
`
|
||||
obj := &netv1alpha1.NamespaceNetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj)).ShouldNot(HaveOccurred())
|
||||
|
||||
np, err := c.convertToK8sNP(obj)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
objSrt = `
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: networkisolate
|
||||
namespace: testns
|
||||
spec:
|
||||
podSelector: {}
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: mylbapp
|
||||
namespaceSelector:
|
||||
matchLabels:
|
||||
kubesphere.io/namespace: testns
|
||||
policyTypes:
|
||||
- Ingress
|
||||
`
|
||||
obj2 := &netv1.NetworkPolicy{}
|
||||
Expect(StringToObject(objSrt, obj2)).ShouldNot(HaveOccurred())
|
||||
Expect(reflect.DeepEqual(np.Spec, obj2.Spec)).To(BeTrue())
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
|
||||
Reference in New Issue
Block a user