Skip to content
This repository was archived by the owner on Jul 30, 2021. It is now read-only.

Commit 172a5f1

Browse files
author
Yifan Gu
authored
Merge pull request #524 from abhinavdahiya/calico_policy_support
Calico policy support
2 parents 8124547 + 593ae03 commit 172a5f1

File tree

16 files changed

+641
-33
lines changed

16 files changed

+641
-33
lines changed

cmd/bootkube/render.go

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ var (
5252
selfHostKubelet bool
5353
cloudProvider string
5454
selfHostedEtcd bool
55+
calicoNetworkPolicy bool
5556
}
5657

5758
imageVersions = asset.DefaultImages
@@ -73,6 +74,7 @@ func init() {
7374
cmdRender.Flags().BoolVar(&renderOpts.selfHostKubelet, "experimental-self-hosted-kubelet", false, "(Experimental) Create a self-hosted kubelet daemonset.")
7475
cmdRender.Flags().StringVar(&renderOpts.cloudProvider, "cloud-provider", "", "The provider for cloud services. Empty string for no provider")
7576
cmdRender.Flags().BoolVar(&renderOpts.selfHostedEtcd, "experimental-self-hosted-etcd", false, "(Experimental) Create self-hosted etcd assets.")
77+
cmdRender.Flags().BoolVar(&renderOpts.calicoNetworkPolicy, "experimental-calico-network-policy", false, "(Experimental) Add network policy support by calico.")
7678
}
7779

7880
func runCmdRender(cmd *cobra.Command, args []string) error {
@@ -222,25 +224,26 @@ func flagsToAssetConfig() (c *asset.Config, err error) {
222224
}
223225

224226
return &asset.Config{
225-
EtcdCACert: etcdCACert,
226-
EtcdClientCert: etcdClientCert,
227-
EtcdClientKey: etcdClientKey,
228-
EtcdServers: etcdServers,
229-
EtcdUseTLS: etcdUseTLS,
230-
CACert: caCert,
231-
CAPrivKey: caPrivKey,
232-
APIServers: apiServers,
233-
AltNames: altNames,
234-
PodCIDR: podNet,
235-
ServiceCIDR: serviceNet,
236-
APIServiceIP: apiServiceIP,
237-
BootEtcdServiceIP: bootEtcdServiceIP,
238-
DNSServiceIP: dnsServiceIP,
239-
EtcdServiceIP: etcdServiceIP,
240-
SelfHostKubelet: renderOpts.selfHostKubelet,
241-
CloudProvider: renderOpts.cloudProvider,
242-
SelfHostedEtcd: renderOpts.selfHostedEtcd,
243-
Images: imageVersions,
227+
EtcdCACert: etcdCACert,
228+
EtcdClientCert: etcdClientCert,
229+
EtcdClientKey: etcdClientKey,
230+
EtcdServers: etcdServers,
231+
EtcdUseTLS: etcdUseTLS,
232+
CACert: caCert,
233+
CAPrivKey: caPrivKey,
234+
APIServers: apiServers,
235+
AltNames: altNames,
236+
PodCIDR: podNet,
237+
ServiceCIDR: serviceNet,
238+
APIServiceIP: apiServiceIP,
239+
BootEtcdServiceIP: bootEtcdServiceIP,
240+
DNSServiceIP: dnsServiceIP,
241+
EtcdServiceIP: etcdServiceIP,
242+
SelfHostKubelet: renderOpts.selfHostKubelet,
243+
CloudProvider: renderOpts.cloudProvider,
244+
SelfHostedEtcd: renderOpts.selfHostedEtcd,
245+
CalicoNetworkPolicy: renderOpts.calicoNetworkPolicy,
246+
Images: imageVersions,
244247
}, nil
245248
}
246249

e2e/network_test.go

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
package e2e
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
"time"
8+
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
utilrand "k8s.io/apimachinery/pkg/util/rand"
11+
"k8s.io/client-go/pkg/api"
12+
"k8s.io/client-go/pkg/api/v1"
13+
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
14+
)
15+
16+
func TestNetwork(t *testing.T) {
17+
//
18+
// 1. create nginx service
19+
di, _, err := api.Codecs.UniversalDecoder().Decode(nginxDepNT, nil, &v1beta1.Deployment{})
20+
if err != nil {
21+
t.Fatalf("unable to decode deployment manifest: %v", err)
22+
}
23+
24+
d, ok := di.(*v1beta1.Deployment)
25+
if !ok {
26+
t.Fatalf("expected manifest to decode into *api.deployment, got %T", di)
27+
}
28+
_, err = client.ExtensionsV1beta1().Deployments(namespace).Create(d)
29+
if err != nil {
30+
t.Fatal(err)
31+
}
32+
33+
deleteDeployment := func() {
34+
delPropPolicy := metav1.DeletePropagationForeground
35+
client.ExtensionsV1beta1().Deployments(namespace).Delete("nginx-deployment-nt", &metav1.DeleteOptions{
36+
PropagationPolicy: &delPropPolicy,
37+
})
38+
}
39+
defer deleteDeployment()
40+
41+
if err := retry(10, time.Second*10, getNginxPod); err != nil {
42+
t.Fatalf("timed out waiting for nginx pod: %v", err)
43+
}
44+
45+
si, _, err := api.Codecs.UniversalDecoder().Decode(nginxSVCNT, nil, &v1.Service{})
46+
if err != nil {
47+
t.Fatalf("unable to decode service manifest: %v", err)
48+
}
49+
s, ok := si.(*v1.Service)
50+
if !ok {
51+
t.Fatalf("expected manifest to decode into *api.service, got %T", si)
52+
}
53+
_, err = client.CoreV1().Services(namespace).Create(s)
54+
if err != nil {
55+
t.Fatal(err)
56+
}
57+
defer client.CoreV1().Services(namespace).Delete("nginx-service-nt", &metav1.DeleteOptions{})
58+
59+
//
60+
// 2. create a wget pod that hits the nginx service
61+
testPodName := fmt.Sprintf("%s-%s", "wget-pod-nt", utilrand.String(5))
62+
wgetPodNT.ObjectMeta.Name = testPodName
63+
_, err = client.CoreV1().Pods(namespace).Create(wgetPodNT)
64+
if err != nil {
65+
t.Fatal(err)
66+
}
67+
68+
if err := retry(10, time.Second*10, getPod(testPodName)); err != nil {
69+
t.Fatalf(fmt.Sprintf("timed out waiting for wget pod to succeed: %v", err))
70+
}
71+
72+
t.Run("DefaultDeny", HelperDefaultDeny)
73+
t.Run("NetworkPolicy", HelperPolicy)
74+
}
75+
76+
func HelperDefaultDeny(t *testing.T) {
77+
//
78+
// 3. set DefaultDeny policy
79+
npi, _, err := api.Codecs.UniversalDecoder().Decode(defaultDenyNetworkPolicy, nil, &v1beta1.NetworkPolicy{})
80+
if err != nil {
81+
t.Fatalf("unable to decode network policy manifest: %v", err)
82+
}
83+
84+
np, ok := npi.(*v1beta1.NetworkPolicy)
85+
if !ok {
86+
t.Fatalf("expected manifest to decode into *api.networkpolicy, got %T", npi)
87+
}
88+
89+
httpRestClient := client.ExtensionsV1beta1().RESTClient()
90+
uri := fmt.Sprintf("/apis/%s/%s/namespaces/%s/%s",
91+
strings.ToLower("extensions"),
92+
strings.ToLower("v1beta1"),
93+
strings.ToLower(namespace),
94+
strings.ToLower("NetworkPolicies"))
95+
96+
result := httpRestClient.Post().RequestURI(uri).Body(np).Do()
97+
if result.Error() != nil {
98+
t.Fatal(result.Error())
99+
}
100+
defer func() {
101+
uri = fmt.Sprintf("/apis/%s/%s/namespaces/%s/%s/%s",
102+
strings.ToLower("extensions"),
103+
strings.ToLower("v1beta1"),
104+
strings.ToLower(namespace),
105+
strings.ToLower("NetworkPolicies"),
106+
strings.ToLower(np.ObjectMeta.Name))
107+
108+
result = httpRestClient.Delete().RequestURI(uri).Do()
109+
if result.Error() != nil {
110+
t.Fatal(result.Error())
111+
}
112+
113+
}()
114+
115+
//
116+
// 4. create a wget pod that fails to hit nginx service
117+
testPodName := fmt.Sprintf("%s-%s", "wget-pod-nt", utilrand.String(5))
118+
wgetPodNT.ObjectMeta.Name = testPodName
119+
_, err = client.CoreV1().Pods(namespace).Create(wgetPodNT)
120+
if err != nil {
121+
t.Fatal(err)
122+
}
123+
124+
if err := retry(10, time.Second*10, getFailedPod(testPodName)); err != nil {
125+
t.Fatalf(fmt.Sprintf("timed out waiting for wget pod to fail: %v", err))
126+
}
127+
}
128+
129+
func HelperPolicy(t *testing.T) {
130+
//
131+
// 5. create NetworkPolicy that allows `allow=access`
132+
npi, _, err := api.Codecs.UniversalDecoder().Decode(netPolicy, nil, &v1beta1.NetworkPolicy{})
133+
if err != nil {
134+
t.Fatalf("unable to decode network policy manifest: %v", err)
135+
}
136+
137+
np, ok := npi.(*v1beta1.NetworkPolicy)
138+
if !ok {
139+
t.Fatalf("expected manifest to decode into *api.networkpolicy, got %T", npi)
140+
}
141+
142+
httpRestClient := client.ExtensionsV1beta1().RESTClient()
143+
uri := fmt.Sprintf("/apis/%s/%s/namespaces/%s/%s",
144+
strings.ToLower("extensions"),
145+
strings.ToLower("v1beta1"),
146+
strings.ToLower(namespace),
147+
strings.ToLower("NetworkPolicies"))
148+
149+
result := httpRestClient.Post().RequestURI(uri).Body(np).Do()
150+
if result.Error() != nil {
151+
t.Fatal(result.Error())
152+
}
153+
defer func() {
154+
uri = fmt.Sprintf("/apis/%s/%s/namespaces/%s/%s/%s",
155+
strings.ToLower("extensions"),
156+
strings.ToLower("v1beta1"),
157+
strings.ToLower(namespace),
158+
strings.ToLower("NetworkPolicies"),
159+
strings.ToLower(np.ObjectMeta.Name))
160+
161+
result = httpRestClient.Delete().RequestURI(uri).Do()
162+
if result.Error() != nil {
163+
t.Fatal(result.Error())
164+
}
165+
166+
}()
167+
168+
//
169+
// 6. create a wget pod with label `allow=access` that hits the nginx service
170+
testPodName := fmt.Sprintf("%s-%s", "wget-pod-nt", utilrand.String(5))
171+
wgetPodNT.ObjectMeta.Name = testPodName
172+
wgetPodNT.ObjectMeta.Labels = map[string]string{}
173+
wgetPodNT.ObjectMeta.Labels["allow"] = "access"
174+
_, err = client.CoreV1().Pods(namespace).Create(wgetPodNT)
175+
if err != nil {
176+
t.Fatal(err)
177+
}
178+
179+
if err := retry(10, time.Second*10, getPod(testPodName)); err != nil {
180+
t.Fatalf(fmt.Sprintf("timed out waiting for wget pod to succeed: %v", err))
181+
}
182+
183+
//
184+
// 7. create a wget pod with label `allow=cant-access` that fails to the nginx service
185+
testPodName = fmt.Sprintf("%s-%s", "wget-pod-nt", utilrand.String(5))
186+
wgetPodNT.ObjectMeta.Name = testPodName
187+
wgetPodNT.ObjectMeta.Labels["allow"] = "cant-access"
188+
_, err = client.CoreV1().Pods(namespace).Create(wgetPodNT)
189+
if err != nil {
190+
t.Fatal(err)
191+
}
192+
193+
if err := retry(10, time.Second*10, getFailedPod(testPodName)); err != nil {
194+
t.Fatalf(fmt.Sprintf("timed out waiting for wget pod to fail: %v", err))
195+
}
196+
}
197+
198+
func getNginxPod() error {
199+
l, err := client.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: "app=nginx"})
200+
if err != nil || len(l.Items) == 0 {
201+
return fmt.Errorf("couldn't list pods: %v", err)
202+
}
203+
204+
// take the first pod
205+
p := &l.Items[0]
206+
207+
if p.Status.Phase != v1.PodRunning {
208+
return fmt.Errorf("pod not yet running: %v", p.Status.Phase)
209+
}
210+
return nil
211+
}
212+
213+
func getPod(name string) func() error {
214+
return func() error {
215+
p, err := client.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
216+
if err != nil {
217+
return fmt.Errorf("couldn't get pod: %v", err)
218+
}
219+
if p.Status.Phase != v1.PodSucceeded {
220+
return fmt.Errorf("pod did not succeed: %v", p.Status.Phase)
221+
}
222+
return nil
223+
}
224+
}
225+
226+
func getFailedPod(name string) func() error {
227+
return func() error {
228+
p, err := client.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
229+
if err != nil {
230+
return fmt.Errorf("couldn't get pod: %v", err)
231+
}
232+
if p.Status.Phase != v1.PodFailed {
233+
return fmt.Errorf("pod did not fail: %v", p.Status.Phase)
234+
}
235+
return nil
236+
}
237+
}
238+
239+
var nginxDepNT = []byte(`apiVersion: apps/v1beta1
240+
kind: Deployment
241+
metadata:
242+
name: nginx-deployment-nt
243+
spec:
244+
replicas: 3
245+
template:
246+
metadata:
247+
labels:
248+
app: nginx
249+
spec:
250+
containers:
251+
- name: nginx
252+
image: nginx:1.8
253+
ports:
254+
- containerPort: 80
255+
`)
256+
257+
var wgetPodNT = &v1.Pod{
258+
ObjectMeta: metav1.ObjectMeta{
259+
Namespace: namespace,
260+
},
261+
Spec: v1.PodSpec{
262+
Containers: []v1.Container{
263+
{
264+
Name: "wget-container",
265+
Image: "busybox:1.26",
266+
Command: []string{"wget", "--timeout", "5", "nginx-service-nt"},
267+
},
268+
},
269+
RestartPolicy: v1.RestartPolicyNever,
270+
},
271+
}
272+
273+
var nginxSVCNT = []byte(`apiVersion: v1
274+
kind: Service
275+
metadata:
276+
name: nginx-service-nt
277+
spec:
278+
selector:
279+
app: nginx
280+
ports:
281+
- protocol: TCP
282+
port: 80
283+
targetPort: 80
284+
`)
285+
286+
var defaultDenyNetworkPolicy = []byte(`kind: NetworkPolicy
287+
apiVersion: extensions/v1beta1
288+
metadata:
289+
name: default-deny
290+
spec:
291+
podSelector:
292+
`)
293+
294+
var netPolicy = []byte(`kind: NetworkPolicy
295+
apiVersion: extensions/v1beta1
296+
metadata:
297+
name: access-nginx
298+
spec:
299+
podSelector:
300+
matchLabels:
301+
app: nginx
302+
ingress:
303+
- from:
304+
- podSelector:
305+
matchLabels:
306+
allow: access
307+
`)

hack/multi-node/bootkube-up

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@ else
1818
etcd_render_flags="--etcd-servers=https://172.17.4.51:2379"
1919
fi
2020

21+
CALICO_NETWORK_POLICY=${CALICO_NETWORK_POLICY:-false}
22+
if [ ${CALICO_NETWORK_POLICY} = "true" ]; then
23+
echo "WARNING: THIS IS EXPERIMENTAL SUPPORT FOR NETWORK POLICY"
24+
cnp_render_flags="--experimental-calico-network-policy"
25+
else
26+
cnp_render_flags=""
27+
fi
28+
2129
# Render assets
2230
if [ ! -d "cluster" ]; then
23-
../../_output/bin/${local_os}/bootkube render --asset-dir=cluster --api-servers=https://172.17.4.101:443 ${etcd_render_flags}
31+
../../_output/bin/${local_os}/bootkube render --asset-dir=cluster --api-servers=https://172.17.4.101:443 ${etcd_render_flags} ${cnp_render_flags}
2432
cp user-data.sample cluster/user-data-worker
2533
cp user-data.sample cluster/user-data-controller
2634
sed -i.bak -e '/node-role.kubernetes.io\/master/d' cluster/user-data-worker

0 commit comments

Comments
 (0)