Browse code

VMware Admission Controller patch for Kubernetes 1.9 and 1.10

Change-Id: I1b6215dbdab4847d56cf7920029256216d43b2fc
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/5224
Reviewed-by: Anish Swaminathan <anishs@vmware.com>
Reviewed-by: Bo Gan <ganb@vmware.com>
Tested-by: gerrit-photon <photon-checkins@vmware.com>

Bo Gan authored on 2018/06/03 08:42:43
Showing 4 changed files
... ...
@@ -1,6 +1,81 @@
1
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1alpha1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/apps_v1alpha1.json
2
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/apps_v1alpha1.json	2018-04-30 21:11:51.000000000 +0000
1
+From e6e701d8663ca3dbcf298ed4a10bf5b6120ce4d3 Mon Sep 17 00:00:00 2001
2
+From: Bo Gan <ganb@vmware.com>
3
+Date: Sat, 2 Jun 2018 16:24:59 -0700
4
+Subject: [PATCH] Cascade Kubernetes patches for v1.9.6 (8ef8da7)
5
+
6
+---
7
+ api/swagger-spec/apps_v1alpha1.json                |  21 +
8
+ api/swagger-spec/apps_v1beta1.json                 |  21 +
9
+ api/swagger-spec/apps_v1beta2.json                 |  21 +
10
+ api/swagger-spec/batch_v1.json                     |  21 +
11
+ api/swagger-spec/batch_v1beta1.json                |  21 +
12
+ api/swagger-spec/batch_v2alpha1.json               |  21 +
13
+ api/swagger-spec/extensions_v1beta1.json           |  21 +
14
+ api/swagger-spec/settings.k8s.io_v1alpha1.json     |  21 +
15
+ api/swagger-spec/v1.json                           |  25 +
16
+ cmd/kube-apiserver/app/options/plugins.go          |   2 +
17
+ cmd/kube-controller-manager/app/BUILD              |   1 +
18
+ cmd/kube-controller-manager/app/plugins.go         |   4 +
19
+ cmd/kubelet/app/BUILD                              |   1 +
20
+ cmd/kubelet/app/plugins.go                         |   2 +
21
+ pkg/apis/core/types.go                             |  14 +
22
+ pkg/apis/core/validation/validation.go             |  25 +
23
+ pkg/apis/extensions/types.go                       |   1 +
24
+ pkg/cloudprovider/providers/BUILD                  |   2 +
25
+ pkg/cloudprovider/providers/cascade/BUILD          |  44 ++
26
+ pkg/cloudprovider/providers/cascade/OWNERS         |   3 +
27
+ pkg/cloudprovider/providers/cascade/apitypes.go    | 227 +++++++++
28
+ pkg/cloudprovider/providers/cascade/auth.go        | 145 ++++++
29
+ pkg/cloudprovider/providers/cascade/cascade.go     | 216 ++++++++
30
+ .../providers/cascade/cascade_disks.go             | 225 +++++++++
31
+ .../providers/cascade/cascade_instances.go         |  90 ++++
32
+ .../providers/cascade/cascade_loadbalancer.go      | 284 +++++++++++
33
+ pkg/cloudprovider/providers/cascade/client.go      | 394 +++++++++++++++
34
+ pkg/cloudprovider/providers/cascade/oidcclient.go  | 297 +++++++++++
35
+ pkg/cloudprovider/providers/cascade/restclient.go  | 262 ++++++++++
36
+ pkg/cloudprovider/providers/cascade/tests_owed     |   5 +
37
+ pkg/cloudprovider/providers/cascade/utils.go       |  25 +
38
+ pkg/cloudprovider/providers/providers.go           |   1 +
39
+ pkg/printers/internalversion/describe.go           |  11 +
40
+ pkg/security/podsecuritypolicy/util/util.go        |   3 +
41
+ pkg/volume/cascade_disk/BUILD                      |  43 ++
42
+ pkg/volume/cascade_disk/OWNERS                     |   2 +
43
+ pkg/volume/cascade_disk/attacher.go                | 269 ++++++++++
44
+ pkg/volume/cascade_disk/cascade_disk.go            | 391 +++++++++++++++
45
+ pkg/volume/cascade_disk/cascade_util.go            | 107 ++++
46
+ .../admission/persistentvolume/label/admission.go  |  54 ++
47
+ plugin/pkg/admission/vke/BUILD                     |  58 +++
48
+ plugin/pkg/admission/vke/admission.go              | 374 ++++++++++++++
49
+ plugin/pkg/admission/vke/admission_test.go         | 541 +++++++++++++++++++++
50
+ staging/src/k8s.io/api/core/v1/generated.pb.go     | 310 +++++++++++-
51
+ staging/src/k8s.io/api/core/v1/types.go            |  26 +-
52
+ 45 files changed, 4623 insertions(+), 29 deletions(-)
53
+ create mode 100644 pkg/cloudprovider/providers/cascade/BUILD
54
+ create mode 100644 pkg/cloudprovider/providers/cascade/OWNERS
55
+ create mode 100644 pkg/cloudprovider/providers/cascade/apitypes.go
56
+ create mode 100644 pkg/cloudprovider/providers/cascade/auth.go
57
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade.go
58
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade_disks.go
59
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade_instances.go
60
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go
61
+ create mode 100644 pkg/cloudprovider/providers/cascade/client.go
62
+ create mode 100644 pkg/cloudprovider/providers/cascade/oidcclient.go
63
+ create mode 100644 pkg/cloudprovider/providers/cascade/restclient.go
64
+ create mode 100644 pkg/cloudprovider/providers/cascade/tests_owed
65
+ create mode 100644 pkg/cloudprovider/providers/cascade/utils.go
66
+ create mode 100644 pkg/volume/cascade_disk/BUILD
67
+ create mode 100644 pkg/volume/cascade_disk/OWNERS
68
+ create mode 100644 pkg/volume/cascade_disk/attacher.go
69
+ create mode 100644 pkg/volume/cascade_disk/cascade_disk.go
70
+ create mode 100644 pkg/volume/cascade_disk/cascade_util.go
71
+ create mode 100644 plugin/pkg/admission/vke/BUILD
72
+ create mode 100644 plugin/pkg/admission/vke/admission.go
73
+ create mode 100644 plugin/pkg/admission/vke/admission_test.go
74
+
75
+diff --git a/api/swagger-spec/apps_v1alpha1.json b/api/swagger-spec/apps_v1alpha1.json
76
+index aa3fbdc..9dba11e 100644
77
+--- a/api/swagger-spec/apps_v1alpha1.json
3 78
 @@ -1459,6 +1459,10 @@
4 79
       "photonPersistentDisk": {
5 80
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
... ...
@@ -12,14 +87,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1alpha1.js
12 12
       }
13 13
      }
14 14
     },
15
-@@ -2105,6 +2109,23 @@
16
-      },
17
-      "fsType": {
18
-       "type": "string",
19
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
20
-+     }
21
-+    }
22
-+   },
15
+@@ -2109,6 +2113,23 @@
16
+      }
17
+     }
18
+    },
23 19
 +   "v1.CascadeDiskVolumeSource": {
24 20
 +    "id": "v1.CascadeDiskVolumeSource",
25 21
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -33,12 +104,17 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1alpha1.js
33 33
 +     },
34 34
 +     "fsType": {
35 35
 +      "type": "string",
36
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
37
-      }
38
-     }
39
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1beta1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/apps_v1beta1.json
40
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/apps_v1beta1.json	2018-04-30 21:11:51.000000000 +0000
36
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
37
++     }
38
++    }
39
++   },
40
+    "v1.Container": {
41
+     "id": "v1.Container",
42
+     "description": "A single application container that you want to run within a pod.",
43
+diff --git a/api/swagger-spec/apps_v1beta1.json b/api/swagger-spec/apps_v1beta1.json
44
+index e253317..6968ed0 100644
45
+--- a/api/swagger-spec/apps_v1beta1.json
41 46
 @@ -4479,6 +4479,10 @@
42 47
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
43 48
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
... ...
@@ -50,14 +126,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1beta1.jso
50 50
       "projected": {
51 51
        "$ref": "v1.ProjectedVolumeSource",
52 52
        "description": "Items for all in one resources secrets, configmaps, and downward API"
53
-@@ -5202,6 +5206,23 @@
54
-      },
55
-      "fsType": {
56
-       "type": "string",
57
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
58
-+     }
59
-+    }
60
-+   },
53
+@@ -5206,6 +5210,23 @@
54
+      }
55
+     }
56
+    },
61 57
 +   "v1.CascadeDiskVolumeSource": {
62 58
 +    "id": "v1.CascadeDiskVolumeSource",
63 59
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -71,12 +143,17 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1beta1.jso
71 71
 +     },
72 72
 +     "fsType": {
73 73
 +      "type": "string",
74
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
75
-      }
76
-     }
77
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1beta2.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/apps_v1beta2.json
78
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/apps_v1beta2.json	2018-04-30 21:11:51.000000000 +0000
74
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
75
++     }
76
++    }
77
++   },
78
+    "v1.ProjectedVolumeSource": {
79
+     "id": "v1.ProjectedVolumeSource",
80
+     "description": "Represents a projected volume source",
81
+diff --git a/api/swagger-spec/apps_v1beta2.json b/api/swagger-spec/apps_v1beta2.json
82
+index be42788..28d0247 100644
83
+--- a/api/swagger-spec/apps_v1beta2.json
79 84
 @@ -6845,6 +6845,10 @@
80 85
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
81 86
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
... ...
@@ -88,14 +165,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1beta2.jso
88 88
       "projected": {
89 89
        "$ref": "v1.ProjectedVolumeSource",
90 90
        "description": "Items for all in one resources secrets, configmaps, and downward API"
91
-@@ -7568,6 +7572,23 @@
92
-      },
93
-      "fsType": {
94
-       "type": "string",
95
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
96
-+     }
97
-+    }
98
-+   },
91
+@@ -7572,6 +7576,23 @@
92
+      }
93
+     }
94
+    },
99 95
 +   "v1.CascadeDiskVolumeSource": {
100 96
 +    "id": "v1.CascadeDiskVolumeSource",
101 97
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -109,13 +182,18 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/apps_v1beta2.jso
109 109
 +     },
110 110
 +     "fsType": {
111 111
 +      "type": "string",
112
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
113
-      }
114
-     }
115
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v1beta1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/batch_v1beta1.json
116
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/batch_v1beta1.json	2018-04-30 21:11:51.000000000 +0000
117
-@@ -1874,6 +1874,10 @@
112
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
113
++     }
114
++    }
115
++   },
116
+    "v1.ProjectedVolumeSource": {
117
+     "id": "v1.ProjectedVolumeSource",
118
+     "description": "Represents a projected volume source",
119
+diff --git a/api/swagger-spec/batch_v1.json b/api/swagger-spec/batch_v1.json
120
+index 28787d8..9adba42 100644
121
+--- a/api/swagger-spec/batch_v1.json
122
+@@ -1819,6 +1819,10 @@
118 123
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
119 124
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
120 125
       },
... ...
@@ -126,14 +204,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v1beta1.js
126 126
       "projected": {
127 127
        "$ref": "v1.ProjectedVolumeSource",
128 128
        "description": "Items for all in one resources secrets, configmaps, and downward API"
129
-@@ -2597,6 +2601,23 @@
130
-      },
131
-      "fsType": {
132
-       "type": "string",
133
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
134
-+     }
135
-+    }
136
-+   },
129
+@@ -2546,6 +2550,23 @@
130
+      }
131
+     }
132
+    },
137 133
 +   "v1.CascadeDiskVolumeSource": {
138 134
 +    "id": "v1.CascadeDiskVolumeSource",
139 135
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -147,13 +221,18 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v1beta1.js
147 147
 +     },
148 148
 +     "fsType": {
149 149
 +      "type": "string",
150
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
151
-      }
152
-     }
153
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/batch_v1.json
154
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/batch_v1.json	2018-04-30 21:11:51.000000000 +0000
155
-@@ -1819,6 +1819,10 @@
150
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
151
++     }
152
++    }
153
++   },
154
+    "v1.ProjectedVolumeSource": {
155
+     "id": "v1.ProjectedVolumeSource",
156
+     "description": "Represents a projected volume source",
157
+diff --git a/api/swagger-spec/batch_v1beta1.json b/api/swagger-spec/batch_v1beta1.json
158
+index bb9b870..8bab946 100644
159
+--- a/api/swagger-spec/batch_v1beta1.json
160
+@@ -1874,6 +1874,10 @@
156 161
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
157 162
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
158 163
       },
... ...
@@ -164,14 +243,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v1.json ku
164 164
       "projected": {
165 165
        "$ref": "v1.ProjectedVolumeSource",
166 166
        "description": "Items for all in one resources secrets, configmaps, and downward API"
167
-@@ -2542,6 +2546,23 @@
168
-      },
169
-      "fsType": {
170
-       "type": "string",
171
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
172
-+     }
173
-+    }
174
-+   },
167
+@@ -2601,6 +2605,23 @@
168
+      }
169
+     }
170
+    },
175 171
 +   "v1.CascadeDiskVolumeSource": {
176 172
 +    "id": "v1.CascadeDiskVolumeSource",
177 173
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -185,12 +260,17 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v1.json ku
185 185
 +     },
186 186
 +     "fsType": {
187 187
 +      "type": "string",
188
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
189
-      }
190
-     }
191
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v2alpha1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/batch_v2alpha1.json
192
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/batch_v2alpha1.json	2018-04-30 21:11:51.000000000 +0000
188
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
189
++     }
190
++    }
191
++   },
192
+    "v1.ProjectedVolumeSource": {
193
+     "id": "v1.ProjectedVolumeSource",
194
+     "description": "Represents a projected volume source",
195
+diff --git a/api/swagger-spec/batch_v2alpha1.json b/api/swagger-spec/batch_v2alpha1.json
196
+index cde6619..1e428a5 100644
197
+--- a/api/swagger-spec/batch_v2alpha1.json
193 198
 @@ -1889,6 +1889,10 @@
194 199
       "storageos": {
195 200
        "$ref": "v1.StorageOSVolumeSource",
... ...
@@ -226,9 +306,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/batch_v2alpha1.j
226 226
     "v1.Container": {
227 227
      "id": "v1.Container",
228 228
      "description": "A single application container that you want to run within a pod.",
229
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/extensions_v1beta1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/extensions_v1beta1.json
230
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/extensions_v1beta1.json	2018-04-30 21:11:51.000000000 +0000
229
+diff --git a/api/swagger-spec/extensions_v1beta1.json b/api/swagger-spec/extensions_v1beta1.json
230
+index d8b20a3..ea271e1 100644
231
+--- a/api/swagger-spec/extensions_v1beta1.json
231 232
 @@ -7502,6 +7502,10 @@
232 233
       "storageos": {
233 234
        "$ref": "v1.StorageOSVolumeSource",
... ...
@@ -240,14 +321,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/extensions_v1bet
240 240
       }
241 241
      }
242 242
     },
243
-@@ -8210,6 +8214,23 @@
244
-      },
245
-      "fsType": {
246
-       "type": "string",
247
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
248
-+     }
249
-+    }
250
-+   },
243
+@@ -8214,6 +8218,23 @@
244
+      }
245
+     }
246
+    },
251 247
 +   "v1.CascadeDiskVolumeSource": {
252 248
 +    "id": "v1.CascadeDiskVolumeSource",
253 249
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -261,12 +338,17 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/extensions_v1bet
261 261
 +     },
262 262
 +     "fsType": {
263 263
 +      "type": "string",
264
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
265
-      }
266
-     }
267
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/settings.k8s.io_v1alpha1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/settings.k8s.io_v1alpha1.json
268
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/settings.k8s.io_v1alpha1.json	2018-04-30 21:11:51.000000000 +0000
264
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
265
++     }
266
++    }
267
++   },
268
+    "v1.ProjectedVolumeSource": {
269
+     "id": "v1.ProjectedVolumeSource",
270
+     "description": "Represents a projected volume source",
271
+diff --git a/api/swagger-spec/settings.k8s.io_v1alpha1.json b/api/swagger-spec/settings.k8s.io_v1alpha1.json
272
+index dc442a8..c1b2d1e 100644
273
+--- a/api/swagger-spec/settings.k8s.io_v1alpha1.json
269 274
 @@ -1676,6 +1676,10 @@
270 275
       "storageos": {
271 276
        "$ref": "v1.StorageOSVolumeSource",
... ...
@@ -278,14 +360,10 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/settings.k8s.io_
278 278
       }
279 279
      }
280 280
     },
281
-@@ -2346,6 +2350,23 @@
282
-      },
283
-      "fsType": {
284
-       "type": "string",
285
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
286
-+     }
287
-+    }
288
-+   },
281
+@@ -2350,6 +2354,23 @@
282
+      }
283
+     }
284
+    },
289 285
 +   "v1.CascadeDiskVolumeSource": {
290 286
 +    "id": "v1.CascadeDiskVolumeSource",
291 287
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -299,12 +377,17 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/settings.k8s.io_
299 299
 +     },
300 300
 +     "fsType": {
301 301
 +      "type": "string",
302
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
303
-      }
304
-     }
305
-diff -uNr --no-dereference kubernetes-original/api/swagger-spec/v1.json kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/v1.json
306
-+++ kubernetes-modified/src/k8s.io/kubernetes/api/swagger-spec/v1.json	2018-04-30 21:11:51.000000000 +0000
302
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
303
++     }
304
++    }
305
++   },
306
+    "v1.ProjectedVolumeSource": {
307
+     "id": "v1.ProjectedVolumeSource",
308
+     "description": "Represents a projected volume source",
309
+diff --git a/api/swagger-spec/v1.json b/api/swagger-spec/v1.json
310
+index 97be62b..e1cba2b 100644
311
+--- a/api/swagger-spec/v1.json
307 312
 @@ -20629,6 +20629,10 @@
308 313
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
309 314
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
... ...
@@ -351,10 +434,29 @@ diff -uNr --no-dereference kubernetes-original/api/swagger-spec/v1.json kubernet
351 351
       }
352 352
      }
353 353
     },
354
-diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/BUILD kubernetes-modified/src/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD
355
-+++ kubernetes-modified/src/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD	2018-04-30 21:11:51.000000000 +0000
356
-@@ -86,6 +86,7 @@
354
+diff --git a/cmd/kube-apiserver/app/options/plugins.go b/cmd/kube-apiserver/app/options/plugins.go
355
+index a0d2502..4fe32e4 100644
356
+--- a/cmd/kube-apiserver/app/options/plugins.go
357
+@@ -52,6 +52,7 @@ import (
358
+ 	"k8s.io/kubernetes/plugin/pkg/admission/securitycontext/scdeny"
359
+ 	"k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
360
+ 	"k8s.io/kubernetes/plugin/pkg/admission/storageclass/setdefault"
361
++	"k8s.io/kubernetes/plugin/pkg/admission/vke"
362
+ )
363
+ 
364
+ // RegisterAllAdmissionPlugins registers all admission plugins
365
+@@ -83,4 +84,5 @@ func RegisterAllAdmissionPlugins(plugins *admission.Plugins) {
366
+ 	setdefault.Register(plugins)
367
+ 	resize.Register(plugins)
368
+ 	pvcprotection.Register(plugins)
369
++	vke.Register(plugins)
370
+ }
371
+diff --git a/cmd/kube-controller-manager/app/BUILD b/cmd/kube-controller-manager/app/BUILD
372
+index c518b36..f1a91f6 100644
373
+--- a/cmd/kube-controller-manager/app/BUILD
374
+@@ -86,6 +86,7 @@ go_library(
357 375
          "//pkg/volume/aws_ebs:go_default_library",
358 376
          "//pkg/volume/azure_dd:go_default_library",
359 377
          "//pkg/volume/azure_file:go_default_library",
... ...
@@ -362,10 +464,11 @@ diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/B
362 362
          "//pkg/volume/cinder:go_default_library",
363 363
          "//pkg/volume/csi:go_default_library",
364 364
          "//pkg/volume/fc:go_default_library",
365
-diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/plugins.go kubernetes-modified/src/k8s.io/kubernetes/cmd/kube-controller-manager/app/plugins.go
366
-+++ kubernetes-modified/src/k8s.io/kubernetes/cmd/kube-controller-manager/app/plugins.go	2018-04-30 21:11:51.000000000 +0000
367
-@@ -34,6 +34,7 @@
365
+diff --git a/cmd/kube-controller-manager/app/plugins.go b/cmd/kube-controller-manager/app/plugins.go
366
+index 170c366..5fa1cb1 100644
367
+--- a/cmd/kube-controller-manager/app/plugins.go
368
+@@ -34,6 +34,7 @@ import (
368 369
  	"k8s.io/kubernetes/pkg/volume/aws_ebs"
369 370
  	"k8s.io/kubernetes/pkg/volume/azure_dd"
370 371
  	"k8s.io/kubernetes/pkg/volume/azure_file"
... ...
@@ -373,7 +476,7 @@ diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/p
373 373
  	"k8s.io/kubernetes/pkg/volume/cinder"
374 374
  	"k8s.io/kubernetes/pkg/volume/csi"
375 375
  	"k8s.io/kubernetes/pkg/volume/fc"
376
-@@ -77,6 +78,7 @@
376
+@@ -77,6 +78,7 @@ func ProbeAttachableVolumePlugins() []volume.VolumePlugin {
377 377
  	allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
378 378
  	allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
379 379
  	allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
... ...
@@ -381,7 +484,7 @@ diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/p
381 381
  	if utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
382 382
  		allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
383 383
  	}
384
-@@ -106,6 +108,7 @@
384
+@@ -106,6 +108,7 @@ func ProbeExpandableVolumePlugins(config componentconfig.VolumeConfiguration) []
385 385
  	allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
386 386
  	allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
387 387
  	allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
... ...
@@ -389,7 +492,7 @@ diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/p
389 389
  	if !utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
390 390
  		allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
391 391
  	}
392
-@@ -165,6 +168,7 @@
392
+@@ -165,6 +168,7 @@ func ProbeControllerVolumePlugins(cloud cloudprovider.Interface, config componen
393 393
  	allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
394 394
  	allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
395 395
  	allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
... ...
@@ -397,10 +500,11 @@ diff -uNr --no-dereference kubernetes-original/cmd/kube-controller-manager/app/p
397 397
  
398 398
  	return allPlugins
399 399
  }
400
-diff -uNr --no-dereference kubernetes-original/cmd/kubelet/app/BUILD kubernetes-modified/src/k8s.io/kubernetes/cmd/kubelet/app/BUILD
401
-+++ kubernetes-modified/src/k8s.io/kubernetes/cmd/kubelet/app/BUILD	2018-04-30 21:11:51.000000000 +0000
402
-@@ -74,6 +74,7 @@
400
+diff --git a/cmd/kubelet/app/BUILD b/cmd/kubelet/app/BUILD
401
+index c7e482f..0d3645a 100644
402
+--- a/cmd/kubelet/app/BUILD
403
+@@ -74,6 +74,7 @@ go_library(
403 404
          "//pkg/volume/aws_ebs:go_default_library",
404 405
          "//pkg/volume/azure_dd:go_default_library",
405 406
          "//pkg/volume/azure_file:go_default_library",
... ...
@@ -408,10 +512,11 @@ diff -uNr --no-dereference kubernetes-original/cmd/kubelet/app/BUILD kubernetes-
408 408
          "//pkg/volume/cephfs:go_default_library",
409 409
          "//pkg/volume/cinder:go_default_library",
410 410
          "//pkg/volume/configmap:go_default_library",
411
-diff -uNr --no-dereference kubernetes-original/cmd/kubelet/app/plugins.go kubernetes-modified/src/k8s.io/kubernetes/cmd/kubelet/app/plugins.go
412
-+++ kubernetes-modified/src/k8s.io/kubernetes/cmd/kubelet/app/plugins.go	2018-04-30 21:11:51.000000000 +0000
413
-@@ -32,6 +32,7 @@
411
+diff --git a/cmd/kubelet/app/plugins.go b/cmd/kubelet/app/plugins.go
412
+index ef41bb8..c9806f7 100644
413
+--- a/cmd/kubelet/app/plugins.go
414
+@@ -32,6 +32,7 @@ import (
414 415
  	"k8s.io/kubernetes/pkg/volume/aws_ebs"
415 416
  	"k8s.io/kubernetes/pkg/volume/azure_dd"
416 417
  	"k8s.io/kubernetes/pkg/volume/azure_file"
... ...
@@ -419,7 +524,7 @@ diff -uNr --no-dereference kubernetes-original/cmd/kubelet/app/plugins.go kubern
419 419
  	"k8s.io/kubernetes/pkg/volume/cephfs"
420 420
  	"k8s.io/kubernetes/pkg/volume/cinder"
421 421
  	"k8s.io/kubernetes/pkg/volume/configmap"
422
-@@ -100,6 +101,7 @@
422
+@@ -100,6 +101,7 @@ func ProbeVolumePlugins() []volume.VolumePlugin {
423 423
  	allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
424 424
  	allPlugins = append(allPlugins, local.ProbeVolumePlugins()...)
425 425
  	allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
... ...
@@ -427,259 +532,11 @@ diff -uNr --no-dereference kubernetes-original/cmd/kubelet/app/plugins.go kubern
427 427
  	if utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
428 428
  		allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
429 429
  	}
430
-diff -uNr --no-dereference kubernetes-original/.idea/kubernetes.iml kubernetes-modified/src/k8s.io/kubernetes/.idea/kubernetes.iml
431
-+++ kubernetes-modified/src/k8s.io/kubernetes/.idea/kubernetes.iml	2018-04-30 21:11:51.000000000 +0000
432
-@@ -0,0 +1,9 @@
433
-+<?xml version="1.0" encoding="UTF-8"?>
434
-+<module type="JAVA_MODULE" version="4">
435
-+  <component name="NewModuleRootManager" inherit-compiler-output="true">
436
-+    <exclude-output />
437
-+    <content url="file://$MODULE_DIR$" />
438
-+    <orderEntry type="inheritedJdk" />
439
-+    <orderEntry type="sourceFolder" forTests="false" />
440
-+  </component>
441
-+</module>
442
-\ No newline at end of file
443
-diff -uNr --no-dereference kubernetes-original/.idea/modules.xml kubernetes-modified/src/k8s.io/kubernetes/.idea/modules.xml
444
-+++ kubernetes-modified/src/k8s.io/kubernetes/.idea/modules.xml	2018-04-30 21:11:51.000000000 +0000
445
-@@ -0,0 +1,8 @@
446
-+<?xml version="1.0" encoding="UTF-8"?>
447
-+<project version="4">
448
-+  <component name="ProjectModuleManager">
449
-+    <modules>
450
-+      <module fileurl="file://$PROJECT_DIR$/.idea/kubernetes.iml" filepath="$PROJECT_DIR$/.idea/kubernetes.iml" />
451
-+    </modules>
452
-+  </component>
453
-+</project>
454
-\ No newline at end of file
455
-diff -uNr --no-dereference kubernetes-original/.idea/workspace.xml kubernetes-modified/src/k8s.io/kubernetes/.idea/workspace.xml
456
-+++ kubernetes-modified/src/k8s.io/kubernetes/.idea/workspace.xml	2018-04-30 21:11:51.000000000 +0000
457
-@@ -0,0 +1,217 @@
458
-+<?xml version="1.0" encoding="UTF-8"?>
459
-+<project version="4">
460
-+  <component name="ChangeListManager">
461
-+    <list default="true" id="76c7d3c7-31f8-4430-8717-7c15514d1ce9" name="Default" comment="" />
462
-+    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
463
-+    <option name="TRACKING_ENABLED" value="true" />
464
-+    <option name="SHOW_DIALOG" value="false" />
465
-+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
466
-+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
467
-+    <option name="LAST_RESOLUTION" value="IGNORE" />
468
-+  </component>
469
-+  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
470
-+  <component name="GradleLocalSettings">
471
-+    <option name="externalProjectsViewState">
472
-+      <projects_view />
473
-+    </option>
474
-+  </component>
475
-+  <component name="ProjectFrameBounds">
476
-+    <option name="x" value="1680" />
477
-+    <option name="y" value="-235" />
478
-+    <option name="width" value="2560" />
479
-+    <option name="height" value="1417" />
480
-+  </component>
481
-+  <component name="ProjectView">
482
-+    <navigator currentView="ProjectPane" proportions="" version="1">
483
-+      <flattenPackages />
484
-+      <showMembers />
485
-+      <showModules />
486
-+      <showLibraryContents />
487
-+      <hideEmptyPackages />
488
-+      <abbreviatePackageNames />
489
-+      <autoscrollToSource />
490
-+      <autoscrollFromSource />
491
-+      <sortByType />
492
-+      <manualOrder />
493
-+      <foldersAlwaysOnTop value="true" />
494
-+    </navigator>
495
-+    <panes>
496
-+      <pane id="Scope" />
497
-+      <pane id="Scratches" />
498
-+      <pane id="PackagesPane" />
499
-+      <pane id="ProjectPane">
500
-+        <subPane>
501
-+          <PATH>
502
-+            <PATH_ELEMENT>
503
-+              <option name="myItemId" value="kubernetes" />
504
-+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
505
-+            </PATH_ELEMENT>
506
-+            <PATH_ELEMENT>
507
-+              <option name="myItemId" value="kubernetes" />
508
-+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
509
-+            </PATH_ELEMENT>
510
-+          </PATH>
511
-+        </subPane>
512
-+      </pane>
513
-+    </panes>
514
-+  </component>
515
-+  <component name="PropertiesComponent">
516
-+    <property name="settings.editor.selected.configurable" value="com.goide.configuration.GoLibrariesConfigurableProvider$1" />
517
-+    <property name="configurable.Global.libraries.is.expanded" value="true" />
518
-+    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
519
-+  </component>
520
-+  <component name="RunDashboard">
521
-+    <option name="ruleStates">
522
-+      <list>
523
-+        <RuleState>
524
-+          <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
525
-+        </RuleState>
526
-+        <RuleState>
527
-+          <option name="name" value="StatusDashboardGroupingRule" />
528
-+        </RuleState>
529
-+      </list>
530
-+    </option>
531
-+  </component>
532
-+  <component name="RunManager">
533
-+    <configuration default="true" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" factoryName="Plugin">
534
-+      <module name="" />
535
-+      <option name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />
536
-+      <option name="PROGRAM_PARAMETERS" />
537
-+      <predefined_log_file id="idea.log" enabled="true" />
538
-+      <method />
539
-+    </configuration>
540
-+    <configuration default="true" type="Applet" factoryName="Applet">
541
-+      <option name="HTML_USED" value="false" />
542
-+      <option name="WIDTH" value="400" />
543
-+      <option name="HEIGHT" value="300" />
544
-+      <option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
545
-+      <module />
546
-+      <method />
547
-+    </configuration>
548
-+    <configuration default="true" type="Application" factoryName="Application">
549
-+      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
550
-+      <option name="MAIN_CLASS_NAME" />
551
-+      <option name="VM_PARAMETERS" />
552
-+      <option name="PROGRAM_PARAMETERS" />
553
-+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
554
-+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
555
-+      <option name="ALTERNATIVE_JRE_PATH" />
556
-+      <option name="ENABLE_SWING_INSPECTOR" value="false" />
557
-+      <option name="ENV_VARIABLES" />
558
-+      <option name="PASS_PARENT_ENVS" value="true" />
559
-+      <module name="" />
560
-+      <envs />
561
-+      <method />
562
-+    </configuration>
563
-+    <configuration default="true" type="JUnit" factoryName="JUnit">
564
-+      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
565
-+      <module name="" />
566
-+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
567
-+      <option name="ALTERNATIVE_JRE_PATH" />
568
-+      <option name="PACKAGE_NAME" />
569
-+      <option name="MAIN_CLASS_NAME" />
570
-+      <option name="METHOD_NAME" />
571
-+      <option name="TEST_OBJECT" value="class" />
572
-+      <option name="VM_PARAMETERS" value="-ea" />
573
-+      <option name="PARAMETERS" />
574
-+      <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
575
-+      <option name="ENV_VARIABLES" />
576
-+      <option name="PASS_PARENT_ENVS" value="true" />
577
-+      <option name="TEST_SEARCH_SCOPE">
578
-+        <value defaultName="singleModule" />
579
-+      </option>
580
-+      <envs />
581
-+      <patterns />
582
-+      <method />
583
-+    </configuration>
584
-+    <configuration default="true" type="Remote" factoryName="Remote">
585
-+      <option name="USE_SOCKET_TRANSPORT" value="true" />
586
-+      <option name="SERVER_MODE" value="false" />
587
-+      <option name="SHMEM_ADDRESS" value="javadebug" />
588
-+      <option name="HOST" value="localhost" />
589
-+      <option name="PORT" value="5005" />
590
-+      <method />
591
-+    </configuration>
592
-+    <configuration default="true" type="TestNG" factoryName="TestNG">
593
-+      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
594
-+      <module name="" />
595
-+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
596
-+      <option name="ALTERNATIVE_JRE_PATH" />
597
-+      <option name="SUITE_NAME" />
598
-+      <option name="PACKAGE_NAME" />
599
-+      <option name="MAIN_CLASS_NAME" />
600
-+      <option name="METHOD_NAME" />
601
-+      <option name="GROUP_NAME" />
602
-+      <option name="TEST_OBJECT" value="CLASS" />
603
-+      <option name="VM_PARAMETERS" value="-ea" />
604
-+      <option name="PARAMETERS" />
605
-+      <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
606
-+      <option name="OUTPUT_DIRECTORY" />
607
-+      <option name="ANNOTATION_TYPE" />
608
-+      <option name="ENV_VARIABLES" />
609
-+      <option name="PASS_PARENT_ENVS" value="true" />
610
-+      <option name="TEST_SEARCH_SCOPE">
611
-+        <value defaultName="singleModule" />
612
-+      </option>
613
-+      <option name="USE_DEFAULT_REPORTERS" value="false" />
614
-+      <option name="PROPERTIES_FILE" />
615
-+      <envs />
616
-+      <properties />
617
-+      <listeners />
618
-+      <method />
619
-+    </configuration>
620
-+  </component>
621
-+  <component name="ShelveChangesManager" show_recycled="false">
622
-+    <option name="remove_strategy" value="false" />
623
-+  </component>
624
-+  <component name="TaskManager">
625
-+    <task active="true" id="Default" summary="Default task">
626
-+      <changelist id="76c7d3c7-31f8-4430-8717-7c15514d1ce9" name="Default" comment="" />
627
-+      <created>1510772775522</created>
628
-+      <option name="number" value="Default" />
629
-+      <option name="presentableId" value="Default" />
630
-+      <updated>1510772775522</updated>
631
-+    </task>
632
-+    <servers />
633
-+  </component>
634
-+  <component name="ToolWindowManager">
635
-+    <frame x="1680" y="-235" width="2560" height="1417" extended-state="6" />
636
-+    <layout>
637
-+      <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
638
-+      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
639
-+      <window_info id="Nl-Palette" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
640
-+      <window_info id="Palette&#9;" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
641
-+      <window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
642
-+      <window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
643
-+      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
644
-+      <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
645
-+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
646
-+      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
647
-+      <window_info id="Properties" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
648
-+      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
649
-+      <window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
650
-+      <window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
651
-+      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25178713" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
652
-+      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
653
-+      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
654
-+      <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
655
-+      <window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
656
-+      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
657
-+      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
658
-+      <window_info id="Data View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
659
-+      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
660
-+      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
661
-+      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
662
-+      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
663
-+      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
664
-+      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
665
-+    </layout>
666
-+  </component>
667
-+  <component name="VcsContentAnnotationSettings">
668
-+    <option name="myLimit" value="2678400000" />
669
-+  </component>
670
-+  <component name="XDebuggerManager">
671
-+    <breakpoint-manager />
672
-+    <watches-manager />
673
-+  </component>
674
-+</project>
675
-\ No newline at end of file
676
-diff -uNr --no-dereference kubernetes-original/pkg/apis/core/types.go kubernetes-modified/src/k8s.io/kubernetes/pkg/apis/core/types.go
677
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/apis/core/types.go	2018-04-30 21:11:51.000000000 +0000
678
-@@ -316,6 +316,8 @@
430
+diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go
431
+index b6b570b..1d9db5e 100644
432
+--- a/pkg/apis/core/types.go
433
+@@ -316,6 +316,8 @@ type VolumeSource struct {
679 434
  	// StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod
680 435
  	// +optional
681 436
  	StorageOS *StorageOSVolumeSource
... ...
@@ -688,7 +545,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/core/types.go kubernetes
688 688
  }
689 689
  
690 690
  // Similar to VolumeSource but meant for the administrator who creates PVs.
691
-@@ -394,6 +396,8 @@
691
+@@ -394,6 +396,8 @@ type PersistentVolumeSource struct {
692 692
  	// CSI (Container Storage Interface) represents storage that handled by an external CSI driver
693 693
  	// +optional
694 694
  	CSI *CSIPersistentVolumeSource
... ...
@@ -697,7 +554,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/core/types.go kubernetes
697 697
  }
698 698
  
699 699
  type PersistentVolumeClaimVolumeSource struct {
700
-@@ -1471,6 +1475,16 @@
700
+@@ -1471,6 +1475,16 @@ type StorageOSPersistentVolumeSource struct {
701 701
  	SecretRef *ObjectReference
702 702
  }
703 703
  
... ...
@@ -714,10 +571,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/core/types.go kubernetes
714 714
  // Adapts a ConfigMap into a volume.
715 715
  //
716 716
  // The contents of the target ConfigMap's Data field will be presented in a
717
-diff -uNr --no-dereference kubernetes-original/pkg/apis/core/validation/validation.go kubernetes-modified/src/k8s.io/kubernetes/pkg/apis/core/validation/validation.go
718
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/apis/core/validation/validation.go	2018-04-30 21:11:51.000000000 +0000
719
-@@ -681,6 +681,14 @@
717
+diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go
718
+index f6ab55f..2fa447d 100644
719
+--- a/pkg/apis/core/validation/validation.go
720
+@@ -681,6 +681,14 @@ func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volNam
720 721
  			allErrs = append(allErrs, validateScaleIOVolumeSource(source.ScaleIO, fldPath.Child("scaleIO"))...)
721 722
  		}
722 723
  	}
... ...
@@ -732,7 +590,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/core/validation/validati
732 732
  
733 733
  	if numVolumes == 0 {
734 734
  		allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
735
-@@ -1440,6 +1448,14 @@
735
+@@ -1440,6 +1448,14 @@ func validateCSIPersistentVolumeSource(csi *core.CSIPersistentVolumeSource, fldP
736 736
  	return allErrs
737 737
  }
738 738
  
... ...
@@ -747,7 +605,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/core/validation/validati
747 747
  // ValidatePersistentVolumeName checks that a name is appropriate for a
748 748
  // PersistentVolumeName object.
749 749
  var ValidatePersistentVolumeName = NameIsDNSSubdomain
750
-@@ -1674,6 +1690,15 @@
750
+@@ -1674,6 +1690,15 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
751 751
  		}
752 752
  	}
753 753
  
... ...
@@ -763,10 +621,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/core/validation/validati
763 763
  	if numVolumes == 0 {
764 764
  		allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
765 765
  	}
766
-diff -uNr --no-dereference kubernetes-original/pkg/apis/extensions/types.go kubernetes-modified/src/k8s.io/kubernetes/pkg/apis/extensions/types.go
767
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/apis/extensions/types.go	2018-04-30 21:11:51.000000000 +0000
768
-@@ -925,6 +925,7 @@
766
+diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go
767
+index e369728..a5406ab 100644
768
+--- a/pkg/apis/extensions/types.go
769
+@@ -925,6 +925,7 @@ var (
769 770
  	PortworxVolume        FSType = "portworxVolume"
770 771
  	ScaleIO               FSType = "scaleIO"
771 772
  	CSI                   FSType = "csi"
... ...
@@ -774,10 +633,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/apis/extensions/types.go kube
774 774
  	All                   FSType = "*"
775 775
  )
776 776
  
777
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/BUILD kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/BUILD
778
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/BUILD	2018-04-30 21:11:51.000000000 +0000
779
-@@ -12,6 +12,7 @@
777
+diff --git a/pkg/cloudprovider/providers/BUILD b/pkg/cloudprovider/providers/BUILD
778
+index aeccfa1..4313576 100644
779
+--- a/pkg/cloudprovider/providers/BUILD
780
+@@ -12,6 +12,7 @@ go_library(
780 781
      deps = [
781 782
          "//pkg/cloudprovider/providers/aws:go_default_library",
782 783
          "//pkg/cloudprovider/providers/azure:go_default_library",
... ...
@@ -785,7 +645,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/BUILD
785 785
          "//pkg/cloudprovider/providers/cloudstack:go_default_library",
786 786
          "//pkg/cloudprovider/providers/gce:go_default_library",
787 787
          "//pkg/cloudprovider/providers/openstack:go_default_library",
788
-@@ -34,6 +35,7 @@
788
+@@ -34,6 +35,7 @@ filegroup(
789 789
          ":package-srcs",
790 790
          "//pkg/cloudprovider/providers/aws:all-srcs",
791 791
          "//pkg/cloudprovider/providers/azure:all-srcs",
... ...
@@ -793,9 +653,70 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/BUILD
793 793
          "//pkg/cloudprovider/providers/cloudstack:all-srcs",
794 794
          "//pkg/cloudprovider/providers/fake:all-srcs",
795 795
          "//pkg/cloudprovider/providers/gce:all-srcs",
796
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/apitypes.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/apitypes.go
797
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/apitypes.go	2018-04-30 21:11:51.000000000 +0000
796
+diff --git a/pkg/cloudprovider/providers/cascade/BUILD b/pkg/cloudprovider/providers/cascade/BUILD
797
+new file mode 100644
798
+index 0000000..1ff2ad1
799
+--- /dev/null
800
+@@ -0,0 +1,44 @@
801
++package(default_visibility = ["//visibility:public"])
802
++
803
++load(
804
++    "@io_bazel_rules_go//go:def.bzl",
805
++    "go_library",
806
++)
807
++
808
++go_library(
809
++    name = "go_default_library",
810
++    srcs = [
811
++        "apitypes.go",
812
++        "auth.go",
813
++        "cascade.go",
814
++        "cascade_disks.go",
815
++        "cascade_instances.go",
816
++        "cascade_loadbalancer.go",
817
++        "client.go",
818
++        "oidcclient.go",
819
++        "restclient.go",
820
++        "utils.go"
821
++        ],
822
++    deps = [
823
++        "//pkg/api/v1/helper:go_default_library",
824
++        "//pkg/cloudprovider:go_default_library",
825
++        "//pkg/controller:go_default_library",
826
++        "//vendor/github.com/golang/glog:go_default_library",
827
++        "//vendor/gopkg.in/gcfg.v1:go_default_library",
828
++        "//vendor/k8s.io/api/core/v1:go_default_library",
829
++        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
830
++    ],
831
++)
832
++
833
++filegroup(
834
++    name = "package-srcs",
835
++    srcs = glob(["**"]),
836
++    tags = ["automanaged"],
837
++    visibility = ["//visibility:private"],
838
++)
839
++
840
++filegroup(
841
++    name = "all-srcs",
842
++    srcs = [":package-srcs"],
843
++    tags = ["automanaged"],
844
++)
845
+diff --git a/pkg/cloudprovider/providers/cascade/OWNERS b/pkg/cloudprovider/providers/cascade/OWNERS
846
+new file mode 100644
847
+index 0000000..70efc9d
848
+--- /dev/null
849
+@@ -0,0 +1,3 @@
850
++maintainers:
851
++- ashokc
852
++- ysheng
853
+diff --git a/pkg/cloudprovider/providers/cascade/apitypes.go b/pkg/cloudprovider/providers/cascade/apitypes.go
854
+new file mode 100644
855
+index 0000000..4a94068
856
+--- /dev/null
798 857
 @@ -0,0 +1,227 @@
799 858
 +package cascade
800 859
 +
... ...
@@ -1024,9 +945,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
1024 1024
 +type LoadBalancerVMUpdate struct {
1025 1025
 +	VMIds []*LoadBalancerVM `json:"vmIds"`
1026 1026
 +}
1027
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/auth.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/auth.go
1028
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/auth.go	2018-04-30 21:11:51.000000000 +0000
1027
+diff --git a/pkg/cloudprovider/providers/cascade/auth.go b/pkg/cloudprovider/providers/cascade/auth.go
1028
+new file mode 100644
1029
+index 0000000..fc92377
1030
+--- /dev/null
1029 1031
 @@ -0,0 +1,145 @@
1030 1032
 +package cascade
1031 1033
 +
... ...
@@ -1174,57 +1097,234 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
1174 1174
 +	return pwd, nil
1175 1175
 +}
1176 1176
 \ No newline at end of file
1177
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/BUILD kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/BUILD
1178
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/BUILD	2018-04-30 21:11:51.000000000 +0000
1179
-@@ -0,0 +1,44 @@
1180
-+package(default_visibility = ["//visibility:public"])
1177
+diff --git a/pkg/cloudprovider/providers/cascade/cascade.go b/pkg/cloudprovider/providers/cascade/cascade.go
1178
+new file mode 100644
1179
+index 0000000..e5e2baf
1180
+--- /dev/null
1181
+@@ -0,0 +1,216 @@
1182
++// The use of Cascade cloud provider requires the kubelet, kube-apiserver, and kube-controller-manager to be started
1183
++// with config flag: '--cloud-provider=cascade --cloud-config=[path_to_config_file]'.
1184
++package cascade
1181 1185
 +
1182
-+load(
1183
-+    "@io_bazel_rules_go//go:def.bzl",
1184
-+    "go_library",
1186
++import (
1187
++	"errors"
1188
++	"fmt"
1189
++	"io"
1190
++	"os"
1191
++	"github.com/golang/glog"
1192
++	"gopkg.in/gcfg.v1"
1193
++	k8stypes "k8s.io/apimachinery/pkg/types"
1194
++	"k8s.io/kubernetes/pkg/cloudprovider"
1195
++	"k8s.io/kubernetes/pkg/controller"
1196
++	"strings"
1185 1197
 +)
1186 1198
 +
1187
-+go_library(
1188
-+    name = "go_default_library",
1189
-+    srcs = [
1190
-+        "apitypes.go",
1191
-+        "auth.go",
1192
-+        "cascade.go",
1193
-+        "cascade_disks.go",
1194
-+        "cascade_instances.go",
1195
-+        "cascade_loadbalancer.go",
1196
-+        "client.go",
1197
-+        "oidcclient.go",
1198
-+        "restclient.go",
1199
-+        "utils.go"
1200
-+        ],
1201
-+    deps = [
1202
-+        "//pkg/api/v1/helper:go_default_library",
1203
-+        "//pkg/cloudprovider:go_default_library",
1204
-+        "//pkg/controller:go_default_library",
1205
-+        "//vendor/github.com/golang/glog:go_default_library",
1206
-+        "//vendor/gopkg.in/gcfg.v1:go_default_library",
1207
-+        "//vendor/k8s.io/api/core/v1:go_default_library",
1208
-+        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
1209
-+    ],
1199
++const (
1200
++	ProviderName = "cascade"
1201
++	DiskSpecKind = "persistent-disk"
1202
++	MasterPrefix = "master"
1210 1203
 +)
1211 1204
 +
1212
-+filegroup(
1213
-+    name = "package-srcs",
1214
-+    srcs = glob(["**"]),
1215
-+    tags = ["automanaged"],
1216
-+    visibility = ["//visibility:private"],
1217
-+)
1205
++// CascadeCloud is an implementation of the cloud provider interface for Cascade Controller.
1206
++type CascadeCloud struct {
1207
++	cfg *CascadeConfig
1208
++	// Authentication client to get token for Cascade API calls
1209
++	authClient *AuthClient
1210
++	// API Client to make Cascade API calls
1211
++	apiClient *Client
1212
++	// local $HOSTNAME
1213
++	localHostname string
1214
++	// hostname from K8S, could be overridden
1215
++	localK8sHostname string
1216
++}
1218 1217
 +
1219
-+filegroup(
1220
-+    name = "all-srcs",
1221
-+    srcs = [":package-srcs"],
1222
-+    tags = ["automanaged"],
1223
-+)
1224
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/cascade_disks.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade_disks.go
1225
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade_disks.go	2018-04-30 21:11:51.000000000 +0000
1218
++// CascadeCloud represents Cascade cloud provider's configuration.
1219
++type CascadeConfig struct {
1220
++	Global struct {
1221
++		// the Cascade Controller endpoint
1222
++		CloudTarget string `gcfg:"target"`
1223
++		// Cascade Controller tenantName name
1224
++		TenantName string `gcfg:"tenantName"`
1225
++		// Cascade Controller cluster ID
1226
++		ClusterID string `gcfg:"clusterID"`
1227
++		// Authentication server endpoint for Cascade Controller
1228
++		AuthEndpoint string `gcfg:"authEndpoint"`
1229
++		// Lightwave domain name for the node
1230
++		DomainName string `gcfg:"domainName"`
1231
++		// DNS name of the node.
1232
++		DNSName string `gcfg:"dnsName"`
1233
++		// Region in which the cluster is in
1234
++		Region string `gcfg:"region"`
1235
++		// Availability zone in which the cluster is in
1236
++		Zone string `gcfg:"zone"`
1237
++	}
1238
++}
1239
++
1240
++// Disks is interface for manipulation with Cascade Controller Persistent Disks.
1241
++type Disks interface {
1242
++	// AttachDisk attaches given disk to given node. Current node
1243
++	// is used when nodeName is empty string.
1244
++	AttachDisk(diskID string, nodeName k8stypes.NodeName) (string, error)
1245
++
1246
++	// DetachDisk detaches given disk to given node. Current node
1247
++	// is used when nodeName is empty string.
1248
++	DetachDisk(diskID string, nodeName k8stypes.NodeName) error
1249
++
1250
++	// DiskIsAttached checks if a disk is attached to the given node.
1251
++	DiskIsAttached(diskID string, nodeName k8stypes.NodeName) (bool, error)
1252
++
1253
++	// DisksAreAttached is a batch function to check if a list of disks are attached
1254
++	// to the node with the specified NodeName.
1255
++	DisksAreAttached(diskID []string, nodeName k8stypes.NodeName) (map[string]bool, error)
1256
++
1257
++	// CreateDisk creates a new PD with given properties.
1258
++	CreateDisk(volumeOptions *VolumeOptions) (diskID string, err error)
1259
++
1260
++	// DeleteDisk deletes PD.
1261
++	DeleteDisk(diskID string) error
1262
++
1263
++	// Get labels to apply to volume on creation.
1264
++	GetVolumeLabels(diskID string) (map[string]string, error)
1265
++}
1266
++
1267
++// VolumeOptions specifies capacity, tags, name and flavorID for a volume.
1268
++type VolumeOptions struct {
1269
++	CapacityGB int
1270
++	Tags       map[string]string
1271
++	Name       string
1272
++	Flavor     string
1273
++}
1274
++
1275
++func readConfig(config io.Reader) (*CascadeConfig, error) {
1276
++	if config == nil {
1277
++		err := fmt.Errorf("Cascade Cloud Provider: config file is missing. Please restart with " +
1278
++			"--cloud-provider=cascade --cloud-config=[path_to_config_file]")
1279
++		return nil, err
1280
++	}
1281
++
1282
++	var cfg CascadeConfig
1283
++	err := gcfg.ReadInto(&cfg, config)
1284
++	return &cfg, err
1285
++}
1286
++
1287
++func init() {
1288
++	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) {
1289
++		cfg, err := readConfig(config)
1290
++		if err != nil {
1291
++			glog.Errorf("Cascade Cloud Provider: failed to read in cloud provider config file. Error[%v]", err)
1292
++			return nil, err
1293
++		}
1294
++		return newCascadeCloud(cfg)
1295
++	})
1296
++}
1297
++
1298
++func newCascadeCloud(cfg *CascadeConfig) (*CascadeCloud, error) {
1299
++	if len(cfg.Global.CloudTarget) == 0 {
1300
++		return nil, fmt.Errorf("Cascade Controller endpoint was not specified.")
1301
++	}
1302
++
1303
++	// Get local hostname
1304
++	hostname, err := os.Hostname()
1305
++	if err != nil {
1306
++		glog.Errorf("Cascade Cloud Provider: get hostname failed. Error[%v]", err)
1307
++		return nil, err
1308
++	}
1309
++
1310
++	cc := CascadeCloud{
1311
++		cfg:              cfg,
1312
++		localHostname:    hostname,
1313
++		localK8sHostname: "",
1314
++	}
1315
++
1316
++	// Instantiate the auth and API clients only on the master nodes. Kubelets running on the workers don't need them as
1317
++	// they are used primarily for making API calls to Cascade.
1318
++	if strings.HasPrefix(hostname, MasterPrefix) {
1319
++		if cc.authClient, err = NewAuthClient(cfg); err != nil {
1320
++			return nil, err
1321
++		}
1322
++
1323
++		if cc.apiClient, err = NewClient(cfg, cc.authClient); err != nil {
1324
++			return nil, err
1325
++		}
1326
++	}
1327
++
1328
++	return &cc, nil
1329
++}
1330
++
1331
++// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
1332
++func (cc *CascadeCloud) Initialize(clientBuilder controller.ControllerClientBuilder) {}
1333
++
1334
++// Instances returns an implementation of Instances for Cascade Controller.
1335
++func (cc *CascadeCloud) Instances() (cloudprovider.Instances, bool) {
1336
++	return cc, true
1337
++}
1338
++
1339
++// List is an implementation of Instances.List.
1340
++func (cc *CascadeCloud) List(filter string) ([]k8stypes.NodeName, error) {
1341
++	return nil, errors.New("unimplemented")
1342
++}
1343
++
1344
++func (cc *CascadeCloud) Clusters() (cloudprovider.Clusters, bool) {
1345
++	return nil, true
1346
++}
1347
++
1348
++// ProviderName returns the cloud provider ID.
1349
++func (cc *CascadeCloud) ProviderName() string {
1350
++	return ProviderName
1351
++}
1352
++
1353
++// LoadBalancer returns an implementation of LoadBalancer for Cascade Controller.
1354
++func (cc *CascadeCloud) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
1355
++	return cc, true
1356
++}
1357
++
1358
++// Zones returns an implementation of Zones for Cascade Controller.
1359
++func (cc *CascadeCloud) Zones() (cloudprovider.Zones, bool) {
1360
++	return cc, true
1361
++}
1362
++
1363
++func (cc *CascadeCloud) GetZone() (cloudprovider.Zone, error) {
1364
++	return cloudprovider.Zone{
1365
++		Region: cc.cfg.Global.Region,
1366
++		FailureDomain: cc.cfg.Global.Zone,
1367
++	}, nil
1368
++}
1369
++
1370
++// GetZoneByProviderID implements Zones.GetZoneByProviderID
1371
++// This is particularly useful in external cloud providers where the kubelet
1372
++// does not initialize node data.
1373
++func (cc *CascadeCloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
1374
++	return cloudprovider.Zone{}, errors.New("unimplemented")
1375
++}
1376
++
1377
++// GetZoneByNodeName implements Zones.GetZoneByNodeName
1378
++// This is particularly useful in external cloud providers where the kubelet
1379
++// does not initialize node data.
1380
++func (cc *CascadeCloud) GetZoneByNodeName(nodeName k8stypes.NodeName) (cloudprovider.Zone, error) {
1381
++	return cloudprovider.Zone{}, errors.New("unimeplemented")
1382
++}
1383
++
1384
++// Routes returns a false since the interface is not supported for Cascade controller.
1385
++func (cc *CascadeCloud) Routes() (cloudprovider.Routes, bool) {
1386
++	return nil, false
1387
++}
1388
++
1389
++// ScrubDNS filters DNS settings for pods.
1390
++func (cc *CascadeCloud) ScrubDNS(nameservers, searches []string) (nsOut, srchOut []string) {
1391
++	return nameservers, searches
1392
++}
1393
++
1394
++// HasClusterID returns true if the cluster has a clusterID
1395
++func (cc *CascadeCloud) HasClusterID() bool {
1396
++	return true
1397
++}
1398
+\ No newline at end of file
1399
+diff --git a/pkg/cloudprovider/providers/cascade/cascade_disks.go b/pkg/cloudprovider/providers/cascade/cascade_disks.go
1400
+new file mode 100644
1401
+index 0000000..320e123
1402
+--- /dev/null
1226 1403
 @@ -0,0 +1,225 @@
1227 1404
 +package cascade
1228 1405
 +
... ...
@@ -1451,230 +1551,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
1451 1451
 +
1452 1452
 +	return labels, nil
1453 1453
 +}
1454
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/cascade.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade.go
1455
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade.go	2018-04-30 21:11:51.000000000 +0000
1456
-@@ -0,0 +1,216 @@
1457
-+// The use of Cascade cloud provider requires the kubelet, kube-apiserver, and kube-controller-manager to be started
1458
-+// with config flag: '--cloud-provider=cascade --cloud-config=[path_to_config_file]'.
1459
-+package cascade
1460
-+
1461
-+import (
1462
-+	"errors"
1463
-+	"fmt"
1464
-+	"io"
1465
-+	"os"
1466
-+	"github.com/golang/glog"
1467
-+	"gopkg.in/gcfg.v1"
1468
-+	k8stypes "k8s.io/apimachinery/pkg/types"
1469
-+	"k8s.io/kubernetes/pkg/cloudprovider"
1470
-+	"k8s.io/kubernetes/pkg/controller"
1471
-+	"strings"
1472
-+)
1473
-+
1474
-+const (
1475
-+	ProviderName = "cascade"
1476
-+	DiskSpecKind = "persistent-disk"
1477
-+	MasterPrefix = "master"
1478
-+)
1479
-+
1480
-+// CascadeCloud is an implementation of the cloud provider interface for Cascade Controller.
1481
-+type CascadeCloud struct {
1482
-+	cfg *CascadeConfig
1483
-+	// Authentication client to get token for Cascade API calls
1484
-+	authClient *AuthClient
1485
-+	// API Client to make Cascade API calls
1486
-+	apiClient *Client
1487
-+	// local $HOSTNAME
1488
-+	localHostname string
1489
-+	// hostname from K8S, could be overridden
1490
-+	localK8sHostname string
1491
-+}
1492
-+
1493
-+// CascadeCloud represents Cascade cloud provider's configuration.
1494
-+type CascadeConfig struct {
1495
-+	Global struct {
1496
-+		// the Cascade Controller endpoint
1497
-+		CloudTarget string `gcfg:"target"`
1498
-+		// Cascade Controller tenantName name
1499
-+		TenantName string `gcfg:"tenantName"`
1500
-+		// Cascade Controller cluster ID
1501
-+		ClusterID string `gcfg:"clusterID"`
1502
-+		// Authentication server endpoint for Cascade Controller
1503
-+		AuthEndpoint string `gcfg:"authEndpoint"`
1504
-+		// Lightwave domain name for the node
1505
-+		DomainName string `gcfg:"domainName"`
1506
-+		// DNS name of the node.
1507
-+		DNSName string `gcfg:"dnsName"`
1508
-+		// Region in which the cluster is in
1509
-+		Region string `gcfg:"region"`
1510
-+		// Availability zone in which the cluster is in
1511
-+		Zone string `gcfg:"zone"`
1512
-+	}
1513
-+}
1514
-+
1515
-+// Disks is interface for manipulation with Cascade Controller Persistent Disks.
1516
-+type Disks interface {
1517
-+	// AttachDisk attaches given disk to given node. Current node
1518
-+	// is used when nodeName is empty string.
1519
-+	AttachDisk(diskID string, nodeName k8stypes.NodeName) (string, error)
1520
-+
1521
-+	// DetachDisk detaches given disk to given node. Current node
1522
-+	// is used when nodeName is empty string.
1523
-+	DetachDisk(diskID string, nodeName k8stypes.NodeName) error
1524
-+
1525
-+	// DiskIsAttached checks if a disk is attached to the given node.
1526
-+	DiskIsAttached(diskID string, nodeName k8stypes.NodeName) (bool, error)
1527
-+
1528
-+	// DisksAreAttached is a batch function to check if a list of disks are attached
1529
-+	// to the node with the specified NodeName.
1530
-+	DisksAreAttached(diskID []string, nodeName k8stypes.NodeName) (map[string]bool, error)
1531
-+
1532
-+	// CreateDisk creates a new PD with given properties.
1533
-+	CreateDisk(volumeOptions *VolumeOptions) (diskID string, err error)
1534
-+
1535
-+	// DeleteDisk deletes PD.
1536
-+	DeleteDisk(diskID string) error
1537
-+
1538
-+	// Get labels to apply to volume on creation.
1539
-+	GetVolumeLabels(diskID string) (map[string]string, error)
1540
-+}
1541
-+
1542
-+// VolumeOptions specifies capacity, tags, name and flavorID for a volume.
1543
-+type VolumeOptions struct {
1544
-+	CapacityGB int
1545
-+	Tags       map[string]string
1546
-+	Name       string
1547
-+	Flavor     string
1548
-+}
1549
-+
1550
-+func readConfig(config io.Reader) (*CascadeConfig, error) {
1551
-+	if config == nil {
1552
-+		err := fmt.Errorf("Cascade Cloud Provider: config file is missing. Please restart with " +
1553
-+			"--cloud-provider=cascade --cloud-config=[path_to_config_file]")
1554
-+		return nil, err
1555
-+	}
1556
-+
1557
-+	var cfg CascadeConfig
1558
-+	err := gcfg.ReadInto(&cfg, config)
1559
-+	return &cfg, err
1560
-+}
1561
-+
1562
-+func init() {
1563
-+	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) {
1564
-+		cfg, err := readConfig(config)
1565
-+		if err != nil {
1566
-+			glog.Errorf("Cascade Cloud Provider: failed to read in cloud provider config file. Error[%v]", err)
1567
-+			return nil, err
1568
-+		}
1569
-+		return newCascadeCloud(cfg)
1570
-+	})
1571
-+}
1572
-+
1573
-+func newCascadeCloud(cfg *CascadeConfig) (*CascadeCloud, error) {
1574
-+	if len(cfg.Global.CloudTarget) == 0 {
1575
-+		return nil, fmt.Errorf("Cascade Controller endpoint was not specified.")
1576
-+	}
1577
-+
1578
-+	// Get local hostname
1579
-+	hostname, err := os.Hostname()
1580
-+	if err != nil {
1581
-+		glog.Errorf("Cascade Cloud Provider: get hostname failed. Error[%v]", err)
1582
-+		return nil, err
1583
-+	}
1584
-+
1585
-+	cc := CascadeCloud{
1586
-+		cfg:              cfg,
1587
-+		localHostname:    hostname,
1588
-+		localK8sHostname: "",
1589
-+	}
1590
-+
1591
-+	// Instantiate the auth and API clients only on the master nodes. Kubelets running on the workers don't need them as
1592
-+	// they are used primarily for making API calls to Cascade.
1593
-+	if strings.HasPrefix(hostname, MasterPrefix) {
1594
-+		if cc.authClient, err = NewAuthClient(cfg); err != nil {
1595
-+			return nil, err
1596
-+		}
1597
-+
1598
-+		if cc.apiClient, err = NewClient(cfg, cc.authClient); err != nil {
1599
-+			return nil, err
1600
-+		}
1601
-+	}
1602
-+
1603
-+	return &cc, nil
1604
-+}
1605
-+
1606
-+// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
1607
-+func (cc *CascadeCloud) Initialize(clientBuilder controller.ControllerClientBuilder) {}
1608
-+
1609
-+// Instances returns an implementation of Instances for Cascade Controller.
1610
-+func (cc *CascadeCloud) Instances() (cloudprovider.Instances, bool) {
1611
-+	return cc, true
1612
-+}
1613
-+
1614
-+// List is an implementation of Instances.List.
1615
-+func (cc *CascadeCloud) List(filter string) ([]k8stypes.NodeName, error) {
1616
-+	return nil, errors.New("unimplemented")
1617
-+}
1618
-+
1619
-+func (cc *CascadeCloud) Clusters() (cloudprovider.Clusters, bool) {
1620
-+	return nil, true
1621
-+}
1622
-+
1623
-+// ProviderName returns the cloud provider ID.
1624
-+func (cc *CascadeCloud) ProviderName() string {
1625
-+	return ProviderName
1626
-+}
1627
-+
1628
-+// LoadBalancer returns an implementation of LoadBalancer for Cascade Controller.
1629
-+func (cc *CascadeCloud) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
1630
-+	return cc, true
1631
-+}
1632
-+
1633
-+// Zones returns an implementation of Zones for Cascade Controller.
1634
-+func (cc *CascadeCloud) Zones() (cloudprovider.Zones, bool) {
1635
-+	return cc, true
1636
-+}
1637
-+
1638
-+func (cc *CascadeCloud) GetZone() (cloudprovider.Zone, error) {
1639
-+	return cloudprovider.Zone{
1640
-+		Region: cc.cfg.Global.Region,
1641
-+		FailureDomain: cc.cfg.Global.Zone,
1642
-+	}, nil
1643
-+}
1644
-+
1645
-+// GetZoneByProviderID implements Zones.GetZoneByProviderID
1646
-+// This is particularly useful in external cloud providers where the kubelet
1647
-+// does not initialize node data.
1648
-+func (cc *CascadeCloud) GetZoneByProviderID(providerID string) (cloudprovider.Zone, error) {
1649
-+	return cloudprovider.Zone{}, errors.New("unimplemented")
1650
-+}
1651
-+
1652
-+// GetZoneByNodeName implements Zones.GetZoneByNodeName
1653
-+// This is particularly useful in external cloud providers where the kubelet
1654
-+// does not initialize node data.
1655
-+func (cc *CascadeCloud) GetZoneByNodeName(nodeName k8stypes.NodeName) (cloudprovider.Zone, error) {
1656
-+	return cloudprovider.Zone{}, errors.New("unimeplemented")
1657
-+}
1658
-+
1659
-+// Routes returns a false since the interface is not supported for Cascade controller.
1660
-+func (cc *CascadeCloud) Routes() (cloudprovider.Routes, bool) {
1661
-+	return nil, false
1662
-+}
1663
-+
1664
-+// ScrubDNS filters DNS settings for pods.
1665
-+func (cc *CascadeCloud) ScrubDNS(nameservers, searches []string) (nsOut, srchOut []string) {
1666
-+	return nameservers, searches
1667
-+}
1668
-+
1669
-+// HasClusterID returns true if the cluster has a clusterID
1670
-+func (cc *CascadeCloud) HasClusterID() bool {
1671
-+	return true
1672
-+}
1673
-\ No newline at end of file
1674
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/cascade_instances.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade_instances.go
1675
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade_instances.go	2018-04-30 21:11:51.000000000 +0000
1454
+diff --git a/pkg/cloudprovider/providers/cascade/cascade_instances.go b/pkg/cloudprovider/providers/cascade/cascade_instances.go
1455
+new file mode 100644
1456
+index 0000000..f270a3d
1457
+--- /dev/null
1676 1458
 @@ -0,0 +1,90 @@
1677 1459
 +package cascade
1678 1460
 +
... ...
@@ -1766,9 +1647,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
1766 1766
 +func (cc *CascadeCloud) InstanceType(nodeName k8stypes.NodeName) (string, error) {
1767 1767
 +	return "", nil
1768 1768
 +}
1769
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go
1770
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go	2018-04-30 21:11:51.000000000 +0000
1769
+diff --git a/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go b/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go
1770
+new file mode 100644
1771
+index 0000000..e28282f
1772
+--- /dev/null
1771 1773
 @@ -0,0 +1,284 @@
1772 1774
 +package cascade
1773 1775
 +
... ...
@@ -2055,9 +1938,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
2055 2055
 +	glog.Infoln(l.getLogMsg(msgTemplate, args))
2056 2056
 +}
2057 2057
 \ No newline at end of file
2058
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/client.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/client.go
2059
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/client.go	2018-04-30 21:11:51.000000000 +0000
2058
+diff --git a/pkg/cloudprovider/providers/cascade/client.go b/pkg/cloudprovider/providers/cascade/client.go
2059
+new file mode 100644
2060
+index 0000000..72049e0
2061
+--- /dev/null
2060 2062
 @@ -0,0 +1,394 @@
2061 2063
 +package cascade
2062 2064
 +
... ...
@@ -2453,9 +2338,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
2453 2453
 +
2454 2454
 +	return errorStep
2455 2455
 +}
2456
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/oidcclient.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/oidcclient.go
2457
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/oidcclient.go	2018-04-30 21:11:51.000000000 +0000
2456
+diff --git a/pkg/cloudprovider/providers/cascade/oidcclient.go b/pkg/cloudprovider/providers/cascade/oidcclient.go
2457
+new file mode 100644
2458
+index 0000000..6a71cc1
2459
+--- /dev/null
2458 2460
 @@ -0,0 +1,297 @@
2459 2461
 +package cascade
2460 2462
 +
... ...
@@ -2754,16 +2641,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
2754 2754
 +
2755 2755
 +	return oidcErr
2756 2756
 +}
2757
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/OWNERS kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/OWNERS
2758
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/OWNERS	2018-04-30 21:11:51.000000000 +0000
2759
-@@ -0,0 +1,3 @@
2760
-+maintainers:
2761
-+- ashokc
2762
-+- ysheng
2763
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/restclient.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/restclient.go
2764
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/restclient.go	2018-04-30 21:11:51.000000000 +0000
2757
+diff --git a/pkg/cloudprovider/providers/cascade/restclient.go b/pkg/cloudprovider/providers/cascade/restclient.go
2758
+new file mode 100644
2759
+index 0000000..71d8d1c
2760
+--- /dev/null
2765 2761
 @@ -0,0 +1,262 @@
2766 2762
 +package cascade
2767 2763
 +
... ...
@@ -3027,18 +2909,22 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
3027 3027
 +	apiError.HttpStatusCode = res.StatusCode
3028 3028
 +	return nil, apiError
3029 3029
 +}
3030
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/tests_owed kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/tests_owed
3031
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/tests_owed	2018-04-30 21:11:51.000000000 +0000
3030
+diff --git a/pkg/cloudprovider/providers/cascade/tests_owed b/pkg/cloudprovider/providers/cascade/tests_owed
3031
+new file mode 100644
3032
+index 0000000..dff5ab1
3033
+--- /dev/null
3032 3034
 @@ -0,0 +1,5 @@
3033 3035
 +
3034 3036
 +Yu Sheng
3035 3037
 +Change-Id: Ifc11818f65a3e018aeea6988d9e2c0719b592920
3036 3038
 +
3037 3039
 +
3038
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/cascade/utils.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/utils.go
3039
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/cascade/utils.go	2018-04-30 21:11:51.000000000 +0000
3040
+diff --git a/pkg/cloudprovider/providers/cascade/utils.go b/pkg/cloudprovider/providers/cascade/utils.go
3041
+new file mode 100644
3042
+index 0000000..4e9e44c
3043
+--- /dev/null
3040 3044
 @@ -0,0 +1,25 @@
3041 3045
 +package cascade
3042 3046
 +
... ...
@@ -3066,10 +2952,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/casca
3066 3066
 +	return &s
3067 3067
 +}
3068 3068
 \ No newline at end of file
3069
-diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/providers.go kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/providers.go
3070
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/cloudprovider/providers/providers.go	2018-04-30 21:11:51.000000000 +0000
3071
-@@ -20,6 +20,7 @@
3069
+diff --git a/pkg/cloudprovider/providers/providers.go b/pkg/cloudprovider/providers/providers.go
3070
+index 7de9ca9..6d8a1d2 100644
3071
+--- a/pkg/cloudprovider/providers/providers.go
3072
+@@ -20,6 +20,7 @@ import (
3072 3073
  	// Cloud providers
3073 3074
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
3074 3075
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
... ...
@@ -3077,10 +2964,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/cloudprovider/providers/provi
3077 3077
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/cloudstack"
3078 3078
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
3079 3079
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/openstack"
3080
-diff -uNr --no-dereference kubernetes-original/pkg/printers/internalversion/describe.go kubernetes-modified/src/k8s.io/kubernetes/pkg/printers/internalversion/describe.go
3081
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/printers/internalversion/describe.go	2018-04-30 21:11:51.000000000 +0000
3082
-@@ -751,6 +751,8 @@
3080
+diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go
3081
+index c33b1c6..11e6c8b 100644
3082
+--- a/pkg/printers/internalversion/describe.go
3083
+@@ -751,6 +751,8 @@ func describeVolumes(volumes []api.Volume, w PrefixWriter, space string) {
3083 3084
  			printFlexVolumeSource(volume.VolumeSource.FlexVolume, w)
3084 3085
  		case volume.VolumeSource.Flocker != nil:
3085 3086
  			printFlockerVolumeSource(volume.VolumeSource.Flocker, w)
... ...
@@ -3089,7 +2977,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/printers/internalversion/desc
3089 3089
  		default:
3090 3090
  			w.Write(LEVEL_1, "<unknown>\n")
3091 3091
  		}
3092
-@@ -1101,6 +1103,13 @@
3092
+@@ -1101,6 +1103,13 @@ func printCSIPersistentVolumeSource(csi *api.CSIPersistentVolumeSource, w Prefix
3093 3093
  		csi.Driver, csi.VolumeHandle, csi.ReadOnly)
3094 3094
  }
3095 3095
  
... ...
@@ -3103,7 +2991,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/printers/internalversion/desc
3103 3103
  type PersistentVolumeDescriber struct {
3104 3104
  	clientset.Interface
3105 3105
  }
3106
-@@ -1189,6 +1198,8 @@
3106
+@@ -1189,6 +1198,8 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
3107 3107
  			printFlockerVolumeSource(pv.Spec.Flocker, w)
3108 3108
  		case pv.Spec.CSI != nil:
3109 3109
  			printCSIPersistentVolumeSource(pv.Spec.CSI, w)
... ...
@@ -3112,10 +3000,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/printers/internalversion/desc
3112 3112
  		default:
3113 3113
  			w.Write(LEVEL_1, "<unknown>\n")
3114 3114
  		}
3115
-diff -uNr --no-dereference kubernetes-original/pkg/security/podsecuritypolicy/util/util.go kubernetes-modified/src/k8s.io/kubernetes/pkg/security/podsecuritypolicy/util/util.go
3116
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/security/podsecuritypolicy/util/util.go	2018-04-30 21:11:51.000000000 +0000
3117
-@@ -68,6 +68,7 @@
3115
+diff --git a/pkg/security/podsecuritypolicy/util/util.go b/pkg/security/podsecuritypolicy/util/util.go
3116
+index d654f88..422fe0d 100644
3117
+--- a/pkg/security/podsecuritypolicy/util/util.go
3118
+@@ -68,6 +68,7 @@ func GetAllFSTypesAsSet() sets.String {
3118 3119
  		string(extensions.PortworxVolume),
3119 3120
  		string(extensions.ScaleIO),
3120 3121
  		string(extensions.CSI),
... ...
@@ -3123,7 +3012,7 @@ diff -uNr --no-dereference kubernetes-original/pkg/security/podsecuritypolicy/ut
3123 3123
  	)
3124 3124
  	return fstypes
3125 3125
  }
3126
-@@ -129,6 +130,8 @@
3126
+@@ -129,6 +130,8 @@ func GetVolumeFSType(v api.Volume) (extensions.FSType, error) {
3127 3127
  		return extensions.PortworxVolume, nil
3128 3128
  	case v.ScaleIO != nil:
3129 3129
  		return extensions.ScaleIO, nil
... ...
@@ -3132,9 +3021,68 @@ diff -uNr --no-dereference kubernetes-original/pkg/security/podsecuritypolicy/ut
3132 3132
  	}
3133 3133
  
3134 3134
  	return "", fmt.Errorf("unknown volume type for volume: %#v", v)
3135
-diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/attacher.go kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/attacher.go
3136
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/attacher.go	2018-04-30 21:11:51.000000000 +0000
3135
+diff --git a/pkg/volume/cascade_disk/BUILD b/pkg/volume/cascade_disk/BUILD
3136
+new file mode 100644
3137
+index 0000000..3386612
3138
+--- /dev/null
3139
+@@ -0,0 +1,43 @@
3140
++package(default_visibility = ["//visibility:public"])
3141
++
3142
++load(
3143
++    "@io_bazel_rules_go//go:def.bzl",
3144
++    "go_library",
3145
++    "go_test",
3146
++)
3147
++
3148
++go_library(
3149
++    name = "go_default_library",
3150
++    srcs = [
3151
++        "attacher.go",
3152
++        "cascade_disk.go",
3153
++        "cascade_util.go",
3154
++    ],
3155
++    deps = [
3156
++        "//pkg/cloudprovider:go_default_library",
3157
++        "//pkg/cloudprovider/providers/cascade:go_default_library",
3158
++        "//pkg/util/mount:go_default_library",
3159
++        "//pkg/util/strings:go_default_library",
3160
++        "//pkg/volume:go_default_library",
3161
++        "//pkg/volume/util:go_default_library",
3162
++        "//pkg/volume/util/volumehelper:go_default_library",
3163
++        "//vendor/github.com/golang/glog:go_default_library",
3164
++        "//vendor/k8s.io/api/core/v1:go_default_library",
3165
++        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
3166
++        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
3167
++        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
3168
++    ],
3169
++)
3170
++
3171
++filegroup(
3172
++    name = "package-srcs",
3173
++    srcs = glob(["**"]),
3174
++    tags = ["automanaged"],
3175
++    visibility = ["//visibility:private"],
3176
++)
3177
++
3178
++filegroup(
3179
++    name = "all-srcs",
3180
++    srcs = [":package-srcs"],
3181
++    tags = ["automanaged"],
3182
++)
3183
+diff --git a/pkg/volume/cascade_disk/OWNERS b/pkg/volume/cascade_disk/OWNERS
3184
+new file mode 100644
3185
+index 0000000..c3a4ed7
3186
+--- /dev/null
3187
+@@ -0,0 +1,2 @@
3188
++maintainers:
3189
++- ashokc
3190
+diff --git a/pkg/volume/cascade_disk/attacher.go b/pkg/volume/cascade_disk/attacher.go
3191
+new file mode 100644
3192
+index 0000000..607fcb5
3193
+--- /dev/null
3137 3194
 @@ -0,0 +1,269 @@
3138 3195
 +package cascade_disk
3139 3196
 +
... ...
@@ -3405,56 +3353,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/attacher.
3405 3405
 +func (detacher *cascadeDiskDetacher) UnmountDevice(deviceMountPath string) error {
3406 3406
 +	return volumeutil.UnmountPath(deviceMountPath, detacher.mounter)
3407 3407
 +}
3408
-diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/BUILD kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/BUILD
3409
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/BUILD	2018-04-30 21:11:51.000000000 +0000
3410
-@@ -0,0 +1,43 @@
3411
-+package(default_visibility = ["//visibility:public"])
3412
-+
3413
-+load(
3414
-+    "@io_bazel_rules_go//go:def.bzl",
3415
-+    "go_library",
3416
-+    "go_test",
3417
-+)
3418
-+
3419
-+go_library(
3420
-+    name = "go_default_library",
3421
-+    srcs = [
3422
-+        "attacher.go",
3423
-+        "cascade_disk.go",
3424
-+        "cascade_util.go",
3425
-+    ],
3426
-+    deps = [
3427
-+        "//pkg/cloudprovider:go_default_library",
3428
-+        "//pkg/cloudprovider/providers/cascade:go_default_library",
3429
-+        "//pkg/util/mount:go_default_library",
3430
-+        "//pkg/util/strings:go_default_library",
3431
-+        "//pkg/volume:go_default_library",
3432
-+        "//pkg/volume/util:go_default_library",
3433
-+        "//pkg/volume/util/volumehelper:go_default_library",
3434
-+        "//vendor/github.com/golang/glog:go_default_library",
3435
-+        "//vendor/k8s.io/api/core/v1:go_default_library",
3436
-+        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
3437
-+        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
3438
-+        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
3439
-+    ],
3440
-+)
3441
-+
3442
-+filegroup(
3443
-+    name = "package-srcs",
3444
-+    srcs = glob(["**"]),
3445
-+    tags = ["automanaged"],
3446
-+    visibility = ["//visibility:private"],
3447
-+)
3448
-+
3449
-+filegroup(
3450
-+    name = "all-srcs",
3451
-+    srcs = [":package-srcs"],
3452
-+    tags = ["automanaged"],
3453
-+)
3454
-diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/cascade_disk.go kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/cascade_disk.go
3455
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/cascade_disk.go	2018-04-30 21:11:51.000000000 +0000
3408
+diff --git a/pkg/volume/cascade_disk/cascade_disk.go b/pkg/volume/cascade_disk/cascade_disk.go
3409
+new file mode 100644
3410
+index 0000000..88945c3
3411
+--- /dev/null
3456 3412
 @@ -0,0 +1,391 @@
3457 3413
 +package cascade_disk
3458 3414
 +
... ...
@@ -3848,9 +3751,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/cascade_d
3848 3848
 +	return nil, false, fmt.Errorf("Spec does not reference a Cascade disk type")
3849 3849
 +}
3850 3850
 \ No newline at end of file
3851
-diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/cascade_util.go kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/cascade_util.go
3852
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/cascade_util.go	2018-04-30 21:11:51.000000000 +0000
3851
+diff --git a/pkg/volume/cascade_disk/cascade_util.go b/pkg/volume/cascade_disk/cascade_util.go
3852
+new file mode 100644
3853
+index 0000000..3dcef3d
3854
+--- /dev/null
3853 3855
 @@ -0,0 +1,107 @@
3854 3856
 +package cascade_disk
3855 3857
 +
... ...
@@ -3959,16 +3864,11 @@ diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/cascade_u
3959 3959
 +	}
3960 3960
 +	return cc, nil
3961 3961
 +}
3962
-diff -uNr --no-dereference kubernetes-original/pkg/volume/cascade_disk/OWNERS kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/OWNERS
3963
-+++ kubernetes-modified/src/k8s.io/kubernetes/pkg/volume/cascade_disk/OWNERS	2018-04-30 21:11:51.000000000 +0000
3964
-@@ -0,0 +1,2 @@
3965
-+maintainers:
3966
-+- ashokc
3967
-diff -uNr --no-dereference kubernetes-original/plugin/pkg/admission/persistentvolume/label/admission.go kubernetes-modified/src/k8s.io/kubernetes/plugin/pkg/admission/persistentvolume/label/admission.go
3968
-+++ kubernetes-modified/src/k8s.io/kubernetes/plugin/pkg/admission/persistentvolume/label/admission.go	2018-04-30 21:11:51.000000000 +0000
3969
-@@ -27,6 +27,7 @@
3962
+diff --git a/plugin/pkg/admission/persistentvolume/label/admission.go b/plugin/pkg/admission/persistentvolume/label/admission.go
3963
+index 86e1921..b9b546f 100644
3964
+--- a/plugin/pkg/admission/persistentvolume/label/admission.go
3965
+@@ -27,6 +27,7 @@ import (
3970 3966
  	api "k8s.io/kubernetes/pkg/apis/core"
3971 3967
  	"k8s.io/kubernetes/pkg/cloudprovider"
3972 3968
  	"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
... ...
@@ -3976,7 +3876,7 @@ diff -uNr --no-dereference kubernetes-original/plugin/pkg/admission/persistentvo
3976 3976
  	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
3977 3977
  	kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
3978 3978
  	kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
3979
-@@ -50,6 +51,7 @@
3979
+@@ -50,6 +51,7 @@ type persistentVolumeLabel struct {
3980 3980
  	ebsVolumes       aws.Volumes
3981 3981
  	cloudConfig      []byte
3982 3982
  	gceCloudProvider *gce.GCECloud
... ...
@@ -3984,7 +3884,7 @@ diff -uNr --no-dereference kubernetes-original/plugin/pkg/admission/persistentvo
3984 3984
  }
3985 3985
  
3986 3986
  var _ admission.MutationInterface = &persistentVolumeLabel{}
3987
-@@ -102,6 +104,13 @@
3987
+@@ -102,6 +104,13 @@ func (l *persistentVolumeLabel) Admit(a admission.Attributes) (err error) {
3988 3988
  		}
3989 3989
  		volumeLabels = labels
3990 3990
  	}
... ...
@@ -3998,7 +3898,7 @@ diff -uNr --no-dereference kubernetes-original/plugin/pkg/admission/persistentvo
3998 3998
  
3999 3999
  	if len(volumeLabels) != 0 {
4000 4000
  		if volume.Labels == nil {
4001
-@@ -214,3 +223,48 @@
4001
+@@ -214,3 +223,48 @@ func (l *persistentVolumeLabel) getGCECloudProvider() (*gce.GCECloud, error) {
4002 4002
  	}
4003 4003
  	return l.gceCloudProvider, nil
4004 4004
  }
... ...
@@ -4047,10 +3947,1003 @@ diff -uNr --no-dereference kubernetes-original/plugin/pkg/admission/persistentvo
4047 4047
 +	}
4048 4048
 +	return l.cascadeDisks, nil
4049 4049
 +}
4050
-diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/generated.pb.go kubernetes-modified/src/k8s.io/kubernetes/staging/src/k8s.io/api/core/v1/generated.pb.go
4051
-+++ kubernetes-modified/src/k8s.io/kubernetes/staging/src/k8s.io/api/core/v1/generated.pb.go	2018-04-30 21:11:51.000000000 +0000
4052
-@@ -35,6 +35,7 @@
4050
+diff --git a/plugin/pkg/admission/vke/BUILD b/plugin/pkg/admission/vke/BUILD
4051
+new file mode 100644
4052
+index 0000000..b0a6026
4053
+--- /dev/null
4054
+@@ -0,0 +1,58 @@
4055
++package(default_visibility = ["//visibility:public"])
4056
++
4057
++load(
4058
++    "@io_bazel_rules_go//go:def.bzl",
4059
++    "go_library",
4060
++)
4061
++
4062
++go_library(
4063
++    name = "go_default_library",
4064
++    srcs = ["admission.go"],
4065
++    importpath = "k8s.io/kubernetes/plugin/pkg/admission/vke",
4066
++    deps = [
4067
++        "//pkg/apis/core:go_default_library",
4068
++        "//pkg/apis/extensions:go_default_library",
4069
++        "//pkg/apis/rbac:go_default_library",
4070
++        "//pkg/registry/rbac:go_default_library",
4071
++        "//pkg/security/podsecuritypolicy:go_default_library",
4072
++        "//vendor/github.com/golang/glog:go_default_library",
4073
++        "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
4074
++        "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
4075
++        "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
4076
++        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
4077
++        "//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
4078
++    ],
4079
++)
4080
++
4081
++go_test(
4082
++    name = "go_default_test",
4083
++    srcs = ["admission_test.go"],
4084
++    embed = [":go_default_library"],
4085
++    deps = [
4086
++        "//pkg/apis/core:go_default_library",
4087
++        "//pkg/apis/extensions:go_default_library",
4088
++        "//pkg/apis/rbac:go_default_library",
4089
++        "//pkg/registry/rbac:go_default_library",
4090
++        "//pkg/security/podsecuritypolicy:go_default_library",
4091
++        "//vendor/github.com/golang/glog:go_default_library",
4092
++        "//vendor/github.com/stretchr/testify/assert:go_default_library",
4093
++        "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
4094
++        "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
4095
++        "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
4096
++        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
4097
++        "//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
4098
++    ],
4099
++)
4100
++
4101
++filegroup(
4102
++    name = "package-srcs",
4103
++    srcs = glob(["**"]),
4104
++    tags = ["automanaged"],
4105
++    visibility = ["//visibility:private"],
4106
++)
4107
++
4108
++filegroup(
4109
++    name = "all-srcs",
4110
++    srcs = [":package-srcs"],
4111
++    tags = ["automanaged"],
4112
++)
4113
+\ No newline at end of file
4114
+diff --git a/plugin/pkg/admission/vke/admission.go b/plugin/pkg/admission/vke/admission.go
4115
+new file mode 100644
4116
+index 0000000..4cfc8c5
4117
+--- /dev/null
4118
+@@ -0,0 +1,374 @@
4119
++package vke
4120
++
4121
++import (
4122
++	"fmt"
4123
++	"io"
4124
++	"strings"
4125
++
4126
++	"github.com/golang/glog"
4127
++	apiequality "k8s.io/apimachinery/pkg/api/equality"
4128
++	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4129
++	"k8s.io/apimachinery/pkg/util/validation/field"
4130
++	"k8s.io/apimachinery/pkg/util/yaml"
4131
++	"k8s.io/apiserver/pkg/admission"
4132
++	api "k8s.io/kubernetes/pkg/apis/core"
4133
++	"k8s.io/kubernetes/pkg/apis/extensions"
4134
++	"k8s.io/kubernetes/pkg/apis/rbac"
4135
++	rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
4136
++	"k8s.io/kubernetes/pkg/security/podsecuritypolicy"
4137
++)
4138
++
4139
++const (
4140
++	// PluginName indicates name of admission plugin.
4141
++	PluginName = "VMwareAdmissionController"
4142
++
4143
++	systemUnsecuredUser      = "system:unsecured"
4144
++	privilegedNamespace      = "vke-system"
4145
++	privilegedServiceAccount = "system:serviceaccount:" + privilegedNamespace + ":"
4146
++	reservedPrefix           = "vke"
4147
++	kubeletGroup             = "system:nodes"
4148
++	kubeProxyGroup           = "cascade:kube-proxies"
4149
++	dashboardPod             = "vke-dashboard-0"
4150
++	kubeSystemNamespace      = "kube-system"
4151
++)
4152
++
4153
++// Register registers a plugin.
4154
++func Register(plugins *admission.Plugins) {
4155
++	plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
4156
++		return NewVMwareAdmissionController(config)
4157
++	})
4158
++}
4159
++
4160
++// vmwareAdmissionController is an implementation of admission.Interface.
4161
++// It restricts access to VKE namespace for users and prevents the users from creating privileged pods.
4162
++type vmwareAdmissionController struct {
4163
++	psp             *extensions.PodSecurityPolicy
4164
++	strategyFactory podsecuritypolicy.StrategyFactory
4165
++	privilegedGroup string
4166
++}
4167
++
4168
++// vmwareAdmissionControllerConfig holds config data for VMwareAdmissionController.
4169
++type vmwareAdmissionControllerConfig struct {
4170
++	PrivilegedGroup string `yaml:"privilegedGroup"`
4171
++}
4172
++
4173
++// AdmissionConfig holds config data for admission controllers.
4174
++type AdmissionConfig struct {
4175
++	VMwareAdmissionController vmwareAdmissionControllerConfig `yaml:"vmwareAdmissionController"`
4176
++}
4177
++
4178
++var _ admission.ValidationInterface = &vmwareAdmissionController{}
4179
++
4180
++// Validate makes an admission decision based on the request attributes.  It is NOT allowed to mutate.
4181
++func (vac *vmwareAdmissionController) Validate(a admission.Attributes) (err error) {
4182
++	if isPrivilegedUser(vac, a) {
4183
++		return nil
4184
++	}
4185
++
4186
++	if isSystemUnsecuredUser(a) {
4187
++		return validateSystemUnsecuredUser(vac, a)
4188
++	}
4189
++
4190
++	if isPrivilegedNamespace(a) {
4191
++		return admission.NewForbidden(a,
4192
++			fmt.Errorf("%s validation failed: cannot modify resources in namespace %s", PluginName, a.GetNamespace()))
4193
++	}
4194
++
4195
++	switch a.GetResource().GroupResource() {
4196
++	case api.Resource("pods"):
4197
++		err = validatePods(vac, a)
4198
++	case api.Resource("nodes"):
4199
++		err = admission.NewForbidden(a, fmt.Errorf("%s validation failed: cannot modify nodes", PluginName))
4200
++	case rbac.Resource("clusterroles"):
4201
++		err = validateClusterRoles(a)
4202
++	case rbac.Resource("clusterrolebindings"):
4203
++		err = validateClusterRoleBindings(a)
4204
++	}
4205
++
4206
++	return err
4207
++}
4208
++
4209
++// Handles returns true if this admission controller can handle the given operation
4210
++// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT.
4211
++func (vac *vmwareAdmissionController) Handles(operation admission.Operation) bool {
4212
++	return true
4213
++}
4214
++
4215
++// NewVMwareAdmissionController creates a new VMwareAdmissionController.
4216
++func NewVMwareAdmissionController(configFile io.Reader) (*vmwareAdmissionController, error) {
4217
++	glog.V(2).Infof("%s is enabled", PluginName)
4218
++	if configFile == nil {
4219
++		glog.Warningf("No config specified for %s. Using default configuration", PluginName)
4220
++		return nil, fmt.Errorf("no config file specified for %s", PluginName)
4221
++	}
4222
++
4223
++	var config AdmissionConfig
4224
++	d := yaml.NewYAMLOrJSONDecoder(configFile, 4096)
4225
++	err := d.Decode(&config)
4226
++	if err != nil {
4227
++		return nil, err
4228
++	}
4229
++
4230
++	return &vmwareAdmissionController{
4231
++		psp:             getDefaultPSP(),
4232
++		strategyFactory: podsecuritypolicy.NewSimpleStrategyFactory(),
4233
++		privilegedGroup: config.VMwareAdmissionController.PrivilegedGroup,
4234
++	}, nil
4235
++}
4236
++
4237
++func getDefaultPSP() *extensions.PodSecurityPolicy {
4238
++	return &extensions.PodSecurityPolicy{
4239
++		TypeMeta: metav1.TypeMeta{
4240
++			Kind:       "PodSecurityPolicy",
4241
++			APIVersion: "extensions/v1beta1",
4242
++		},
4243
++		Spec: extensions.PodSecurityPolicySpec{
4244
++			Privileged:               false,
4245
++			HostNetwork:              false,
4246
++			HostIPC:                  false,
4247
++			HostPID:                  false,
4248
++			AllowPrivilegeEscalation: false,
4249
++			Volumes: []extensions.FSType{
4250
++				"emptyDir",
4251
++				"secret",
4252
++				"downwardAPI",
4253
++				"configMap",
4254
++				"persistentVolumeClaim",
4255
++				"projected",
4256
++			},
4257
++			FSGroup: extensions.FSGroupStrategyOptions{
4258
++				Rule: extensions.FSGroupStrategyRunAsAny,
4259
++			},
4260
++			RunAsUser: extensions.RunAsUserStrategyOptions{
4261
++				Rule: extensions.RunAsUserStrategyRunAsAny,
4262
++			},
4263
++			SELinux: extensions.SELinuxStrategyOptions{
4264
++				Rule: extensions.SELinuxStrategyRunAsAny,
4265
++			},
4266
++			SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
4267
++				Rule: extensions.SupplementalGroupsStrategyRunAsAny,
4268
++			},
4269
++		},
4270
++	}
4271
++}
4272
++
4273
++func isPrivilegedUser(vac *vmwareAdmissionController, a admission.Attributes) bool {
4274
++	// We need to allow the service accounts inside the privileged namespace to be able to access pods and nodes.
4275
++	// Node-monitor agent, Photon OS update controller and Cluster autoscaler depend on this.
4276
++	user := a.GetUserInfo().GetName()
4277
++	if strings.HasPrefix(user, privilegedServiceAccount) {
4278
++		return true
4279
++	}
4280
++
4281
++	// If the request comes from a user belonging to a privileged group, then we allow it. Only calls from Cascade
4282
++	// controller will belong to this privileged group.
4283
++	// If the request comes from kubelet or kube-proxy, we allow those too. We don't want to prevent kubelet from being
4284
++	// able to create a privileged pod or update nodes. The same way we don't want to prevent kube-proxy from creating
4285
++	// events.
4286
++	groups := a.GetUserInfo().GetGroups()
4287
++	for _, group := range groups {
4288
++		if group == vac.privilegedGroup || group == kubeletGroup || group == kubeProxyGroup {
4289
++			return true
4290
++		}
4291
++	}
4292
++
4293
++	return false
4294
++}
4295
++
4296
++func isSystemUnsecuredUser(a admission.Attributes) bool {
4297
++	return a.GetUserInfo().GetName() == systemUnsecuredUser
4298
++}
4299
++
4300
++func validateSystemUnsecuredUser(vac *vmwareAdmissionController, a admission.Attributes) (err error) {
4301
++	// Currently the insecure port 8080 is exposed to only localhost inside the Kubernetes master VMs. So it can be used
4302
++	// only by kube-controller-manager, kube-scheduler and cloud-init script which creates our pods and other resources.
4303
++	// When a call comes on insecure port 8080, Kubernetes assigns them system:unsecured user name. We need to allow
4304
++	// this so that our master components can be started successfully and kube-controller-manager and kube-scheduler can
4305
++	// work as expected.
4306
++	// But this needs to be allowed only inside our privileged namespace. If the request comes to any other namespace,
4307
++	// we need to make it go through our pod validation. This is needed because a user can create a deployment or
4308
++	// replica set which has a privileged pod. Since our admission controller does not look at deployments or replica
4309
++	// sets, we will allow it. The actual pod inside the deployment or replica set will be created by the
4310
++	// controller-manager and if we allow it to create pods in any namespace, then a user can create a privileged pod
4311
++	// totally bypassing our security checks.
4312
++	if !isPrivilegedNamespace(a) && (a.GetResource().GroupResource() == api.Resource("pods")) {
4313
++		return validatePods(vac, a)
4314
++	}
4315
++
4316
++	// For all other resources, allow.
4317
++	return nil
4318
++}
4319
++
4320
++func isPrivilegedNamespace(a admission.Attributes) bool {
4321
++	// If the namespace mentioned in the resource is privileged, return true. We will hit this for calls made to all
4322
++	// resources in this namespace and during delete and update operation on the namespace itself.
4323
++	if a.GetNamespace() == privilegedNamespace {
4324
++		return true
4325
++	}
4326
++
4327
++	// If the resource is a namespace and if its name matched the privileged namespace, return true. We will hit this
4328
++	// during creation of the namespace.
4329
++	if a.GetResource().GroupResource() == api.Resource("namespaces") {
4330
++		if namespace, ok := a.GetObject().(*api.Namespace); ok {
4331
++			if namespace.Name == privilegedNamespace {
4332
++				return true
4333
++			}
4334
++		}
4335
++	}
4336
++
4337
++	return false
4338
++}
4339
++
4340
++func validateClusterRoles(a admission.Attributes) error {
4341
++	// If the name in the request is not empty and has the reserved prefix, then fail. We will hit this during delete
4342
++	// and update operations on the cluster roles. If it does not have the reserved prefix, allow it. If the name is
4343
++	// empty then proceed to read it from the object in the request.
4344
++	if a.GetName() != "" {
4345
++		return checkReservedPrefix(a.GetName(), a)
4346
++	}
4347
++
4348
++	clusterRole, ok := a.GetObject().(*rbac.ClusterRole)
4349
++	// If we cannot get the cluster role binding object, fail.
4350
++	if !ok {
4351
++		return admission.NewForbidden(a,
4352
++			fmt.Errorf("%s validation failed: unexpected type %T", PluginName, a.GetObject()))
4353
++	}
4354
++	// If we get the object and the name has the reserved prefix, fail. We will hit this when someone tries to create a
4355
++	// cluster role with the reserved prefix.
4356
++	return checkReservedPrefix(clusterRole.Name, a)
4357
++}
4358
++
4359
++func validateClusterRoleBindings(a admission.Attributes) error {
4360
++	// If the name in the request is not empty and has the reserved prefix, then fail. We will hit this during delete
4361
++	// and update operations on the cluster role bindings. If it does not have the reserved prefix, allow it. If the
4362
++	// name is empty then proceed to read it from the object in the request.
4363
++	if a.GetName() != "" {
4364
++		return checkReservedPrefix(a.GetName(), a)
4365
++	}
4366
++
4367
++	clusterRoleBinding, ok := a.GetObject().(*rbac.ClusterRoleBinding)
4368
++	// If we cannot get the cluster role binding object, fail.
4369
++	if !ok {
4370
++		return admission.NewForbidden(a,
4371
++			fmt.Errorf("%s validation failed: unexpected type %T", PluginName, a.GetObject()))
4372
++	}
4373
++	// If we get the object and the name has the reserved prefix, fail. We will hit this when someone tries to create a
4374
++	// cluster role binding with the reserved prefix.
4375
++	return checkReservedPrefix(clusterRoleBinding.Name, a)
4376
++}
4377
++
4378
++func validatePods(vac *vmwareAdmissionController, a admission.Attributes) error {
4379
++	// If the request is acting on a sub resource of a pod then allow it. This request is not directly coming to a pod,
4380
++	// but to a sub-resource like pods/foo/status. So, this does not have to be blocked.
4381
++	if len(a.GetSubresource()) != 0 {
4382
++		return nil
4383
++	}
4384
++
4385
++	// If it is a Connect operation, allow it. We restrict access to connect to any pods in the vke-system namespace.
4386
++	// Also, DenyEscalatingExec admission controller denies access to connect to any privileged pod in general. So it is
4387
++	// OK to allow this.
4388
++	if a.GetOperation() == admission.Connect {
4389
++		return nil
4390
++	}
4391
++
4392
++	// If it is a Delete operation and it is not a pod with a reserved prefix, allow it. We restrict access to delete
4393
++	// any pods in the vke-system namespace. So it is OK to allow this.
4394
++	// TODO: Make sure we do not have a need to delete the dashboard stateful set. If we do then it will fail.
4395
++	if a.GetOperation() == admission.Delete {
4396
++		return checkReservedPrefix(a.GetName(), a)
4397
++	}
4398
++
4399
++	// If we cannot get the pod object, fail.
4400
++	if _, ok := a.GetObject().(*api.Pod); !ok {
4401
++		return admission.NewForbidden(a,
4402
++			fmt.Errorf("%s validation failed: unexpected type %T", PluginName, a.GetObject()))
4403
++	}
4404
++
4405
++	// If this is an update, see if we are only updating the ownerRef/finalizers.  Garbage collection does this
4406
++	// and we should allow it in general, since you had the power to update and the power to delete.
4407
++	// The worst that happens is that you delete something, but you aren't controlling the privileged object itself
4408
++	if a.GetOperation() == admission.Update &&
4409
++		rbacregistry.IsOnlyMutatingGCFields(a.GetObject(), a.GetOldObject(), apiequality.Semantic) {
4410
++		return nil
4411
++	}
4412
++
4413
++	errs := field.ErrorList{}
4414
++	originalPod := a.GetObject().(*api.Pod)
4415
++
4416
++	// If the pod is our dashboard pod, its namespace is kube-system and it is created by the controller-manager then
4417
++	// skip validation. This pod is in kube-system namespace which is not privileged. But we need to allow the dashboard
4418
++	// pod to be privileged because it has the OIDC proxy container which requires hostPath volume mount. Just to make
4419
++	// sure we allow only this one pod, we make sure that it is created by the controller manager and name matches the
4420
++	// dashboard pod and it is in kube-system.
4421
++	if a.GetUserInfo().GetName() == systemUnsecuredUser && a.GetNamespace() == kubeSystemNamespace &&
4422
++		(a.GetName() == dashboardPod || originalPod.Name == dashboardPod) {
4423
++		return nil
4424
++	}
4425
++
4426
++	// Check if the pod that needs to be created or updated has the reserved prefix. If it does, deny the request.
4427
++	podName := a.GetName()
4428
++	if podName == "" {
4429
++		podName = originalPod.Name
4430
++	}
4431
++	if err := checkReservedPrefix(podName, a); err != nil {
4432
++		return err
4433
++	}
4434
++
4435
++	// Generate a copy of the pod object because we are not allowed to mutate the pod object.
4436
++	pod := originalPod.DeepCopy()
4437
++
4438
++	provider, err := podsecuritypolicy.NewSimpleProvider(vac.psp, pod.Namespace, vac.strategyFactory)
4439
++	if err != nil {
4440
++		return admission.NewForbidden(a, fmt.Errorf("%s validation failed: %v", PluginName, err))
4441
++	}
4442
++
4443
++	// Set default security context for the pod. This fills in the defaults for the security context values that are not
4444
++	// provided. This is needed to validate the security context correctly.
4445
++	pod.Spec.SecurityContext, _, err = provider.CreatePodSecurityContext(pod)
4446
++	if err != nil {
4447
++		errs = append(errs, field.Invalid(field.NewPath("spec", "securityContext"),
4448
++			pod.Spec.SecurityContext, err.Error()))
4449
++	}
4450
++
4451
++	// Validate the pod.
4452
++	errs = append(errs, provider.ValidatePodSecurityContext(pod, field.NewPath("spec", "securityContext"))...)
4453
++
4454
++	// Validate the initContainers that are part of the pod.
4455
++	for i := range pod.Spec.InitContainers {
4456
++		pod.Spec.InitContainers[i].SecurityContext, _, err = provider.CreateContainerSecurityContext(pod, &pod.Spec.InitContainers[i])
4457
++		if err != nil {
4458
++			errs = append(errs, field.Invalid(field.NewPath("spec", "initContainers").Index(i).
4459
++				Child("securityContext"), "", err.Error()))
4460
++			continue
4461
++		}
4462
++		errs = append(errs, provider.ValidateContainerSecurityContext(pod, &pod.Spec.InitContainers[i],
4463
++			field.NewPath("spec", "initContainers").Index(i).Child("securityContext"))...)
4464
++	}
4465
++
4466
++	// Validate the containers that are part of the pod.
4467
++	for i := range pod.Spec.Containers {
4468
++		pod.Spec.Containers[i].SecurityContext, _, err = provider.CreateContainerSecurityContext(pod, &pod.Spec.Containers[i])
4469
++		if err != nil {
4470
++			errs = append(errs, field.Invalid(field.NewPath("spec", "containers").Index(i).
4471
++				Child("securityContext"), "", err.Error()))
4472
++			continue
4473
++		}
4474
++		errs = append(errs, provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[i],
4475
++			field.NewPath("spec", "containers").Index(i).Child("securityContext"))...)
4476
++	}
4477
++
4478
++	if len(errs) > 0 {
4479
++		return admission.NewForbidden(a,
4480
++			fmt.Errorf("%s validation failed: %v", PluginName, errs))
4481
++	}
4482
++
4483
++	return nil
4484
++}
4485
++
4486
++func checkReservedPrefix(resourceName string, a admission.Attributes) error {
4487
++	if strings.HasPrefix(resourceName, reservedPrefix) {
4488
++		return admission.NewForbidden(a,
4489
++			fmt.Errorf("%s validation failed: cannot modify resources with prefix %s", PluginName, reservedPrefix))
4490
++	}
4491
++	return nil
4492
++}
4493
+diff --git a/plugin/pkg/admission/vke/admission_test.go b/plugin/pkg/admission/vke/admission_test.go
4494
+new file mode 100644
4495
+index 0000000..81acbe1
4496
+--- /dev/null
4497
+@@ -0,0 +1,541 @@
4498
++package vke
4499
++
4500
++import (
4501
++	"fmt"
4502
++	"strings"
4503
++	"testing"
4504
++
4505
++	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4506
++	kadmission "k8s.io/apiserver/pkg/admission"
4507
++	kapi "k8s.io/kubernetes/pkg/apis/core"
4508
++	"k8s.io/kubernetes/pkg/apis/rbac"
4509
++	"k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/authentication/user"
4510
++)
4511
++
4512
++const (
4513
++	testServiceAccountsGroup = "system.test\\cascade-controller-service-accounts"
4514
++	defaultConfigFileFormat  = `
4515
++vmwareAdmissionController:
4516
++  privilegedGroup: %s
4517
++`
4518
++)
4519
++
4520
++func TestAdmitPrivileged(t *testing.T) {
4521
++	tests := map[string]struct {
4522
++		operation          kadmission.Operation
4523
++		pod                *kapi.Pod
4524
++		name               string
4525
++		userInfo           user.Info
4526
++		shouldPassValidate bool
4527
++	}{
4528
++		"create pod with Privileged=nil allowed": {
4529
++			operation:          kadmission.Create,
4530
++			pod:                newTestPodBuilder().build(),
4531
++			userInfo:           newTestUserBuilder().build(),
4532
++			shouldPassValidate: true,
4533
++		},
4534
++		"create pod with Privileged=false allowed": {
4535
++			operation:          kadmission.Create,
4536
++			pod:                newTestPodBuilder().withPrivileged(false).build(),
4537
++			userInfo:           newTestUserBuilder().build(),
4538
++			shouldPassValidate: true,
4539
++		},
4540
++		"create pod with Privileged=true denied": {
4541
++			operation:          kadmission.Create,
4542
++			pod:                newTestPodBuilder().withPrivileged(true).build(),
4543
++			userInfo:           newTestUserBuilder().build(),
4544
++			shouldPassValidate: false,
4545
++		},
4546
++		"create pod with multiple containers, one has Privileged=true denied": {
4547
++			operation:          kadmission.Create,
4548
++			pod:                newTestPodBuilder().withPrivileged(true).withInitContainer().withContainer().build(),
4549
++			userInfo:           newTestUserBuilder().build(),
4550
++			shouldPassValidate: false,
4551
++		},
4552
++		"update pod with Privileged=true denied": {
4553
++			operation:          kadmission.Update,
4554
++			pod:                newTestPodBuilder().withPrivileged(true).build(),
4555
++			userInfo:           newTestUserBuilder().build(),
4556
++			shouldPassValidate: false,
4557
++		},
4558
++		"create pod with HostNetwork=true denied": {
4559
++			operation:          kadmission.Create,
4560
++			pod:                newTestPodBuilder().withHostNetwork(true).build(),
4561
++			userInfo:           newTestUserBuilder().build(),
4562
++			shouldPassValidate: false,
4563
++		},
4564
++		"create pod with HostIPC=true denied": {
4565
++			operation:          kadmission.Create,
4566
++			pod:                newTestPodBuilder().withHostIPC(true).build(),
4567
++			userInfo:           newTestUserBuilder().build(),
4568
++			shouldPassValidate: false,
4569
++		},
4570
++		"create pod with HostPID=true denied": {
4571
++			operation:          kadmission.Create,
4572
++			pod:                newTestPodBuilder().withHostPID(true).build(),
4573
++			userInfo:           newTestUserBuilder().build(),
4574
++			shouldPassValidate: false,
4575
++		},
4576
++		"create pod with HostVolume denied": {
4577
++			operation:          kadmission.Create,
4578
++			pod:                newTestPodBuilder().withHostVolume().build(),
4579
++			userInfo:           newTestUserBuilder().build(),
4580
++			shouldPassValidate: false,
4581
++		},
4582
++		"create pod with CascadeDisk allowed": {
4583
++			operation:          kadmission.Create,
4584
++			pod:                newTestPodBuilder().withCascadeDisk().build(),
4585
++			userInfo:           newTestUserBuilder().build(),
4586
++			shouldPassValidate: true,
4587
++		},
4588
++		"create pod with HostVolume and CascadeDisk denied": {
4589
++			operation:          kadmission.Create,
4590
++			pod:                newTestPodBuilder().withHostVolume().withCascadeDisk().build(),
4591
++			userInfo:           newTestUserBuilder().build(),
4592
++			shouldPassValidate: false,
4593
++		},
4594
++		"create pod with vke prefix denied": {
4595
++			operation:          kadmission.Create,
4596
++			pod:                newTestPodBuilder().build(),
4597
++			name:               "vke-dashboard",
4598
++			userInfo:           newTestUserBuilder().build(),
4599
++			shouldPassValidate: false,
4600
++		},
4601
++		"create dashboard pod with vke prefix by privileged user in kube-system allowed": {
4602
++			operation:          kadmission.Create,
4603
++			pod:                newTestPodBuilder().withNamespace(kubeSystemNamespace).build(),
4604
++			name:               "vke-dashboard-0",
4605
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4606
++			shouldPassValidate: true,
4607
++		},
4608
++		"connect pod allowed": {
4609
++			operation:          kadmission.Connect,
4610
++			pod:                newTestPodBuilder().build(),
4611
++			userInfo:           newTestUserBuilder().build(),
4612
++			shouldPassValidate: true,
4613
++		},
4614
++		"delete pod allowed": {
4615
++			operation:          kadmission.Delete,
4616
++			pod:                newTestPodBuilder().build(),
4617
++			userInfo:           newTestUserBuilder().build(),
4618
++			shouldPassValidate: true,
4619
++		},
4620
++		"delete pod with vke prefix denied": {
4621
++			operation:          kadmission.Delete,
4622
++			pod:                newTestPodBuilder().build(),
4623
++			name:               "vke-dashboard",
4624
++			userInfo:           newTestUserBuilder().build(),
4625
++			shouldPassValidate: false,
4626
++		},
4627
++	}
4628
++
4629
++	for k, v := range tests {
4630
++		testPodValidation(k, v.operation, v.pod, v.name, v.userInfo, v.shouldPassValidate, t)
4631
++	}
4632
++}
4633
++
4634
++func TestPrivilegedNamespace(t *testing.T) {
4635
++	tests := map[string]struct {
4636
++		operation          kadmission.Operation
4637
++		pod                *kapi.Pod
4638
++		name               string
4639
++		userInfo           user.Info
4640
++		shouldPassValidate bool
4641
++	}{
4642
++		"denied: regular lightwave user creates pod in vke-system namespace": {
4643
++			operation:          kadmission.Create,
4644
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4645
++			userInfo:           newTestUserBuilder().build(),
4646
++			shouldPassValidate: false,
4647
++		},
4648
++		"denied: regular lightwave user cannot escalate privilege using service account": {
4649
++			operation:          kadmission.Create,
4650
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).withServiceAccount("system:serviceaccount:" + privilegedNamespace + ":default").build(),
4651
++			userInfo:           newTestUserBuilder().build(),
4652
++			shouldPassValidate: false,
4653
++		},
4654
++		"denied: regular service account creates pod in vke-system namespace": {
4655
++			operation:          kadmission.Create,
4656
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4657
++			userInfo:           newTestUserBuilder().withName("system:serviceaccount:kube-system:default").build(),
4658
++			shouldPassValidate: false,
4659
++		},
4660
++		"allowed: regular user creates pod in other namespace": {
4661
++			operation:          kadmission.Create,
4662
++			pod:                newTestPodBuilder().withNamespace("default").build(),
4663
++			userInfo:           newTestUserBuilder().build(),
4664
++			shouldPassValidate: true,
4665
++		},
4666
++		"allowed: Cascade Controller Service Account creates pod in vke-system namespace": {
4667
++			operation:          kadmission.Create,
4668
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4669
++			userInfo:           newTestUserBuilder().withGroup(testServiceAccountsGroup).build(),
4670
++			shouldPassValidate: true,
4671
++		},
4672
++		"allowed: systemUnsecuredUser creates pod in vke-system namespace": {
4673
++			operation:          kadmission.Create,
4674
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4675
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4676
++			shouldPassValidate: true,
4677
++		},
4678
++		"allowed: vke-system service account creates pod in vke-system namespace": {
4679
++			operation:          kadmission.Create,
4680
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4681
++			userInfo:           newTestUserBuilder().withName("system:serviceaccount:" + privilegedNamespace + ":default").build(),
4682
++			shouldPassValidate: true,
4683
++		},
4684
++		"allowed: kubelet group creates pod in vke-system namespace": {
4685
++			operation:          kadmission.Create,
4686
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4687
++			userInfo:           newTestUserBuilder().withGroup(kubeletGroup).build(),
4688
++			shouldPassValidate: true,
4689
++		},
4690
++		"allowed: kubeProxy group creates pod in vke-system namespace": {
4691
++			operation:          kadmission.Create,
4692
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4693
++			userInfo:           newTestUserBuilder().withGroup(kubeProxyGroup).build(),
4694
++			shouldPassValidate: true,
4695
++		},
4696
++		"denied: regular lightwave group does not grant privileged access": {
4697
++			operation:          kadmission.Create,
4698
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4699
++			userInfo:           newTestUserBuilder().withGroup("test1\\group1").build(),
4700
++			shouldPassValidate: false,
4701
++		},
4702
++		"allowed: if user has multiple groups, any privileged group can grant privileged access": {
4703
++			operation:          kadmission.Create,
4704
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4705
++			userInfo:           newTestUserBuilder().withGroup("test1\\group1").withGroup(testServiceAccountsGroup).build(),
4706
++			shouldPassValidate: true,
4707
++		},
4708
++	}
4709
++	for k, v := range tests {
4710
++		testPodValidation(k, v.operation, v.pod, v.name, v.userInfo, v.shouldPassValidate, t)
4711
++	}
4712
++}
4713
++
4714
++func TestClusterLevelResources(t *testing.T) {
4715
++	tests := map[string]struct {
4716
++		operation          kadmission.Operation
4717
++		resource           string
4718
++		name               string
4719
++		namespace          string
4720
++		userInfo           user.Info
4721
++		shouldPassValidate bool
4722
++	}{
4723
++		"denied: regular lightwave user update configmaps in vke-system namespace": {
4724
++			operation:          kadmission.Update,
4725
++			resource:           "configmaps",
4726
++			namespace:          privilegedNamespace,
4727
++			userInfo:           newTestUserBuilder().build(),
4728
++			shouldPassValidate: false,
4729
++		},
4730
++		"denied: regular lightwave user delete daemonsets in vke-system namespace": {
4731
++			operation:          kadmission.Delete,
4732
++			resource:           "daemonsets",
4733
++			namespace:          privilegedNamespace,
4734
++			userInfo:           newTestUserBuilder().build(),
4735
++			shouldPassValidate: false,
4736
++		},
4737
++		"denied: regular lightwave user create deployments in vke-system namespace": {
4738
++			operation:          kadmission.Create,
4739
++			resource:           "deployments",
4740
++			namespace:          privilegedNamespace,
4741
++			userInfo:           newTestUserBuilder().build(),
4742
++			shouldPassValidate: false,
4743
++		},
4744
++		"denied: regular lightwave user create rolebindings in vke-system namespace": {
4745
++			operation:          kadmission.Create,
4746
++			resource:           "rolebindings",
4747
++			namespace:          privilegedNamespace,
4748
++			userInfo:           newTestUserBuilder().build(),
4749
++			shouldPassValidate: false,
4750
++		},
4751
++		"allowed: regular lightwave user create rolebindings in other namespace": {
4752
++			operation:          kadmission.Create,
4753
++			resource:           "rolebindings",
4754
++			namespace:          "default",
4755
++			userInfo:           newTestUserBuilder().build(),
4756
++			shouldPassValidate: true,
4757
++		},
4758
++		"allowed: regular lightwave user create clusterroles": {
4759
++			operation:          kadmission.Create,
4760
++			resource:           "clusterroles",
4761
++			name:               "cluster-role",
4762
++			namespace:          "",
4763
++			userInfo:           newTestUserBuilder().build(),
4764
++			shouldPassValidate: true,
4765
++		},
4766
++		"denied: regular lightwave user create clusterroles with vke: prefix": {
4767
++			operation:          kadmission.Create,
4768
++			resource:           "clusterroles",
4769
++			name:               "vke:clusterrole",
4770
++			namespace:          "",
4771
++			userInfo:           newTestUserBuilder().build(),
4772
++			shouldPassValidate: false,
4773
++		},
4774
++		"denied: regular lightwave user delete clusterroles with vke: prefix": {
4775
++			operation:          kadmission.Delete,
4776
++			resource:           "clusterroles",
4777
++			name:               "vke:clusterrole",
4778
++			namespace:          "",
4779
++			userInfo:           newTestUserBuilder().build(),
4780
++			shouldPassValidate: false,
4781
++		},
4782
++		"allowed: systemUnsecuredUser update clusterroles with vke: prefix": {
4783
++			operation:          kadmission.Update,
4784
++			resource:           "clusterroles",
4785
++			name:               "vke:clusterrole",
4786
++			namespace:          "",
4787
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4788
++			shouldPassValidate: true,
4789
++		},
4790
++		"allowed: regular lightwave user create clusterrolebindings": {
4791
++			operation:          kadmission.Create,
4792
++			resource:           "clusterrolebindings",
4793
++			name:               "cluster-role-binding",
4794
++			namespace:          "",
4795
++			userInfo:           newTestUserBuilder().build(),
4796
++			shouldPassValidate: true,
4797
++		},
4798
++		"denied: regular lightwave user create clusterrolebindings with vke: prefix": {
4799
++			operation:          kadmission.Create,
4800
++			resource:           "clusterrolebindings",
4801
++			name:               "vke:clusterrolebinding",
4802
++			namespace:          "",
4803
++			userInfo:           newTestUserBuilder().build(),
4804
++			shouldPassValidate: false,
4805
++		},
4806
++		"denied: regular lightwave user update clusterrolebindings with vke: prefix": {
4807
++			operation:          kadmission.Delete,
4808
++			resource:           "clusterrolebindings",
4809
++			name:               "vke:clusterrolebinding",
4810
++			namespace:          "",
4811
++			userInfo:           newTestUserBuilder().build(),
4812
++			shouldPassValidate: false,
4813
++		},
4814
++		"allowed: systemUnsecuredUser update clusterrolebindings with vke: prefix": {
4815
++			operation:          kadmission.Update,
4816
++			resource:           "clusterrolebindings",
4817
++			name:               "vke:clusterrolebinding",
4818
++			namespace:          "",
4819
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4820
++			shouldPassValidate: true,
4821
++		},
4822
++		"denied: regular lightwave user update nodes": {
4823
++			operation:          kadmission.Update,
4824
++			resource:           "nodes",
4825
++			namespace:          "",
4826
++			userInfo:           newTestUserBuilder().build(),
4827
++			shouldPassValidate: false,
4828
++		},
4829
++		"allowed: systemUnsecuredUser update nodes": {
4830
++			operation:          kadmission.Update,
4831
++			resource:           "nodes",
4832
++			namespace:          "",
4833
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4834
++			shouldPassValidate: true,
4835
++		},
4836
++	}
4837
++	for k, v := range tests {
4838
++		testResourceValidation(k, v.operation, v.resource, v.name, v.namespace, v.userInfo, v.shouldPassValidate, t)
4839
++	}
4840
++}
4841
++
4842
++func testPodValidation(testCaseName string, op kadmission.Operation, pod *kapi.Pod, name string, userInfo user.Info,
4843
++	shouldPassValidate bool, t *testing.T) {
4844
++
4845
++	defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup)
4846
++	configFile := strings.NewReader(defaultConfigFile)
4847
++	plugin, err := NewVMwareAdmissionController(configFile)
4848
++	if err != nil {
4849
++		t.Errorf("%s: failed to create admission controller %v", testCaseName, err)
4850
++	}
4851
++
4852
++	attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"),
4853
++		pod.Namespace, name, kapi.Resource("pods").WithVersion("version"), "", op, userInfo)
4854
++
4855
++	err = plugin.Validate(attrs)
4856
++	if shouldPassValidate && err != nil {
4857
++		t.Errorf("%s: expected no errors on Validate but received %v", testCaseName, err)
4858
++	} else if !shouldPassValidate && err == nil {
4859
++		t.Errorf("%s: expected errors on Validate but received none", testCaseName)
4860
++	}
4861
++}
4862
++
4863
++func testResourceValidation(testCaseName string, op kadmission.Operation, resource string, name string,
4864
++	namespace string, userInfo user.Info, shouldPassValidate bool, t *testing.T) {
4865
++
4866
++	defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup)
4867
++	configFile := strings.NewReader(defaultConfigFile)
4868
++	plugin, err := NewVMwareAdmissionController(configFile)
4869
++	if err != nil {
4870
++		t.Errorf("%s: failed to create admission controller %v", testCaseName, err)
4871
++	}
4872
++
4873
++	groupResource := kapi.Resource(resource).WithVersion("version")
4874
++	if resource == "clusterroles" || resource == "clusterrolebindings" {
4875
++		groupResource = rbac.Resource(resource).WithVersion("version")
4876
++	}
4877
++
4878
++	attrs := kadmission.NewAttributesRecord(nil, nil, kapi.Kind("kind").WithVersion("version"),
4879
++		namespace, name, groupResource, "", op, userInfo)
4880
++
4881
++	err = plugin.Validate(attrs)
4882
++	if shouldPassValidate && err != nil {
4883
++		t.Errorf("%s: expected no errors on Validate but received %v", testCaseName, err)
4884
++	} else if !shouldPassValidate && err == nil {
4885
++		t.Errorf("%s: expected errors on Validate but received none", testCaseName)
4886
++	}
4887
++}
4888
++
4889
++// testPodBuilder
4890
++type testPodBuilder struct {
4891
++	pod kapi.Pod
4892
++}
4893
++
4894
++func newTestPodBuilder() *testPodBuilder {
4895
++	builder := new(testPodBuilder)
4896
++	return builder.init()
4897
++}
4898
++
4899
++func (p *testPodBuilder) init() *testPodBuilder {
4900
++	p.pod = kapi.Pod{
4901
++		ObjectMeta: metav1.ObjectMeta{
4902
++			Name:        "pod",
4903
++			Namespace:   "namespace",
4904
++			Annotations: map[string]string{},
4905
++		},
4906
++		Spec: kapi.PodSpec{
4907
++			ServiceAccountName: "default",
4908
++			SecurityContext:    &kapi.PodSecurityContext{},
4909
++			Containers: []kapi.Container{
4910
++				{
4911
++					Name:            "test-container-1",
4912
++					SecurityContext: &kapi.SecurityContext{},
4913
++				},
4914
++			},
4915
++		},
4916
++	}
4917
++	return p
4918
++}
4919
++
4920
++func (p *testPodBuilder) build() *kapi.Pod {
4921
++	return &p.pod
4922
++}
4923
++
4924
++func (p *testPodBuilder) withNamespace(namespace string) *testPodBuilder {
4925
++	p.pod.ObjectMeta.Namespace = namespace
4926
++	return p
4927
++}
4928
++
4929
++func (p *testPodBuilder) withServiceAccount(sa string) *testPodBuilder {
4930
++	p.pod.Spec.ServiceAccountName = sa
4931
++	return p
4932
++}
4933
++
4934
++func (p *testPodBuilder) withPrivileged(v bool) *testPodBuilder {
4935
++	p.pod.Spec.Containers[0].SecurityContext.Privileged = &v
4936
++	return p
4937
++}
4938
++
4939
++func (p *testPodBuilder) withHostNetwork(v bool) *testPodBuilder {
4940
++	p.pod.Spec.SecurityContext.HostNetwork = v
4941
++	return p
4942
++}
4943
++
4944
++func (p *testPodBuilder) withHostIPC(v bool) *testPodBuilder {
4945
++	p.pod.Spec.SecurityContext.HostIPC = v
4946
++	return p
4947
++}
4948
++
4949
++func (p *testPodBuilder) withHostPID(v bool) *testPodBuilder {
4950
++	p.pod.Spec.SecurityContext.HostPID = v
4951
++	return p
4952
++}
4953
++
4954
++func (p *testPodBuilder) withHostVolume() *testPodBuilder {
4955
++	volume := kapi.Volume{
4956
++		Name: "host",
4957
++		VolumeSource: kapi.VolumeSource{
4958
++			HostPath: &kapi.HostPathVolumeSource{
4959
++				Path: "/",
4960
++			},
4961
++		},
4962
++	}
4963
++	device := kapi.VolumeDevice{Name: "host", DevicePath: "/host"}
4964
++
4965
++	p.pod.Spec.Volumes = append(p.pod.Spec.Volumes, volume)
4966
++	p.pod.Spec.Containers[0].VolumeDevices = append(p.pod.Spec.Containers[0].VolumeDevices, device)
4967
++	return p
4968
++}
4969
++
4970
++func (p *testPodBuilder) withCascadeDisk() *testPodBuilder {
4971
++	volume := kapi.Volume{
4972
++		Name: "cascadeDisk",
4973
++		VolumeSource: kapi.VolumeSource{
4974
++			PersistentVolumeClaim: &kapi.PersistentVolumeClaimVolumeSource{
4975
++				ClaimName: "00000000-0000-0000-0000-000000000001",
4976
++				ReadOnly:  false,
4977
++			},
4978
++		},
4979
++	}
4980
++	device := kapi.VolumeDevice{Name: "cascadeDisk", DevicePath: "/cascadeDisk"}
4981
++
4982
++	p.pod.Spec.Volumes = append(p.pod.Spec.Volumes, volume)
4983
++	p.pod.Spec.Containers[0].VolumeDevices = append(p.pod.Spec.Containers[0].VolumeDevices, device)
4984
++	return p
4985
++}
4986
++
4987
++func (p *testPodBuilder) withContainer() *testPodBuilder {
4988
++	container := kapi.Container{
4989
++		Name:            "test-container-2",
4990
++		SecurityContext: &kapi.SecurityContext{},
4991
++	}
4992
++
4993
++	p.pod.Spec.Containers = append(p.pod.Spec.Containers, container)
4994
++	return p
4995
++}
4996
++
4997
++func (p *testPodBuilder) withInitContainer() *testPodBuilder {
4998
++	container := kapi.Container{
4999
++		Name:            "test-init-container",
5000
++		SecurityContext: &kapi.SecurityContext{},
5001
++	}
5002
++
5003
++	p.pod.Spec.Containers = append(p.pod.Spec.Containers, container)
5004
++	return p
5005
++}
5006
++
5007
++// testUserBuilder
5008
++type testUserBuilder struct {
5009
++	user *user.DefaultInfo
5010
++}
5011
++
5012
++func newTestUserBuilder() *testUserBuilder {
5013
++	builder := new(testUserBuilder)
5014
++	return builder.init()
5015
++}
5016
++
5017
++func (p *testUserBuilder) init() *testUserBuilder {
5018
++	p.user = &user.DefaultInfo{
5019
++		Name:   "https://lightwave.cascade-cloud.com/openidconnect/00000000-0000-0000-0000-000000000001#joe@vmware.com",
5020
++		UID:    "10001",
5021
++		Groups: []string{},
5022
++	}
5023
++	return p
5024
++}
5025
++
5026
++func (p *testUserBuilder) build() *user.DefaultInfo {
5027
++	return p.user
5028
++}
5029
++
5030
++func (p *testUserBuilder) withName(name string) *testUserBuilder {
5031
++	p.user.Name = name
5032
++	return p
5033
++}
5034
++
5035
++func (p *testUserBuilder) withGroup(group string) *testUserBuilder {
5036
++	p.user.Groups = append(p.user.Groups, group)
5037
++	return p
5038
++}
5039
+diff --git a/staging/src/k8s.io/api/core/v1/generated.pb.go b/staging/src/k8s.io/api/core/v1/generated.pb.go
5040
+index 5aeae2c..a7d5b12 100644
5041
+--- a/staging/src/k8s.io/api/core/v1/generated.pb.go
5042
+@@ -35,6 +35,7 @@ limitations under the License.
4053 5043
  		Binding
4054 5044
  		CSIPersistentVolumeSource
4055 5045
  		Capabilities
... ...
@@ -4058,7 +4951,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4058 4058
  		CephFSPersistentVolumeSource
4059 4059
  		CephFSVolumeSource
4060 4060
  		CinderVolumeSource
4061
-@@ -260,9 +261,11 @@
4061
+@@ -260,9 +261,11 @@ func (m *AvoidPods) Reset()                    { *m = AvoidPods{} }
4062 4062
  func (*AvoidPods) ProtoMessage()               {}
4063 4063
  func (*AvoidPods) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} }
4064 4064
  
... ...
@@ -4073,7 +4966,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4073 4073
  
4074 4074
  func (m *AzureFilePersistentVolumeSource) Reset()      { *m = AzureFilePersistentVolumeSource{} }
4075 4075
  func (*AzureFilePersistentVolumeSource) ProtoMessage() {}
4076
-@@ -1040,6 +1043,11 @@
4076
+@@ -1040,6 +1043,11 @@ func (*WeightedPodAffinityTerm) Descriptor() ([]byte, []int) {
4077 4077
  	return fileDescriptorGenerated, []int{185}
4078 4078
  }
4079 4079
  
... ...
@@ -4085,7 +4978,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4085 4085
  func init() {
4086 4086
  	proto.RegisterType((*AWSElasticBlockStoreVolumeSource)(nil), "k8s.io.api.core.v1.AWSElasticBlockStoreVolumeSource")
4087 4087
  	proto.RegisterType((*Affinity)(nil), "k8s.io.api.core.v1.Affinity")
4088
-@@ -1051,6 +1059,7 @@
4088
+@@ -1051,6 +1059,7 @@ func init() {
4089 4089
  	proto.RegisterType((*Binding)(nil), "k8s.io.api.core.v1.Binding")
4090 4090
  	proto.RegisterType((*CSIPersistentVolumeSource)(nil), "k8s.io.api.core.v1.CSIPersistentVolumeSource")
4091 4091
  	proto.RegisterType((*Capabilities)(nil), "k8s.io.api.core.v1.Capabilities")
... ...
@@ -4093,7 +4986,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4093 4093
  	proto.RegisterType((*CephFSPersistentVolumeSource)(nil), "k8s.io.api.core.v1.CephFSPersistentVolumeSource")
4094 4094
  	proto.RegisterType((*CephFSVolumeSource)(nil), "k8s.io.api.core.v1.CephFSVolumeSource")
4095 4095
  	proto.RegisterType((*CinderVolumeSource)(nil), "k8s.io.api.core.v1.CinderVolumeSource")
4096
-@@ -1613,6 +1622,32 @@
4096
+@@ -1613,6 +1622,32 @@ func (m *Capabilities) MarshalTo(dAtA []byte) (int, error) {
4097 4097
  	return i, nil
4098 4098
  }
4099 4099
  
... ...
@@ -4126,7 +5019,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4126 4126
  func (m *CephFSPersistentVolumeSource) Marshal() (dAtA []byte, err error) {
4127 4127
  	size := m.Size()
4128 4128
  	dAtA = make([]byte, size)
4129
-@@ -6283,13 +6318,13 @@
4129
+@@ -6283,13 +6318,13 @@ func (m *PersistentVolumeSource) MarshalTo(dAtA []byte) (int, error) {
4130 4130
  		}
4131 4131
  		i += n120
4132 4132
  	}
... ...
@@ -4143,7 +5036,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4143 4143
  		if err != nil {
4144 4144
  			return 0, err
4145 4145
  		}
4146
-@@ -6367,6 +6402,18 @@
4146
+@@ -6367,6 +6402,18 @@ func (m *PersistentVolumeSource) MarshalTo(dAtA []byte) (int, error) {
4147 4147
  		}
4148 4148
  		i += n127
4149 4149
  	}
... ...
@@ -4162,7 +5055,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4162 4162
  	return i, nil
4163 4163
  }
4164 4164
  
4165
-@@ -10316,13 +10363,13 @@
4165
+@@ -10316,13 +10363,13 @@ func (m *VolumeSource) MarshalTo(dAtA []byte) (int, error) {
4166 4166
  		}
4167 4167
  		i += n223
4168 4168
  	}
... ...
@@ -4179,7 +5072,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4179 4179
  		if err != nil {
4180 4180
  			return 0, err
4181 4181
  		}
4182
-@@ -10388,6 +10435,18 @@
4182
+@@ -10388,6 +10435,18 @@ func (m *VolumeSource) MarshalTo(dAtA []byte) (int, error) {
4183 4183
  		}
4184 4184
  		i += n229
4185 4185
  	}
... ...
@@ -4198,7 +5091,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4198 4198
  	return i, nil
4199 4199
  }
4200 4200
  
4201
-@@ -10623,6 +10682,16 @@
4201
+@@ -10623,6 +10682,16 @@ func (m *Capabilities) Size() (n int) {
4202 4202
  	return n
4203 4203
  }
4204 4204
  
... ...
@@ -4215,7 +5108,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4215 4215
  func (m *CephFSPersistentVolumeSource) Size() (n int) {
4216 4216
  	var l int
4217 4217
  	_ = l
4218
-@@ -12331,8 +12400,8 @@
4218
+@@ -12331,8 +12400,8 @@ func (m *PersistentVolumeSource) Size() (n int) {
4219 4219
  		l = m.Quobyte.Size()
4220 4220
  		n += 1 + l + sovGenerated(uint64(l))
4221 4221
  	}
... ...
@@ -4226,7 +5119,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4226 4226
  		n += 2 + l + sovGenerated(uint64(l))
4227 4227
  	}
4228 4228
  	if m.PhotonPersistentDisk != nil {
4229
-@@ -12359,6 +12428,10 @@
4229
+@@ -12359,6 +12428,10 @@ func (m *PersistentVolumeSource) Size() (n int) {
4230 4230
  		l = m.CSI.Size()
4231 4231
  		n += 2 + l + sovGenerated(uint64(l))
4232 4232
  	}
... ...
@@ -4237,7 +5130,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4237 4237
  	return n
4238 4238
  }
4239 4239
  
4240
-@@ -13788,8 +13861,8 @@
4240
+@@ -13788,8 +13861,8 @@ func (m *VolumeSource) Size() (n int) {
4241 4241
  		l = m.Quobyte.Size()
4242 4242
  		n += 2 + l + sovGenerated(uint64(l))
4243 4243
  	}
... ...
@@ -4248,7 +5141,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4248 4248
  		n += 2 + l + sovGenerated(uint64(l))
4249 4249
  	}
4250 4250
  	if m.PhotonPersistentDisk != nil {
4251
-@@ -13812,6 +13885,10 @@
4251
+@@ -13812,6 +13885,10 @@ func (m *VolumeSource) Size() (n int) {
4252 4252
  		l = m.StorageOS.Size()
4253 4253
  		n += 2 + l + sovGenerated(uint64(l))
4254 4254
  	}
... ...
@@ -4259,7 +5152,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4259 4259
  	return n
4260 4260
  }
4261 4261
  
4262
-@@ -13971,6 +14048,17 @@
4262
+@@ -13971,6 +14048,17 @@ func (this *Capabilities) String() string {
4263 4263
  	}, "")
4264 4264
  	return s
4265 4265
  }
... ...
@@ -4277,7 +5170,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4277 4277
  func (this *CephFSPersistentVolumeSource) String() string {
4278 4278
  	if this == nil {
4279 4279
  		return "nil"
4280
-@@ -15335,13 +15423,14 @@
4280
+@@ -15335,13 +15423,14 @@ func (this *PersistentVolumeSource) String() string {
4281 4281
  		`AzureFile:` + strings.Replace(fmt.Sprintf("%v", this.AzureFile), "AzureFilePersistentVolumeSource", "AzureFilePersistentVolumeSource", 1) + `,`,
4282 4282
  		`VsphereVolume:` + strings.Replace(fmt.Sprintf("%v", this.VsphereVolume), "VsphereVirtualDiskVolumeSource", "VsphereVirtualDiskVolumeSource", 1) + `,`,
4283 4283
  		`Quobyte:` + strings.Replace(fmt.Sprintf("%v", this.Quobyte), "QuobyteVolumeSource", "QuobyteVolumeSource", 1) + `,`,
... ...
@@ -4293,7 +5186,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4293 4293
  		`}`,
4294 4294
  	}, "")
4295 4295
  	return s
4296
-@@ -16468,12 +16557,13 @@
4296
+@@ -16468,12 +16557,13 @@ func (this *VolumeSource) String() string {
4297 4297
  		`ConfigMap:` + strings.Replace(fmt.Sprintf("%v", this.ConfigMap), "ConfigMapVolumeSource", "ConfigMapVolumeSource", 1) + `,`,
4298 4298
  		`VsphereVolume:` + strings.Replace(fmt.Sprintf("%v", this.VsphereVolume), "VsphereVirtualDiskVolumeSource", "VsphereVirtualDiskVolumeSource", 1) + `,`,
4299 4299
  		`Quobyte:` + strings.Replace(fmt.Sprintf("%v", this.Quobyte), "QuobyteVolumeSource", "QuobyteVolumeSource", 1) + `,`,
... ...
@@ -4308,7 +5201,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4308 4308
  		`}`,
4309 4309
  	}, "")
4310 4310
  	return s
4311
-@@ -34322,7 +34412,7 @@
4311
+@@ -34322,7 +34412,7 @@ func (m *PersistentVolumeSource) Unmarshal(dAtA []byte) error {
4312 4312
  			iNdEx = postIndex
4313 4313
  		case 16:
4314 4314
  			if wireType != 2 {
... ...
@@ -4317,7 +5210,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4317 4317
  			}
4318 4318
  			var msglen int
4319 4319
  			for shift := uint(0); ; shift += 7 {
4320
-@@ -34346,10 +34436,10 @@
4320
+@@ -34346,10 +34436,10 @@ func (m *PersistentVolumeSource) Unmarshal(dAtA []byte) error {
4321 4321
  			if postIndex > l {
4322 4322
  				return io.ErrUnexpectedEOF
4323 4323
  			}
... ...
@@ -4331,7 +5224,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4331 4331
  				return err
4332 4332
  			}
4333 4333
  			iNdEx = postIndex
4334
-@@ -34551,6 +34641,39 @@
4334
+@@ -34551,6 +34641,39 @@ func (m *PersistentVolumeSource) Unmarshal(dAtA []byte) error {
4335 4335
  				return err
4336 4336
  			}
4337 4337
  			iNdEx = postIndex
... ...
@@ -4371,7 +5264,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4371 4371
  		default:
4372 4372
  			iNdEx = preIndex
4373 4373
  			skippy, err := skipGenerated(dAtA[iNdEx:])
4374
-@@ -35089,6 +35212,114 @@
4374
+@@ -35089,6 +35212,114 @@ func (m *PersistentVolumeStatus) Unmarshal(dAtA []byte) error {
4375 4375
  	}
4376 4376
  	return nil
4377 4377
  }
... ...
@@ -4486,7 +5379,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4486 4486
  func (m *PhotonPersistentDiskVolumeSource) Unmarshal(dAtA []byte) error {
4487 4487
  	l := len(dAtA)
4488 4488
  	iNdEx := 0
4489
-@@ -48522,7 +48753,7 @@
4489
+@@ -48522,7 +48753,7 @@ func (m *VolumeSource) Unmarshal(dAtA []byte) error {
4490 4490
  			iNdEx = postIndex
4491 4491
  		case 22:
4492 4492
  			if wireType != 2 {
... ...
@@ -4495,7 +5388,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4495 4495
  			}
4496 4496
  			var msglen int
4497 4497
  			for shift := uint(0); ; shift += 7 {
4498
-@@ -48546,10 +48777,10 @@
4498
+@@ -48546,10 +48777,10 @@ func (m *VolumeSource) Unmarshal(dAtA []byte) error {
4499 4499
  			if postIndex > l {
4500 4500
  				return io.ErrUnexpectedEOF
4501 4501
  			}
... ...
@@ -4509,7 +5402,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4509 4509
  				return err
4510 4510
  			}
4511 4511
  			iNdEx = postIndex
4512
-@@ -48718,6 +48949,39 @@
4512
+@@ -48718,6 +48949,39 @@ func (m *VolumeSource) Unmarshal(dAtA []byte) error {
4513 4513
  				return err
4514 4514
  			}
4515 4515
  			iNdEx = postIndex
... ...
@@ -4549,10 +5442,11 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ge
4549 4549
  		default:
4550 4550
  			iNdEx = preIndex
4551 4551
  			skippy, err := skipGenerated(dAtA[iNdEx:])
4552
-diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/types.go kubernetes-modified/src/k8s.io/kubernetes/staging/src/k8s.io/api/core/v1/types.go
4553
-+++ kubernetes-modified/src/k8s.io/kubernetes/staging/src/k8s.io/api/core/v1/types.go	2018-04-30 21:11:51.000000000 +0000
4554
-@@ -333,9 +333,8 @@
4552
+diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go
4553
+index 728cbd5..8c50888 100644
4554
+--- a/staging/src/k8s.io/api/core/v1/types.go
4555
+@@ -333,9 +333,8 @@ type VolumeSource struct {
4555 4556
  	// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
4556 4557
  	// +optional
4557 4558
  	Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty" protobuf:"bytes,21,opt,name=quobyte"`
... ...
@@ -4564,7 +5458,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ty
4564 4564
  	// PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine
4565 4565
  	PhotonPersistentDisk *PhotonPersistentDiskVolumeSource `json:"photonPersistentDisk,omitempty" protobuf:"bytes,23,opt,name=photonPersistentDisk"`
4566 4566
  	// Items for all in one resources secrets, configmaps, and downward API
4567
-@@ -349,6 +348,9 @@
4567
+@@ -349,6 +348,9 @@ type VolumeSource struct {
4568 4568
  	// StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.
4569 4569
  	// +optional
4570 4570
  	StorageOS *StorageOSVolumeSource `json:"storageos,omitempty" protobuf:"bytes,27,opt,name=storageos"`
... ...
@@ -4574,7 +5468,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ty
4574 4574
  }
4575 4575
  
4576 4576
  // PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
4577
-@@ -428,9 +430,8 @@
4577
+@@ -428,9 +430,8 @@ type PersistentVolumeSource struct {
4578 4578
  	// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
4579 4579
  	// +optional
4580 4580
  	Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty" protobuf:"bytes,15,opt,name=quobyte"`
... ...
@@ -4586,7 +5480,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ty
4586 4586
  	// PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine
4587 4587
  	PhotonPersistentDisk *PhotonPersistentDiskVolumeSource `json:"photonPersistentDisk,omitempty" protobuf:"bytes,17,opt,name=photonPersistentDisk"`
4588 4588
  	// PortworxVolume represents a portworx volume attached and mounted on kubelets host machine
4589
-@@ -449,6 +450,9 @@
4589
+@@ -449,6 +450,9 @@ type PersistentVolumeSource struct {
4590 4590
  	// CSI represents storage that handled by an external CSI driver
4591 4591
  	// +optional
4592 4592
  	CSI *CSIPersistentVolumeSource `json:"csi,omitempty" protobuf:"bytes,22,opt,name=csi"`
... ...
@@ -4596,7 +5490,7 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ty
4596 4596
  }
4597 4597
  
4598 4598
  const (
4599
-@@ -1578,6 +1582,16 @@
4599
+@@ -1578,6 +1582,16 @@ type StorageOSPersistentVolumeSource struct {
4600 4600
  	SecretRef *ObjectReference `json:"secretRef,omitempty" protobuf:"bytes,5,opt,name=secretRef"`
4601 4601
  }
4602 4602
  
... ...
@@ -4613,3 +5507,6 @@ diff -uNr --no-dereference kubernetes-original/staging/src/k8s.io/api/core/v1/ty
4613 4613
  // Adapts a ConfigMap into a volume.
4614 4614
  //
4615 4615
  // The contents of the target ConfigMap's Data field will be presented in a
4616
+-- 
4617
+2.7.4
4618
+
... ...
@@ -1,6 +1,81 @@
1
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1alpha1.json kubernetes/api/swagger-spec/apps_v1alpha1.json
2
-+++ kubernetes/api/swagger-spec/apps_v1alpha1.json	2018-05-17 00:03:37.000000000 +0000
1
+From e1297ed2ee86ca1fca087b06ae1227c1e5e4d61f Mon Sep 17 00:00:00 2001
2
+From: Bo Gan <ganb@vmware.com>
3
+Date: Sat, 2 Jun 2018 16:12:09 -0700
4
+Subject: [PATCH] Cascade Kubernetes patches for v1.10.2 (7b1ec01)
5
+
6
+---
7
+ api/swagger-spec/apps_v1alpha1.json                |  21 +
8
+ api/swagger-spec/apps_v1beta1.json                 |  21 +
9
+ api/swagger-spec/apps_v1beta2.json                 |  21 +
10
+ api/swagger-spec/batch_v1.json                     |  21 +
11
+ api/swagger-spec/batch_v1beta1.json                |  21 +
12
+ api/swagger-spec/batch_v2alpha1.json               |  21 +
13
+ api/swagger-spec/extensions_v1beta1.json           |  21 +
14
+ api/swagger-spec/settings.k8s.io_v1alpha1.json     |  21 +
15
+ api/swagger-spec/v1.json                           |  25 +
16
+ cmd/kube-controller-manager/app/BUILD              |   1 +
17
+ cmd/kube-controller-manager/app/plugins.go         |   4 +
18
+ cmd/kubelet/app/BUILD                              |   1 +
19
+ cmd/kubelet/app/plugins.go                         |   2 +
20
+ pkg/apis/core/types.go                             |  14 +
21
+ pkg/apis/core/validation/validation.go             |  29 +-
22
+ pkg/apis/extensions/types.go                       |   1 +
23
+ pkg/cloudprovider/providers/BUILD                  |   2 +
24
+ pkg/cloudprovider/providers/cascade/BUILD          |  44 ++
25
+ pkg/cloudprovider/providers/cascade/OWNERS         |   3 +
26
+ pkg/cloudprovider/providers/cascade/apitypes.go    | 227 +++++++++
27
+ pkg/cloudprovider/providers/cascade/auth.go        | 145 ++++++
28
+ pkg/cloudprovider/providers/cascade/cascade.go     | 212 ++++++++
29
+ .../providers/cascade/cascade_disks.go             | 227 +++++++++
30
+ .../providers/cascade/cascade_instances.go         |  91 ++++
31
+ .../providers/cascade/cascade_loadbalancer.go      | 285 +++++++++++
32
+ pkg/cloudprovider/providers/cascade/client.go      | 394 +++++++++++++++
33
+ pkg/cloudprovider/providers/cascade/oidcclient.go  | 297 +++++++++++
34
+ pkg/cloudprovider/providers/cascade/restclient.go  | 262 ++++++++++
35
+ pkg/cloudprovider/providers/cascade/tests_owed     |   5 +
36
+ pkg/cloudprovider/providers/cascade/utils.go       |  25 +
37
+ pkg/cloudprovider/providers/providers.go           |   1 +
38
+ pkg/kubeapiserver/options/plugins.go               |   3 +
39
+ pkg/printers/internalversion/describe.go           |  11 +
40
+ pkg/security/podsecuritypolicy/util/util.go        |   3 +
41
+ pkg/volume/cascade_disk/BUILD                      |  43 ++
42
+ pkg/volume/cascade_disk/OWNERS                     |   2 +
43
+ pkg/volume/cascade_disk/attacher.go                | 268 ++++++++++
44
+ pkg/volume/cascade_disk/cascade_disk.go            | 390 +++++++++++++++
45
+ pkg/volume/cascade_disk/cascade_util.go            | 107 ++++
46
+ .../admission/persistentvolume/label/admission.go  |  54 ++
47
+ plugin/pkg/admission/vke/BUILD                     |  58 +++
48
+ plugin/pkg/admission/vke/admission.go              | 374 ++++++++++++++
49
+ plugin/pkg/admission/vke/admission_test.go         | 541 +++++++++++++++++++++
50
+ staging/src/k8s.io/api/core/v1/generated.pb.go     | 310 +++++++++++-
51
+ staging/src/k8s.io/api/core/v1/types.go            |  24 +-
52
+ 45 files changed, 4624 insertions(+), 29 deletions(-)
53
+ create mode 100644 pkg/cloudprovider/providers/cascade/BUILD
54
+ create mode 100644 pkg/cloudprovider/providers/cascade/OWNERS
55
+ create mode 100644 pkg/cloudprovider/providers/cascade/apitypes.go
56
+ create mode 100644 pkg/cloudprovider/providers/cascade/auth.go
57
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade.go
58
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade_disks.go
59
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade_instances.go
60
+ create mode 100644 pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go
61
+ create mode 100644 pkg/cloudprovider/providers/cascade/client.go
62
+ create mode 100644 pkg/cloudprovider/providers/cascade/oidcclient.go
63
+ create mode 100644 pkg/cloudprovider/providers/cascade/restclient.go
64
+ create mode 100644 pkg/cloudprovider/providers/cascade/tests_owed
65
+ create mode 100644 pkg/cloudprovider/providers/cascade/utils.go
66
+ create mode 100644 pkg/volume/cascade_disk/BUILD
67
+ create mode 100644 pkg/volume/cascade_disk/OWNERS
68
+ create mode 100644 pkg/volume/cascade_disk/attacher.go
69
+ create mode 100644 pkg/volume/cascade_disk/cascade_disk.go
70
+ create mode 100644 pkg/volume/cascade_disk/cascade_util.go
71
+ create mode 100644 plugin/pkg/admission/vke/BUILD
72
+ create mode 100644 plugin/pkg/admission/vke/admission.go
73
+ create mode 100644 plugin/pkg/admission/vke/admission_test.go
74
+
75
+diff --git a/api/swagger-spec/apps_v1alpha1.json b/api/swagger-spec/apps_v1alpha1.json
76
+index 6f54662..bf61f93 100644
77
+--- a/api/swagger-spec/apps_v1alpha1.json
3 78
 @@ -1459,6 +1459,10 @@
4 79
       "photonPersistentDisk": {
5 80
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
... ...
@@ -12,14 +87,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1alpha1.json k
12 12
       }
13 13
      }
14 14
     },
15
-@@ -2105,6 +2109,23 @@
16
-      },
17
-      "fsType": {
18
-       "type": "string",
19
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
20
-+     }
21
-+    }
22
-+   },
15
+@@ -2109,6 +2113,23 @@
16
+      }
17
+     }
18
+    },
23 19
 +   "v1.CascadeDiskVolumeSource": {
24 20
 +    "id": "v1.CascadeDiskVolumeSource",
25 21
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -33,12 +104,17 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1alpha1.json k
33 33
 +     },
34 34
 +     "fsType": {
35 35
 +      "type": "string",
36
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
37
-      }
38
-     }
39
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1beta1.json kubernetes/api/swagger-spec/apps_v1beta1.json
40
-+++ kubernetes/api/swagger-spec/apps_v1beta1.json	2018-05-17 00:03:37.000000000 +0000
36
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
37
++     }
38
++    }
39
++   },
40
+    "v1.Container": {
41
+     "id": "v1.Container",
42
+     "description": "A single application container that you want to run within a pod.",
43
+diff --git a/api/swagger-spec/apps_v1beta1.json b/api/swagger-spec/apps_v1beta1.json
44
+index a4b090a..6e6471b 100644
45
+--- a/api/swagger-spec/apps_v1beta1.json
41 46
 @@ -4483,6 +4483,10 @@
42 47
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
43 48
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
... ...
@@ -50,14 +126,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1beta1.json ku
50 50
       "projected": {
51 51
        "$ref": "v1.ProjectedVolumeSource",
52 52
        "description": "Items for all in one resources secrets, configmaps, and downward API"
53
-@@ -5206,6 +5210,23 @@
54
-      },
55
-      "fsType": {
56
-       "type": "string",
57
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
58
-+     }
59
-+    }
60
-+   },
53
+@@ -5210,6 +5214,23 @@
54
+      }
55
+     }
56
+    },
61 57
 +   "v1.CascadeDiskVolumeSource": {
62 58
 +    "id": "v1.CascadeDiskVolumeSource",
63 59
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -71,12 +143,17 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1beta1.json ku
71 71
 +     },
72 72
 +     "fsType": {
73 73
 +      "type": "string",
74
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
75
-      }
76
-     }
77
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1beta2.json kubernetes/api/swagger-spec/apps_v1beta2.json
78
-+++ kubernetes/api/swagger-spec/apps_v1beta2.json	2018-05-17 00:03:37.000000000 +0000
74
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
75
++     }
76
++    }
77
++   },
78
+    "v1.ProjectedVolumeSource": {
79
+     "id": "v1.ProjectedVolumeSource",
80
+     "description": "Represents a projected volume source",
81
+diff --git a/api/swagger-spec/apps_v1beta2.json b/api/swagger-spec/apps_v1beta2.json
82
+index b1fcb48..b00e42e 100644
83
+--- a/api/swagger-spec/apps_v1beta2.json
79 84
 @@ -6849,6 +6849,10 @@
80 85
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
81 86
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
... ...
@@ -88,14 +165,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1beta2.json ku
88 88
       "projected": {
89 89
        "$ref": "v1.ProjectedVolumeSource",
90 90
        "description": "Items for all in one resources secrets, configmaps, and downward API"
91
-@@ -7572,6 +7576,23 @@
92
-      },
93
-      "fsType": {
94
-       "type": "string",
95
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
96
-+     }
97
-+    }
98
-+   },
91
+@@ -7576,6 +7580,23 @@
92
+      }
93
+     }
94
+    },
99 95
 +   "v1.CascadeDiskVolumeSource": {
100 96
 +    "id": "v1.CascadeDiskVolumeSource",
101 97
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -109,13 +182,18 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/apps_v1beta2.json ku
109 109
 +     },
110 110
 +     "fsType": {
111 111
 +      "type": "string",
112
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
113
-      }
114
-     }
115
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v1beta1.json kubernetes/api/swagger-spec/batch_v1beta1.json
116
-+++ kubernetes/api/swagger-spec/batch_v1beta1.json	2018-05-17 00:03:37.000000000 +0000
117
-@@ -1878,6 +1878,10 @@
112
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
113
++     }
114
++    }
115
++   },
116
+    "v1.ProjectedVolumeSource": {
117
+     "id": "v1.ProjectedVolumeSource",
118
+     "description": "Represents a projected volume source",
119
+diff --git a/api/swagger-spec/batch_v1.json b/api/swagger-spec/batch_v1.json
120
+index b6d6cea..fafdd88 100644
121
+--- a/api/swagger-spec/batch_v1.json
122
+@@ -1823,6 +1823,10 @@
118 123
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
119 124
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
120 125
       },
... ...
@@ -126,14 +204,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v1beta1.json k
126 126
       "projected": {
127 127
        "$ref": "v1.ProjectedVolumeSource",
128 128
        "description": "Items for all in one resources secrets, configmaps, and downward API"
129
-@@ -2601,6 +2605,23 @@
130
-      },
131
-      "fsType": {
132
-       "type": "string",
133
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
134
-+     }
135
-+    }
136
-+   },
129
+@@ -2550,6 +2554,23 @@
130
+      }
131
+     }
132
+    },
137 133
 +   "v1.CascadeDiskVolumeSource": {
138 134
 +    "id": "v1.CascadeDiskVolumeSource",
139 135
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -147,13 +221,18 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v1beta1.json k
147 147
 +     },
148 148
 +     "fsType": {
149 149
 +      "type": "string",
150
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
151
-      }
152
-     }
153
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v1.json kubernetes/api/swagger-spec/batch_v1.json
154
-+++ kubernetes/api/swagger-spec/batch_v1.json	2018-05-17 00:03:37.000000000 +0000
155
-@@ -1823,6 +1823,10 @@
150
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
151
++     }
152
++    }
153
++   },
154
+    "v1.ProjectedVolumeSource": {
155
+     "id": "v1.ProjectedVolumeSource",
156
+     "description": "Represents a projected volume source",
157
+diff --git a/api/swagger-spec/batch_v1beta1.json b/api/swagger-spec/batch_v1beta1.json
158
+index 32cdfc0..a91eca5 100644
159
+--- a/api/swagger-spec/batch_v1beta1.json
160
+@@ -1878,6 +1878,10 @@
156 161
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
157 162
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
158 163
       },
... ...
@@ -164,14 +243,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v1.json kubern
164 164
       "projected": {
165 165
        "$ref": "v1.ProjectedVolumeSource",
166 166
        "description": "Items for all in one resources secrets, configmaps, and downward API"
167
-@@ -2546,6 +2550,23 @@
168
-      },
169
-      "fsType": {
170
-       "type": "string",
171
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
172
-+     }
173
-+    }
174
-+   },
167
+@@ -2605,6 +2609,23 @@
168
+      }
169
+     }
170
+    },
175 171
 +   "v1.CascadeDiskVolumeSource": {
176 172
 +    "id": "v1.CascadeDiskVolumeSource",
177 173
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -185,12 +260,17 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v1.json kubern
185 185
 +     },
186 186
 +     "fsType": {
187 187
 +      "type": "string",
188
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
189
-      }
190
-     }
191
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v2alpha1.json kubernetes/api/swagger-spec/batch_v2alpha1.json
192
-+++ kubernetes/api/swagger-spec/batch_v2alpha1.json	2018-05-17 00:03:37.000000000 +0000
188
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
189
++     }
190
++    }
191
++   },
192
+    "v1.ProjectedVolumeSource": {
193
+     "id": "v1.ProjectedVolumeSource",
194
+     "description": "Represents a projected volume source",
195
+diff --git a/api/swagger-spec/batch_v2alpha1.json b/api/swagger-spec/batch_v2alpha1.json
196
+index 57acdbb..7866e56 100644
197
+--- a/api/swagger-spec/batch_v2alpha1.json
193 198
 @@ -1893,6 +1893,10 @@
194 199
       "storageos": {
195 200
        "$ref": "v1.StorageOSVolumeSource",
... ...
@@ -226,9 +306,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/batch_v2alpha1.json
226 226
     "v1.Container": {
227 227
      "id": "v1.Container",
228 228
      "description": "A single application container that you want to run within a pod.",
229
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/extensions_v1beta1.json kubernetes/api/swagger-spec/extensions_v1beta1.json
230
-+++ kubernetes/api/swagger-spec/extensions_v1beta1.json	2018-05-17 00:03:37.000000000 +0000
229
+diff --git a/api/swagger-spec/extensions_v1beta1.json b/api/swagger-spec/extensions_v1beta1.json
230
+index 6d2e049..d0c687e 100644
231
+--- a/api/swagger-spec/extensions_v1beta1.json
231 232
 @@ -7506,6 +7506,10 @@
232 233
       "storageos": {
233 234
        "$ref": "v1.StorageOSVolumeSource",
... ...
@@ -240,14 +321,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/extensions_v1beta1.j
240 240
       }
241 241
      }
242 242
     },
243
-@@ -8214,6 +8218,23 @@
244
-      },
245
-      "fsType": {
246
-       "type": "string",
247
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
248
-+     }
249
-+    }
250
-+   },
243
+@@ -8218,6 +8222,23 @@
244
+      }
245
+     }
246
+    },
251 247
 +   "v1.CascadeDiskVolumeSource": {
252 248
 +    "id": "v1.CascadeDiskVolumeSource",
253 249
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -261,12 +338,17 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/extensions_v1beta1.j
261 261
 +     },
262 262
 +     "fsType": {
263 263
 +      "type": "string",
264
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
265
-      }
266
-     }
267
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/settings.k8s.io_v1alpha1.json kubernetes/api/swagger-spec/settings.k8s.io_v1alpha1.json
268
-+++ kubernetes/api/swagger-spec/settings.k8s.io_v1alpha1.json	2018-05-17 00:03:37.000000000 +0000
264
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
265
++     }
266
++    }
267
++   },
268
+    "v1.ProjectedVolumeSource": {
269
+     "id": "v1.ProjectedVolumeSource",
270
+     "description": "Represents a projected volume source",
271
+diff --git a/api/swagger-spec/settings.k8s.io_v1alpha1.json b/api/swagger-spec/settings.k8s.io_v1alpha1.json
272
+index d4427ba..5fc467e 100644
273
+--- a/api/swagger-spec/settings.k8s.io_v1alpha1.json
269 274
 @@ -1676,6 +1676,10 @@
270 275
       "storageos": {
271 276
        "$ref": "v1.StorageOSVolumeSource",
... ...
@@ -278,14 +360,10 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/settings.k8s.io_v1al
278 278
       }
279 279
      }
280 280
     },
281
-@@ -2346,6 +2350,23 @@
282
-      },
283
-      "fsType": {
284
-       "type": "string",
285
-+      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
286
-+     }
287
-+    }
288
-+   },
281
+@@ -2350,6 +2354,23 @@
282
+      }
283
+     }
284
+    },
289 285
 +   "v1.CascadeDiskVolumeSource": {
290 286
 +    "id": "v1.CascadeDiskVolumeSource",
291 287
 +    "description": "Represents a Cascade persistent disk resource.",
... ...
@@ -299,12 +377,17 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/settings.k8s.io_v1al
299 299
 +     },
300 300
 +     "fsType": {
301 301
 +      "type": "string",
302
-       "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
303
-      }
304
-     }
305
-diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/v1.json kubernetes/api/swagger-spec/v1.json
306
-+++ kubernetes/api/swagger-spec/v1.json	2018-05-17 00:03:37.000000000 +0000
302
++      "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified."
303
++     }
304
++    }
305
++   },
306
+    "v1.ProjectedVolumeSource": {
307
+     "id": "v1.ProjectedVolumeSource",
308
+     "description": "Represents a projected volume source",
309
+diff --git a/api/swagger-spec/v1.json b/api/swagger-spec/v1.json
310
+index 3f1198e..6eaf2fa 100644
311
+--- a/api/swagger-spec/v1.json
307 312
 @@ -19310,6 +19310,10 @@
308 313
        "$ref": "v1.PhotonPersistentDiskVolumeSource",
309 314
        "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
... ...
@@ -351,10 +434,11 @@ diff -uNr --no-dereference kubernetes-orig/api/swagger-spec/v1.json kubernetes/a
351 351
       }
352 352
      }
353 353
     },
354
-diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/BUILD kubernetes/cmd/kube-controller-manager/app/BUILD
355
-+++ kubernetes/cmd/kube-controller-manager/app/BUILD	2018-05-17 00:03:37.000000000 +0000
356
-@@ -88,6 +88,7 @@
354
+diff --git a/cmd/kube-controller-manager/app/BUILD b/cmd/kube-controller-manager/app/BUILD
355
+index a3f98b1..3410214 100644
356
+--- a/cmd/kube-controller-manager/app/BUILD
357
+@@ -88,6 +88,7 @@ go_library(
357 358
          "//pkg/volume/aws_ebs:go_default_library",
358 359
          "//pkg/volume/azure_dd:go_default_library",
359 360
          "//pkg/volume/azure_file:go_default_library",
... ...
@@ -362,10 +446,11 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/BUILD
362 362
          "//pkg/volume/cinder:go_default_library",
363 363
          "//pkg/volume/csi:go_default_library",
364 364
          "//pkg/volume/fc:go_default_library",
365
-diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/plugins.go kubernetes/cmd/kube-controller-manager/app/plugins.go
366
-+++ kubernetes/cmd/kube-controller-manager/app/plugins.go	2018-05-17 00:03:37.000000000 +0000
367
-@@ -34,6 +34,7 @@
365
+diff --git a/cmd/kube-controller-manager/app/plugins.go b/cmd/kube-controller-manager/app/plugins.go
366
+index 42034d5..e729785 100644
367
+--- a/cmd/kube-controller-manager/app/plugins.go
368
+@@ -34,6 +34,7 @@ import (
368 369
  	"k8s.io/kubernetes/pkg/volume/aws_ebs"
369 370
  	"k8s.io/kubernetes/pkg/volume/azure_dd"
370 371
  	"k8s.io/kubernetes/pkg/volume/azure_file"
... ...
@@ -373,7 +458,7 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/plugi
373 373
  	"k8s.io/kubernetes/pkg/volume/cinder"
374 374
  	"k8s.io/kubernetes/pkg/volume/csi"
375 375
  	"k8s.io/kubernetes/pkg/volume/fc"
376
-@@ -77,6 +78,7 @@
376
+@@ -77,6 +78,7 @@ func ProbeAttachableVolumePlugins() []volume.VolumePlugin {
377 377
  	allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
378 378
  	allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
379 379
  	allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
... ...
@@ -381,7 +466,7 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/plugi
381 381
  	if utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
382 382
  		allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
383 383
  	}
384
-@@ -107,6 +109,7 @@
384
+@@ -107,6 +109,7 @@ func ProbeExpandableVolumePlugins(config componentconfig.VolumeConfiguration) []
385 385
  	allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
386 386
  	allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
387 387
  	allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
... ...
@@ -389,7 +474,7 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/plugi
389 389
  	return allPlugins
390 390
  }
391 391
  
392
-@@ -163,6 +166,7 @@
392
+@@ -163,6 +166,7 @@ func ProbeControllerVolumePlugins(cloud cloudprovider.Interface, config componen
393 393
  	allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
394 394
  	allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
395 395
  	allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
... ...
@@ -397,10 +482,11 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kube-controller-manager/app/plugi
397 397
  
398 398
  	return allPlugins
399 399
  }
400
-diff -uNr --no-dereference kubernetes-orig/cmd/kubelet/app/BUILD kubernetes/cmd/kubelet/app/BUILD
401
-+++ kubernetes/cmd/kubelet/app/BUILD	2018-05-17 00:03:37.000000000 +0000
402
-@@ -117,6 +117,7 @@
400
+diff --git a/cmd/kubelet/app/BUILD b/cmd/kubelet/app/BUILD
401
+index cbfb90f..6264d0c 100644
402
+--- a/cmd/kubelet/app/BUILD
403
+@@ -117,6 +117,7 @@ go_library(
403 404
          "//pkg/volume/aws_ebs:go_default_library",
404 405
          "//pkg/volume/azure_dd:go_default_library",
405 406
          "//pkg/volume/azure_file:go_default_library",
... ...
@@ -408,10 +494,11 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kubelet/app/BUILD kubernetes/cmd/
408 408
          "//pkg/volume/cephfs:go_default_library",
409 409
          "//pkg/volume/cinder:go_default_library",
410 410
          "//pkg/volume/configmap:go_default_library",
411
-diff -uNr --no-dereference kubernetes-orig/cmd/kubelet/app/plugins.go kubernetes/cmd/kubelet/app/plugins.go
412
-+++ kubernetes/cmd/kubelet/app/plugins.go	2018-05-17 00:03:37.000000000 +0000
413
-@@ -32,6 +32,7 @@
411
+diff --git a/cmd/kubelet/app/plugins.go b/cmd/kubelet/app/plugins.go
412
+index ef41bb8..c9806f7 100644
413
+--- a/cmd/kubelet/app/plugins.go
414
+@@ -32,6 +32,7 @@ import (
414 415
  	"k8s.io/kubernetes/pkg/volume/aws_ebs"
415 416
  	"k8s.io/kubernetes/pkg/volume/azure_dd"
416 417
  	"k8s.io/kubernetes/pkg/volume/azure_file"
... ...
@@ -419,7 +506,7 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kubelet/app/plugins.go kubernetes
419 419
  	"k8s.io/kubernetes/pkg/volume/cephfs"
420 420
  	"k8s.io/kubernetes/pkg/volume/cinder"
421 421
  	"k8s.io/kubernetes/pkg/volume/configmap"
422
-@@ -100,6 +101,7 @@
422
+@@ -100,6 +101,7 @@ func ProbeVolumePlugins() []volume.VolumePlugin {
423 423
  	allPlugins = append(allPlugins, scaleio.ProbeVolumePlugins()...)
424 424
  	allPlugins = append(allPlugins, local.ProbeVolumePlugins()...)
425 425
  	allPlugins = append(allPlugins, storageos.ProbeVolumePlugins()...)
... ...
@@ -427,10 +514,11 @@ diff -uNr --no-dereference kubernetes-orig/cmd/kubelet/app/plugins.go kubernetes
427 427
  	if utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
428 428
  		allPlugins = append(allPlugins, csi.ProbeVolumePlugins()...)
429 429
  	}
430
-diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/types.go kubernetes/pkg/apis/core/types.go
431
-+++ kubernetes/pkg/apis/core/types.go	2018-05-17 00:03:37.000000000 +0000
432
-@@ -316,6 +316,8 @@
430
+diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go
431
+index 8b183de..cfe4c85 100644
432
+--- a/pkg/apis/core/types.go
433
+@@ -316,6 +316,8 @@ type VolumeSource struct {
433 434
  	// StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod
434 435
  	// +optional
435 436
  	StorageOS *StorageOSVolumeSource
... ...
@@ -439,7 +527,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/types.go kubernetes/pkg
439 439
  }
440 440
  
441 441
  // Similar to VolumeSource but meant for the administrator who creates PVs.
442
-@@ -394,6 +396,8 @@
442
+@@ -394,6 +396,8 @@ type PersistentVolumeSource struct {
443 443
  	// CSI (Container Storage Interface) represents storage that handled by an external CSI driver (Beta feature).
444 444
  	// +optional
445 445
  	CSI *CSIPersistentVolumeSource
... ...
@@ -448,7 +536,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/types.go kubernetes/pkg
448 448
  }
449 449
  
450 450
  type PersistentVolumeClaimVolumeSource struct {
451
-@@ -1510,6 +1514,16 @@
451
+@@ -1510,6 +1514,16 @@ type StorageOSPersistentVolumeSource struct {
452 452
  	SecretRef *ObjectReference
453 453
  }
454 454
  
... ...
@@ -465,10 +553,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/types.go kubernetes/pkg
465 465
  // Adapts a ConfigMap into a volume.
466 466
  //
467 467
  // The contents of the target ConfigMap's Data field will be presented in a
468
-diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/validation/validation.go kubernetes/pkg/apis/core/validation/validation.go
469
-+++ kubernetes/pkg/apis/core/validation/validation.go	2018-05-17 00:03:37.000000000 +0000
470
-@@ -664,6 +664,14 @@
468
+diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go
469
+index b66fd6f..7f0e6bd 100644
470
+--- a/pkg/apis/core/validation/validation.go
471
+@@ -664,6 +664,14 @@ func validateVolumeSource(source *core.VolumeSource, fldPath *field.Path, volNam
471 472
  			allErrs = append(allErrs, validateScaleIOVolumeSource(source.ScaleIO, fldPath.Child("scaleIO"))...)
472 473
  		}
473 474
  	}
... ...
@@ -483,7 +572,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/validation/validation.g
483 483
  
484 484
  	if numVolumes == 0 {
485 485
  		allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
486
-@@ -1494,6 +1502,14 @@
486
+@@ -1494,6 +1502,14 @@ func validateCSIPersistentVolumeSource(csi *core.CSIPersistentVolumeSource, fldP
487 487
  	return allErrs
488 488
  }
489 489
  
... ...
@@ -498,7 +587,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/validation/validation.g
498 498
  // ValidatePersistentVolumeName checks that a name is appropriate for a
499 499
  // PersistentVolumeName object.
500 500
  var ValidatePersistentVolumeName = NameIsDNSSubdomain
501
-@@ -1737,6 +1753,15 @@
501
+@@ -1737,6 +1753,15 @@ func ValidatePersistentVolume(pv *core.PersistentVolume) field.ErrorList {
502 502
  		}
503 503
  	}
504 504
  
... ...
@@ -514,7 +603,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/validation/validation.g
514 514
  	if numVolumes == 0 {
515 515
  		allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
516 516
  	}
517
-@@ -4370,7 +4395,7 @@
517
+@@ -4370,7 +4395,7 @@ func ValidateSecret(secret *core.Secret) field.ErrorList {
518 518
  			allErrs = append(allErrs, field.Required(field.NewPath("metadata", "annotations").Key(core.ServiceAccountNameKey), ""))
519 519
  		}
520 520
  	case core.SecretTypeOpaque, "":
... ...
@@ -523,7 +612,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/validation/validation.g
523 523
  	case core.SecretTypeDockercfg:
524 524
  		dockercfgBytes, exists := secret.Data[core.DockerConfigKey]
525 525
  		if !exists {
526
-@@ -4416,7 +4441,7 @@
526
+@@ -4416,7 +4441,7 @@ func ValidateSecret(secret *core.Secret) field.ErrorList {
527 527
  		if _, exists := secret.Data[core.TLSPrivateKeyKey]; !exists {
528 528
  			allErrs = append(allErrs, field.Required(dataPath.Key(core.TLSPrivateKeyKey), ""))
529 529
  		}
... ...
@@ -532,10 +621,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/core/validation/validation.g
532 532
  	default:
533 533
  		// no-op
534 534
  	}
535
-diff -uNr --no-dereference kubernetes-orig/pkg/apis/extensions/types.go kubernetes/pkg/apis/extensions/types.go
536
-+++ kubernetes/pkg/apis/extensions/types.go	2018-05-17 00:03:37.000000000 +0000
537
-@@ -925,6 +925,7 @@
535
+diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go
536
+index e369728..a5406ab 100644
537
+--- a/pkg/apis/extensions/types.go
538
+@@ -925,6 +925,7 @@ var (
538 539
  	PortworxVolume        FSType = "portworxVolume"
539 540
  	ScaleIO               FSType = "scaleIO"
540 541
  	CSI                   FSType = "csi"
... ...
@@ -543,10 +633,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/apis/extensions/types.go kubernet
543 543
  	All                   FSType = "*"
544 544
  )
545 545
  
546
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/BUILD kubernetes/pkg/cloudprovider/providers/BUILD
547
-+++ kubernetes/pkg/cloudprovider/providers/BUILD	2018-05-17 00:03:37.000000000 +0000
548
-@@ -12,6 +12,7 @@
546
+diff --git a/pkg/cloudprovider/providers/BUILD b/pkg/cloudprovider/providers/BUILD
547
+index aeccfa1..4313576 100644
548
+--- a/pkg/cloudprovider/providers/BUILD
549
+@@ -12,6 +12,7 @@ go_library(
549 550
      deps = [
550 551
          "//pkg/cloudprovider/providers/aws:go_default_library",
551 552
          "//pkg/cloudprovider/providers/azure:go_default_library",
... ...
@@ -554,7 +645,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/BUILD kub
554 554
          "//pkg/cloudprovider/providers/cloudstack:go_default_library",
555 555
          "//pkg/cloudprovider/providers/gce:go_default_library",
556 556
          "//pkg/cloudprovider/providers/openstack:go_default_library",
557
-@@ -34,6 +35,7 @@
557
+@@ -34,6 +35,7 @@ filegroup(
558 558
          ":package-srcs",
559 559
          "//pkg/cloudprovider/providers/aws:all-srcs",
560 560
          "//pkg/cloudprovider/providers/azure:all-srcs",
... ...
@@ -562,9 +653,70 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/BUILD kub
562 562
          "//pkg/cloudprovider/providers/cloudstack:all-srcs",
563 563
          "//pkg/cloudprovider/providers/fake:all-srcs",
564 564
          "//pkg/cloudprovider/providers/gce:all-srcs",
565
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/apitypes.go kubernetes/pkg/cloudprovider/providers/cascade/apitypes.go
566
-+++ kubernetes/pkg/cloudprovider/providers/cascade/apitypes.go	2018-05-17 00:03:37.000000000 +0000
565
+diff --git a/pkg/cloudprovider/providers/cascade/BUILD b/pkg/cloudprovider/providers/cascade/BUILD
566
+new file mode 100644
567
+index 0000000..1ff2ad1
568
+--- /dev/null
569
+@@ -0,0 +1,44 @@
570
++package(default_visibility = ["//visibility:public"])
571
++
572
++load(
573
++    "@io_bazel_rules_go//go:def.bzl",
574
++    "go_library",
575
++)
576
++
577
++go_library(
578
++    name = "go_default_library",
579
++    srcs = [
580
++        "apitypes.go",
581
++        "auth.go",
582
++        "cascade.go",
583
++        "cascade_disks.go",
584
++        "cascade_instances.go",
585
++        "cascade_loadbalancer.go",
586
++        "client.go",
587
++        "oidcclient.go",
588
++        "restclient.go",
589
++        "utils.go"
590
++        ],
591
++    deps = [
592
++        "//pkg/api/v1/helper:go_default_library",
593
++        "//pkg/cloudprovider:go_default_library",
594
++        "//pkg/controller:go_default_library",
595
++        "//vendor/github.com/golang/glog:go_default_library",
596
++        "//vendor/gopkg.in/gcfg.v1:go_default_library",
597
++        "//vendor/k8s.io/api/core/v1:go_default_library",
598
++        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
599
++    ],
600
++)
601
++
602
++filegroup(
603
++    name = "package-srcs",
604
++    srcs = glob(["**"]),
605
++    tags = ["automanaged"],
606
++    visibility = ["//visibility:private"],
607
++)
608
++
609
++filegroup(
610
++    name = "all-srcs",
611
++    srcs = [":package-srcs"],
612
++    tags = ["automanaged"],
613
++)
614
+diff --git a/pkg/cloudprovider/providers/cascade/OWNERS b/pkg/cloudprovider/providers/cascade/OWNERS
615
+new file mode 100644
616
+index 0000000..70efc9d
617
+--- /dev/null
618
+@@ -0,0 +1,3 @@
619
++maintainers:
620
++- ashokc
621
++- ysheng
622
+diff --git a/pkg/cloudprovider/providers/cascade/apitypes.go b/pkg/cloudprovider/providers/cascade/apitypes.go
623
+new file mode 100644
624
+index 0000000..4a94068
625
+--- /dev/null
567 626
 @@ -0,0 +1,227 @@
568 627
 +package cascade
569 628
 +
... ...
@@ -793,9 +945,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/a
793 793
 +type LoadBalancerVMUpdate struct {
794 794
 +	VMIds []*LoadBalancerVM `json:"vmIds"`
795 795
 +}
796
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/auth.go kubernetes/pkg/cloudprovider/providers/cascade/auth.go
797
-+++ kubernetes/pkg/cloudprovider/providers/cascade/auth.go	2018-05-17 00:03:37.000000000 +0000
796
+diff --git a/pkg/cloudprovider/providers/cascade/auth.go b/pkg/cloudprovider/providers/cascade/auth.go
797
+new file mode 100644
798
+index 0000000..fc92377
799
+--- /dev/null
798 800
 @@ -0,0 +1,145 @@
799 801
 +package cascade
800 802
 +
... ...
@@ -943,57 +1097,229 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/a
943 943
 +	return pwd, nil
944 944
 +}
945 945
 \ No newline at end of file
946
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/BUILD kubernetes/pkg/cloudprovider/providers/cascade/BUILD
947
-+++ kubernetes/pkg/cloudprovider/providers/cascade/BUILD	2018-05-17 00:03:37.000000000 +0000
948
-@@ -0,0 +1,44 @@
949
-+package(default_visibility = ["//visibility:public"])
946
+diff --git a/pkg/cloudprovider/providers/cascade/cascade.go b/pkg/cloudprovider/providers/cascade/cascade.go
947
+new file mode 100644
948
+index 0000000..5901c58
949
+--- /dev/null
950
+@@ -0,0 +1,212 @@
951
++// The use of Cascade cloud provider requires the kubelet, kube-apiserver, and kube-controller-manager to be started
952
++// with config flag: '--cloud-provider=cascade --cloud-config=[path_to_config_file]'.
953
++package cascade
950 954
 +
951
-+load(
952
-+    "@io_bazel_rules_go//go:def.bzl",
953
-+    "go_library",
955
++import (
956
++	"context"
957
++	"errors"
958
++	"fmt"
959
++	"github.com/golang/glog"
960
++	"gopkg.in/gcfg.v1"
961
++	"io"
962
++	k8stypes "k8s.io/apimachinery/pkg/types"
963
++	"k8s.io/kubernetes/pkg/cloudprovider"
964
++	"k8s.io/kubernetes/pkg/controller"
965
++	"os"
966
++	"strings"
954 967
 +)
955 968
 +
956
-+go_library(
957
-+    name = "go_default_library",
958
-+    srcs = [
959
-+        "apitypes.go",
960
-+        "auth.go",
961
-+        "cascade.go",
962
-+        "cascade_disks.go",
963
-+        "cascade_instances.go",
964
-+        "cascade_loadbalancer.go",
965
-+        "client.go",
966
-+        "oidcclient.go",
967
-+        "restclient.go",
968
-+        "utils.go"
969
-+        ],
970
-+    deps = [
971
-+        "//pkg/api/v1/helper:go_default_library",
972
-+        "//pkg/cloudprovider:go_default_library",
973
-+        "//pkg/controller:go_default_library",
974
-+        "//vendor/github.com/golang/glog:go_default_library",
975
-+        "//vendor/gopkg.in/gcfg.v1:go_default_library",
976
-+        "//vendor/k8s.io/api/core/v1:go_default_library",
977
-+        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
978
-+    ],
969
++const (
970
++	ProviderName = "cascade"
971
++	DiskSpecKind = "persistent-disk"
972
++	MasterPrefix = "master"
979 973
 +)
980 974
 +
981
-+filegroup(
982
-+    name = "package-srcs",
983
-+    srcs = glob(["**"]),
984
-+    tags = ["automanaged"],
985
-+    visibility = ["//visibility:private"],
986
-+)
975
++// CascadeCloud is an implementation of the cloud provider interface for Cascade Controller.
976
++type CascadeCloud struct {
977
++	cfg *CascadeConfig
978
++	// Authentication client to get token for Cascade API calls
979
++	authClient *AuthClient
980
++	// API Client to make Cascade API calls
981
++	apiClient *Client
982
++	// local $HOSTNAME
983
++	localHostname string
984
++	// hostname from K8S, could be overridden
985
++	localK8sHostname string
986
++}
987 987
 +
988
-+filegroup(
989
-+    name = "all-srcs",
990
-+    srcs = [":package-srcs"],
991
-+    tags = ["automanaged"],
992
-+)
993
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/cascade_disks.go kubernetes/pkg/cloudprovider/providers/cascade/cascade_disks.go
994
-+++ kubernetes/pkg/cloudprovider/providers/cascade/cascade_disks.go	2018-05-17 00:03:37.000000000 +0000
988
++// CascadeCloud represents Cascade cloud provider's configuration.
989
++type CascadeConfig struct {
990
++	Global struct {
991
++		// the Cascade Controller endpoint
992
++		CloudTarget string `gcfg:"target"`
993
++		// Cascade Controller tenantName name
994
++		TenantName string `gcfg:"tenantName"`
995
++		// Cascade Controller cluster ID
996
++		ClusterID string `gcfg:"clusterID"`
997
++		// Authentication server endpoint for Cascade Controller
998
++		AuthEndpoint string `gcfg:"authEndpoint"`
999
++		// Lightwave domain name for the node
1000
++		DomainName string `gcfg:"domainName"`
1001
++		// DNS name of the node.
1002
++		DNSName string `gcfg:"dnsName"`
1003
++		// Region in which the cluster is in
1004
++		Region string `gcfg:"region"`
1005
++		// Availability zone in which the cluster is in
1006
++		Zone string `gcfg:"zone"`
1007
++	}
1008
++}
1009
++
1010
++// Disks is interface for manipulation with Cascade Controller Persistent Disks.
1011
++type Disks interface {
1012
++	// AttachDisk attaches given disk to given node. Current node
1013
++	// is used when nodeName is empty string.
1014
++	AttachDisk(diskID string, nodeName k8stypes.NodeName) (string, error)
1015
++
1016
++	// DetachDisk detaches given disk to given node. Current node
1017
++	// is used when nodeName is empty string.
1018
++	DetachDisk(diskID string, nodeName k8stypes.NodeName) error
1019
++
1020
++	// DiskIsAttached checks if a disk is attached to the given node.
1021
++	DiskIsAttached(diskID string, nodeName k8stypes.NodeName) (bool, error)
1022
++
1023
++	// DisksAreAttached is a batch function to check if a list of disks are attached
1024
++	// to the node with the specified NodeName.
1025
++	DisksAreAttached(diskID []string, nodeName k8stypes.NodeName) (map[string]bool, error)
1026
++
1027
++	// CreateDisk creates a new PD with given properties.
1028
++	CreateDisk(volumeOptions *VolumeOptions) (diskID string, err error)
1029
++
1030
++	// DeleteDisk deletes PD.
1031
++	DeleteDisk(diskID string) error
1032
++
1033
++	// Get labels to apply to volume on creation.
1034
++	GetVolumeLabels(diskID string) (map[string]string, error)
1035
++}
1036
++
1037
++// VolumeOptions specifies capacity, tags, name and flavorID for a volume.
1038
++type VolumeOptions struct {
1039
++	CapacityGB int
1040
++	Tags       map[string]string
1041
++	Name       string
1042
++	Flavor     string
1043
++}
1044
++
1045
++func readConfig(config io.Reader) (*CascadeConfig, error) {
1046
++	if config == nil {
1047
++		err := fmt.Errorf("Cascade Cloud Provider: config file is missing. Please restart with " +
1048
++			"--cloud-provider=cascade --cloud-config=[path_to_config_file]")
1049
++		return nil, err
1050
++	}
1051
++
1052
++	var cfg CascadeConfig
1053
++	err := gcfg.ReadInto(&cfg, config)
1054
++	return &cfg, err
1055
++}
1056
++
1057
++func init() {
1058
++	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) {
1059
++		cfg, err := readConfig(config)
1060
++		if err != nil {
1061
++			glog.Errorf("Cascade Cloud Provider: failed to read in cloud provider config file. Error[%v]", err)
1062
++			return nil, err
1063
++		}
1064
++		return newCascadeCloud(cfg)
1065
++	})
1066
++}
1067
++
1068
++func newCascadeCloud(cfg *CascadeConfig) (*CascadeCloud, error) {
1069
++	if len(cfg.Global.CloudTarget) == 0 {
1070
++		return nil, fmt.Errorf("Cascade Controller endpoint was not specified.")
1071
++	}
1072
++
1073
++	// Get local hostname
1074
++	hostname, err := os.Hostname()
1075
++	if err != nil {
1076
++		glog.Errorf("Cascade Cloud Provider: get hostname failed. Error[%v]", err)
1077
++		return nil, err
1078
++	}
1079
++
1080
++	cc := CascadeCloud{
1081
++		cfg:              cfg,
1082
++		localHostname:    hostname,
1083
++		localK8sHostname: "",
1084
++	}
1085
++
1086
++	// Instantiate the auth and API clients only on the master nodes. Kubelets running on the workers don't need them as
1087
++	// they are used primarily for making API calls to Cascade.
1088
++	if strings.HasPrefix(hostname, MasterPrefix) {
1089
++		if cc.authClient, err = NewAuthClient(cfg); err != nil {
1090
++			return nil, err
1091
++		}
1092
++
1093
++		if cc.apiClient, err = NewClient(cfg, cc.authClient); err != nil {
1094
++			return nil, err
1095
++		}
1096
++	}
1097
++
1098
++	return &cc, nil
1099
++}
1100
++
1101
++// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
1102
++func (cc *CascadeCloud) Initialize(clientBuilder controller.ControllerClientBuilder) {}
1103
++
1104
++// Instances returns an implementation of Instances for Cascade Controller.
1105
++func (cc *CascadeCloud) Instances() (cloudprovider.Instances, bool) {
1106
++	return cc, true
1107
++}
1108
++
1109
++func (cc *CascadeCloud) Clusters() (cloudprovider.Clusters, bool) {
1110
++	return nil, true
1111
++}
1112
++
1113
++// ProviderName returns the cloud provider ID.
1114
++func (cc *CascadeCloud) ProviderName() string {
1115
++	return ProviderName
1116
++}
1117
++
1118
++// LoadBalancer returns an implementation of LoadBalancer for Cascade Controller.
1119
++func (cc *CascadeCloud) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
1120
++	return cc, true
1121
++}
1122
++
1123
++// Zones returns an implementation of Zones for Cascade Controller.
1124
++func (cc *CascadeCloud) Zones() (cloudprovider.Zones, bool) {
1125
++	return cc, true
1126
++}
1127
++
1128
++func (cc *CascadeCloud) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
1129
++	return cloudprovider.Zone{
1130
++		Region:        cc.cfg.Global.Region,
1131
++		FailureDomain: cc.cfg.Global.Zone,
1132
++	}, nil
1133
++}
1134
++
1135
++// GetZoneByProviderID implements Zones.GetZoneByProviderID
1136
++// This is particularly useful in external cloud providers where the kubelet
1137
++// does not initialize node data.
1138
++func (cc *CascadeCloud) GetZoneByProviderID(ctx context.Context, providerID string) (cloudprovider.Zone, error) {
1139
++	return cloudprovider.Zone{}, errors.New("unimplemented")
1140
++}
1141
++
1142
++// GetZoneByNodeName implements Zones.GetZoneByNodeName
1143
++// This is particularly useful in external cloud providers where the kubelet
1144
++// does not initialize node data.
1145
++func (cc *CascadeCloud) GetZoneByNodeName(ctx context.Context, nodeName k8stypes.NodeName) (cloudprovider.Zone, error) {
1146
++	return cloudprovider.Zone{}, errors.New("unimeplemented")
1147
++}
1148
++
1149
++// Routes returns a false since the interface is not supported for Cascade controller.
1150
++func (cc *CascadeCloud) Routes() (cloudprovider.Routes, bool) {
1151
++	return nil, false
1152
++}
1153
++
1154
++// ScrubDNS filters DNS settings for pods.
1155
++func (cc *CascadeCloud) ScrubDNS(nameservers, searches []string) (nsOut, srchOut []string) {
1156
++	return nameservers, searches
1157
++}
1158
++
1159
++// HasClusterID returns true if the cluster has a clusterID
1160
++func (cc *CascadeCloud) HasClusterID() bool {
1161
++	return true
1162
++}
1163
+diff --git a/pkg/cloudprovider/providers/cascade/cascade_disks.go b/pkg/cloudprovider/providers/cascade/cascade_disks.go
1164
+new file mode 100644
1165
+index 0000000..7e43846
1166
+--- /dev/null
995 1167
 @@ -0,0 +1,227 @@
996 1168
 +package cascade
997 1169
 +
... ...
@@ -1222,225 +1548,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/c
1222 1222
 +
1223 1223
 +	return labels, nil
1224 1224
 +}
1225
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/cascade.go kubernetes/pkg/cloudprovider/providers/cascade/cascade.go
1226
-+++ kubernetes/pkg/cloudprovider/providers/cascade/cascade.go	2018-05-17 00:03:37.000000000 +0000
1227
-@@ -0,0 +1,212 @@
1228
-+// The use of Cascade cloud provider requires the kubelet, kube-apiserver, and kube-controller-manager to be started
1229
-+// with config flag: '--cloud-provider=cascade --cloud-config=[path_to_config_file]'.
1230
-+package cascade
1231
-+
1232
-+import (
1233
-+	"context"
1234
-+	"errors"
1235
-+	"fmt"
1236
-+	"github.com/golang/glog"
1237
-+	"gopkg.in/gcfg.v1"
1238
-+	"io"
1239
-+	k8stypes "k8s.io/apimachinery/pkg/types"
1240
-+	"k8s.io/kubernetes/pkg/cloudprovider"
1241
-+	"k8s.io/kubernetes/pkg/controller"
1242
-+	"os"
1243
-+	"strings"
1244
-+)
1245
-+
1246
-+const (
1247
-+	ProviderName = "cascade"
1248
-+	DiskSpecKind = "persistent-disk"
1249
-+	MasterPrefix = "master"
1250
-+)
1251
-+
1252
-+// CascadeCloud is an implementation of the cloud provider interface for Cascade Controller.
1253
-+type CascadeCloud struct {
1254
-+	cfg *CascadeConfig
1255
-+	// Authentication client to get token for Cascade API calls
1256
-+	authClient *AuthClient
1257
-+	// API Client to make Cascade API calls
1258
-+	apiClient *Client
1259
-+	// local $HOSTNAME
1260
-+	localHostname string
1261
-+	// hostname from K8S, could be overridden
1262
-+	localK8sHostname string
1263
-+}
1264
-+
1265
-+// CascadeCloud represents Cascade cloud provider's configuration.
1266
-+type CascadeConfig struct {
1267
-+	Global struct {
1268
-+		// the Cascade Controller endpoint
1269
-+		CloudTarget string `gcfg:"target"`
1270
-+		// Cascade Controller tenantName name
1271
-+		TenantName string `gcfg:"tenantName"`
1272
-+		// Cascade Controller cluster ID
1273
-+		ClusterID string `gcfg:"clusterID"`
1274
-+		// Authentication server endpoint for Cascade Controller
1275
-+		AuthEndpoint string `gcfg:"authEndpoint"`
1276
-+		// Lightwave domain name for the node
1277
-+		DomainName string `gcfg:"domainName"`
1278
-+		// DNS name of the node.
1279
-+		DNSName string `gcfg:"dnsName"`
1280
-+		// Region in which the cluster is in
1281
-+		Region string `gcfg:"region"`
1282
-+		// Availability zone in which the cluster is in
1283
-+		Zone string `gcfg:"zone"`
1284
-+	}
1285
-+}
1286
-+
1287
-+// Disks is interface for manipulation with Cascade Controller Persistent Disks.
1288
-+type Disks interface {
1289
-+	// AttachDisk attaches given disk to given node. Current node
1290
-+	// is used when nodeName is empty string.
1291
-+	AttachDisk(diskID string, nodeName k8stypes.NodeName) (string, error)
1292
-+
1293
-+	// DetachDisk detaches given disk to given node. Current node
1294
-+	// is used when nodeName is empty string.
1295
-+	DetachDisk(diskID string, nodeName k8stypes.NodeName) error
1296
-+
1297
-+	// DiskIsAttached checks if a disk is attached to the given node.
1298
-+	DiskIsAttached(diskID string, nodeName k8stypes.NodeName) (bool, error)
1299
-+
1300
-+	// DisksAreAttached is a batch function to check if a list of disks are attached
1301
-+	// to the node with the specified NodeName.
1302
-+	DisksAreAttached(diskID []string, nodeName k8stypes.NodeName) (map[string]bool, error)
1303
-+
1304
-+	// CreateDisk creates a new PD with given properties.
1305
-+	CreateDisk(volumeOptions *VolumeOptions) (diskID string, err error)
1306
-+
1307
-+	// DeleteDisk deletes PD.
1308
-+	DeleteDisk(diskID string) error
1309
-+
1310
-+	// Get labels to apply to volume on creation.
1311
-+	GetVolumeLabels(diskID string) (map[string]string, error)
1312
-+}
1313
-+
1314
-+// VolumeOptions specifies capacity, tags, name and flavorID for a volume.
1315
-+type VolumeOptions struct {
1316
-+	CapacityGB int
1317
-+	Tags       map[string]string
1318
-+	Name       string
1319
-+	Flavor     string
1320
-+}
1321
-+
1322
-+func readConfig(config io.Reader) (*CascadeConfig, error) {
1323
-+	if config == nil {
1324
-+		err := fmt.Errorf("Cascade Cloud Provider: config file is missing. Please restart with " +
1325
-+			"--cloud-provider=cascade --cloud-config=[path_to_config_file]")
1326
-+		return nil, err
1327
-+	}
1328
-+
1329
-+	var cfg CascadeConfig
1330
-+	err := gcfg.ReadInto(&cfg, config)
1331
-+	return &cfg, err
1332
-+}
1333
-+
1334
-+func init() {
1335
-+	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) {
1336
-+		cfg, err := readConfig(config)
1337
-+		if err != nil {
1338
-+			glog.Errorf("Cascade Cloud Provider: failed to read in cloud provider config file. Error[%v]", err)
1339
-+			return nil, err
1340
-+		}
1341
-+		return newCascadeCloud(cfg)
1342
-+	})
1343
-+}
1344
-+
1345
-+func newCascadeCloud(cfg *CascadeConfig) (*CascadeCloud, error) {
1346
-+	if len(cfg.Global.CloudTarget) == 0 {
1347
-+		return nil, fmt.Errorf("Cascade Controller endpoint was not specified.")
1348
-+	}
1349
-+
1350
-+	// Get local hostname
1351
-+	hostname, err := os.Hostname()
1352
-+	if err != nil {
1353
-+		glog.Errorf("Cascade Cloud Provider: get hostname failed. Error[%v]", err)
1354
-+		return nil, err
1355
-+	}
1356
-+
1357
-+	cc := CascadeCloud{
1358
-+		cfg:              cfg,
1359
-+		localHostname:    hostname,
1360
-+		localK8sHostname: "",
1361
-+	}
1362
-+
1363
-+	// Instantiate the auth and API clients only on the master nodes. Kubelets running on the workers don't need them as
1364
-+	// they are used primarily for making API calls to Cascade.
1365
-+	if strings.HasPrefix(hostname, MasterPrefix) {
1366
-+		if cc.authClient, err = NewAuthClient(cfg); err != nil {
1367
-+			return nil, err
1368
-+		}
1369
-+
1370
-+		if cc.apiClient, err = NewClient(cfg, cc.authClient); err != nil {
1371
-+			return nil, err
1372
-+		}
1373
-+	}
1374
-+
1375
-+	return &cc, nil
1376
-+}
1377
-+
1378
-+// Initialize passes a Kubernetes clientBuilder interface to the cloud provider
1379
-+func (cc *CascadeCloud) Initialize(clientBuilder controller.ControllerClientBuilder) {}
1380
-+
1381
-+// Instances returns an implementation of Instances for Cascade Controller.
1382
-+func (cc *CascadeCloud) Instances() (cloudprovider.Instances, bool) {
1383
-+	return cc, true
1384
-+}
1385
-+
1386
-+func (cc *CascadeCloud) Clusters() (cloudprovider.Clusters, bool) {
1387
-+	return nil, true
1388
-+}
1389
-+
1390
-+// ProviderName returns the cloud provider ID.
1391
-+func (cc *CascadeCloud) ProviderName() string {
1392
-+	return ProviderName
1393
-+}
1394
-+
1395
-+// LoadBalancer returns an implementation of LoadBalancer for Cascade Controller.
1396
-+func (cc *CascadeCloud) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
1397
-+	return cc, true
1398
-+}
1399
-+
1400
-+// Zones returns an implementation of Zones for Cascade Controller.
1401
-+func (cc *CascadeCloud) Zones() (cloudprovider.Zones, bool) {
1402
-+	return cc, true
1403
-+}
1404
-+
1405
-+func (cc *CascadeCloud) GetZone(ctx context.Context) (cloudprovider.Zone, error) {
1406
-+	return cloudprovider.Zone{
1407
-+		Region:        cc.cfg.Global.Region,
1408
-+		FailureDomain: cc.cfg.Global.Zone,
1409
-+	}, nil
1410
-+}
1411
-+
1412
-+// GetZoneByProviderID implements Zones.GetZoneByProviderID
1413
-+// This is particularly useful in external cloud providers where the kubelet
1414
-+// does not initialize node data.
1415
-+func (cc *CascadeCloud) GetZoneByProviderID(ctx context.Context, providerID string) (cloudprovider.Zone, error) {
1416
-+	return cloudprovider.Zone{}, errors.New("unimplemented")
1417
-+}
1418
-+
1419
-+// GetZoneByNodeName implements Zones.GetZoneByNodeName
1420
-+// This is particularly useful in external cloud providers where the kubelet
1421
-+// does not initialize node data.
1422
-+func (cc *CascadeCloud) GetZoneByNodeName(ctx context.Context, nodeName k8stypes.NodeName) (cloudprovider.Zone, error) {
1423
-+	return cloudprovider.Zone{}, errors.New("unimeplemented")
1424
-+}
1425
-+
1426
-+// Routes returns a false since the interface is not supported for Cascade controller.
1427
-+func (cc *CascadeCloud) Routes() (cloudprovider.Routes, bool) {
1428
-+	return nil, false
1429
-+}
1430
-+
1431
-+// ScrubDNS filters DNS settings for pods.
1432
-+func (cc *CascadeCloud) ScrubDNS(nameservers, searches []string) (nsOut, srchOut []string) {
1433
-+	return nameservers, searches
1434
-+}
1435
-+
1436
-+// HasClusterID returns true if the cluster has a clusterID
1437
-+func (cc *CascadeCloud) HasClusterID() bool {
1438
-+	return true
1439
-+}
1440
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/cascade_instances.go kubernetes/pkg/cloudprovider/providers/cascade/cascade_instances.go
1441
-+++ kubernetes/pkg/cloudprovider/providers/cascade/cascade_instances.go	2018-05-17 00:03:37.000000000 +0000
1225
+diff --git a/pkg/cloudprovider/providers/cascade/cascade_instances.go b/pkg/cloudprovider/providers/cascade/cascade_instances.go
1226
+new file mode 100644
1227
+index 0000000..58aa1b1
1228
+--- /dev/null
1442 1229
 @@ -0,0 +1,91 @@
1443 1230
 +package cascade
1444 1231
 +
... ...
@@ -1533,9 +1645,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/c
1533 1533
 +func (cc *CascadeCloud) InstanceType(ctx context.Context, nodeName k8stypes.NodeName) (string, error) {
1534 1534
 +	return "", nil
1535 1535
 +}
1536
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go kubernetes/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go
1537
-+++ kubernetes/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go	2018-05-17 00:03:37.000000000 +0000
1536
+diff --git a/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go b/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go
1537
+new file mode 100644
1538
+index 0000000..1038639
1539
+--- /dev/null
1538 1540
 @@ -0,0 +1,285 @@
1539 1541
 +package cascade
1540 1542
 +
... ...
@@ -1822,9 +1936,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/c
1822 1822
 +func (l *loadBalancerLogger) Infof(msgTemplate string, args ...interface{}) {
1823 1823
 +	glog.Infoln(l.getLogMsg(msgTemplate, args))
1824 1824
 +}
1825
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/client.go kubernetes/pkg/cloudprovider/providers/cascade/client.go
1826
-+++ kubernetes/pkg/cloudprovider/providers/cascade/client.go	2018-05-17 00:03:37.000000000 +0000
1825
+diff --git a/pkg/cloudprovider/providers/cascade/client.go b/pkg/cloudprovider/providers/cascade/client.go
1826
+new file mode 100644
1827
+index 0000000..72049e0
1828
+--- /dev/null
1827 1829
 @@ -0,0 +1,394 @@
1828 1830
 +package cascade
1829 1831
 +
... ...
@@ -2220,9 +2336,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/c
2220 2220
 +
2221 2221
 +	return errorStep
2222 2222
 +}
2223
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/oidcclient.go kubernetes/pkg/cloudprovider/providers/cascade/oidcclient.go
2224
-+++ kubernetes/pkg/cloudprovider/providers/cascade/oidcclient.go	2018-05-17 00:03:37.000000000 +0000
2223
+diff --git a/pkg/cloudprovider/providers/cascade/oidcclient.go b/pkg/cloudprovider/providers/cascade/oidcclient.go
2224
+new file mode 100644
2225
+index 0000000..6a71cc1
2226
+--- /dev/null
2225 2227
 @@ -0,0 +1,297 @@
2226 2228
 +package cascade
2227 2229
 +
... ...
@@ -2521,16 +2639,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/o
2521 2521
 +
2522 2522
 +	return oidcErr
2523 2523
 +}
2524
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/OWNERS kubernetes/pkg/cloudprovider/providers/cascade/OWNERS
2525
-+++ kubernetes/pkg/cloudprovider/providers/cascade/OWNERS	2018-05-17 00:03:37.000000000 +0000
2526
-@@ -0,0 +1,3 @@
2527
-+maintainers:
2528
-+- ashokc
2529
-+- ysheng
2530
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/restclient.go kubernetes/pkg/cloudprovider/providers/cascade/restclient.go
2531
-+++ kubernetes/pkg/cloudprovider/providers/cascade/restclient.go	2018-05-17 00:03:37.000000000 +0000
2524
+diff --git a/pkg/cloudprovider/providers/cascade/restclient.go b/pkg/cloudprovider/providers/cascade/restclient.go
2525
+new file mode 100644
2526
+index 0000000..71d8d1c
2527
+--- /dev/null
2532 2528
 @@ -0,0 +1,262 @@
2533 2529
 +package cascade
2534 2530
 +
... ...
@@ -2794,18 +2907,22 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/r
2794 2794
 +	apiError.HttpStatusCode = res.StatusCode
2795 2795
 +	return nil, apiError
2796 2796
 +}
2797
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/tests_owed kubernetes/pkg/cloudprovider/providers/cascade/tests_owed
2798
-+++ kubernetes/pkg/cloudprovider/providers/cascade/tests_owed	2018-05-17 00:03:37.000000000 +0000
2797
+diff --git a/pkg/cloudprovider/providers/cascade/tests_owed b/pkg/cloudprovider/providers/cascade/tests_owed
2798
+new file mode 100644
2799
+index 0000000..dff5ab1
2800
+--- /dev/null
2799 2801
 @@ -0,0 +1,5 @@
2800 2802
 +
2801 2803
 +Yu Sheng
2802 2804
 +Change-Id: Ifc11818f65a3e018aeea6988d9e2c0719b592920
2803 2805
 +
2804 2806
 +
2805
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/utils.go kubernetes/pkg/cloudprovider/providers/cascade/utils.go
2806
-+++ kubernetes/pkg/cloudprovider/providers/cascade/utils.go	2018-05-17 00:03:37.000000000 +0000
2807
+diff --git a/pkg/cloudprovider/providers/cascade/utils.go b/pkg/cloudprovider/providers/cascade/utils.go
2808
+new file mode 100644
2809
+index 0000000..4e9e44c
2810
+--- /dev/null
2807 2811
 @@ -0,0 +1,25 @@
2808 2812
 +package cascade
2809 2813
 +
... ...
@@ -2833,10 +2950,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/cascade/u
2833 2833
 +	return &s
2834 2834
 +}
2835 2835
 \ No newline at end of file
2836
-diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/providers.go kubernetes/pkg/cloudprovider/providers/providers.go
2837
-+++ kubernetes/pkg/cloudprovider/providers/providers.go	2018-05-17 00:03:37.000000000 +0000
2838
-@@ -20,6 +20,7 @@
2836
+diff --git a/pkg/cloudprovider/providers/providers.go b/pkg/cloudprovider/providers/providers.go
2837
+index 7de9ca9..6d8a1d2 100644
2838
+--- a/pkg/cloudprovider/providers/providers.go
2839
+@@ -20,6 +20,7 @@ import (
2839 2840
  	// Cloud providers
2840 2841
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
2841 2842
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
... ...
@@ -2844,10 +2962,39 @@ diff -uNr --no-dereference kubernetes-orig/pkg/cloudprovider/providers/providers
2844 2844
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/cloudstack"
2845 2845
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
2846 2846
  	_ "k8s.io/kubernetes/pkg/cloudprovider/providers/openstack"
2847
-diff -uNr --no-dereference kubernetes-orig/pkg/printers/internalversion/describe.go kubernetes/pkg/printers/internalversion/describe.go
2848
-+++ kubernetes/pkg/printers/internalversion/describe.go	2018-05-17 00:03:37.000000000 +0000
2849
-@@ -754,6 +754,8 @@
2847
+diff --git a/pkg/kubeapiserver/options/plugins.go b/pkg/kubeapiserver/options/plugins.go
2848
+index 75095b2..0914847 100644
2849
+--- a/pkg/kubeapiserver/options/plugins.go
2850
+@@ -58,6 +58,7 @@ import (
2851
+ 	"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
2852
+ 	mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
2853
+ 	validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
2854
++	"k8s.io/kubernetes/plugin/pkg/admission/vke"
2855
+ )
2856
+ 
2857
+ // AllOrderedPlugins is the list of all the plugins in order.
2858
+@@ -93,6 +94,7 @@ var AllOrderedPlugins = []string{
2859
+ 	initialization.PluginName,               // Initializers
2860
+ 	validatingwebhook.PluginName,            // ValidatingAdmissionWebhook
2861
+ 	resourcequota.PluginName,                // ResourceQuota
2862
++	vke.PluginName,                          // VMwareAdmissionController
2863
+ 	deny.PluginName,                         // AlwaysDeny
2864
+ }
2865
+ 
2866
+@@ -126,6 +128,7 @@ func RegisterAllAdmissionPlugins(plugins *admission.Plugins) {
2867
+ 	setdefault.Register(plugins)
2868
+ 	resize.Register(plugins)
2869
+ 	storageobjectinuseprotection.Register(plugins)
2870
++	vke.Register(plugins)
2871
+ }
2872
+ 
2873
+ // DefaultOffAdmissionPlugins get admission plugins off by default for kube-apiserver.
2874
+diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go
2875
+index 318148d..994f6ec 100644
2876
+--- a/pkg/printers/internalversion/describe.go
2877
+@@ -754,6 +754,8 @@ func describeVolumes(volumes []api.Volume, w PrefixWriter, space string) {
2850 2878
  			printFlexVolumeSource(volume.VolumeSource.FlexVolume, w)
2851 2879
  		case volume.VolumeSource.Flocker != nil:
2852 2880
  			printFlockerVolumeSource(volume.VolumeSource.Flocker, w)
... ...
@@ -2856,7 +3003,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/printers/internalversion/describe
2856 2856
  		default:
2857 2857
  			w.Write(LEVEL_1, "<unknown>\n")
2858 2858
  		}
2859
-@@ -1114,6 +1116,13 @@
2859
+@@ -1114,6 +1116,13 @@ func printCSIPersistentVolumeSource(csi *api.CSIPersistentVolumeSource, w Prefix
2860 2860
  		csi.Driver, csi.VolumeHandle, csi.ReadOnly)
2861 2861
  }
2862 2862
  
... ...
@@ -2870,7 +3017,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/printers/internalversion/describe
2870 2870
  type PersistentVolumeDescriber struct {
2871 2871
  	clientset.Interface
2872 2872
  }
2873
-@@ -1250,6 +1259,8 @@
2873
+@@ -1250,6 +1259,8 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
2874 2874
  			printFlockerVolumeSource(pv.Spec.Flocker, w)
2875 2875
  		case pv.Spec.CSI != nil:
2876 2876
  			printCSIPersistentVolumeSource(pv.Spec.CSI, w)
... ...
@@ -2879,10 +3026,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/printers/internalversion/describe
2879 2879
  		default:
2880 2880
  			w.Write(LEVEL_1, "<unknown>\n")
2881 2881
  		}
2882
-diff -uNr --no-dereference kubernetes-orig/pkg/security/podsecuritypolicy/util/util.go kubernetes/pkg/security/podsecuritypolicy/util/util.go
2883
-+++ kubernetes/pkg/security/podsecuritypolicy/util/util.go	2018-05-17 00:03:37.000000000 +0000
2884
-@@ -68,6 +68,7 @@
2882
+diff --git a/pkg/security/podsecuritypolicy/util/util.go b/pkg/security/podsecuritypolicy/util/util.go
2883
+index d581f50..bfd21b1 100644
2884
+--- a/pkg/security/podsecuritypolicy/util/util.go
2885
+@@ -68,6 +68,7 @@ func GetAllFSTypesAsSet() sets.String {
2885 2886
  		string(extensions.PortworxVolume),
2886 2887
  		string(extensions.ScaleIO),
2887 2888
  		string(extensions.CSI),
... ...
@@ -2890,7 +3038,7 @@ diff -uNr --no-dereference kubernetes-orig/pkg/security/podsecuritypolicy/util/u
2890 2890
  	)
2891 2891
  	return fstypes
2892 2892
  }
2893
-@@ -129,6 +130,8 @@
2893
+@@ -129,6 +130,8 @@ func GetVolumeFSType(v api.Volume) (extensions.FSType, error) {
2894 2894
  		return extensions.PortworxVolume, nil
2895 2895
  	case v.ScaleIO != nil:
2896 2896
  		return extensions.ScaleIO, nil
... ...
@@ -2899,9 +3047,68 @@ diff -uNr --no-dereference kubernetes-orig/pkg/security/podsecuritypolicy/util/u
2899 2899
  	}
2900 2900
  
2901 2901
  	return "", fmt.Errorf("unknown volume type for volume: %#v", v)
2902
-diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/attacher.go kubernetes/pkg/volume/cascade_disk/attacher.go
2903
-+++ kubernetes/pkg/volume/cascade_disk/attacher.go	2018-05-17 00:03:37.000000000 +0000
2902
+diff --git a/pkg/volume/cascade_disk/BUILD b/pkg/volume/cascade_disk/BUILD
2903
+new file mode 100644
2904
+index 0000000..3386612
2905
+--- /dev/null
2906
+@@ -0,0 +1,43 @@
2907
++package(default_visibility = ["//visibility:public"])
2908
++
2909
++load(
2910
++    "@io_bazel_rules_go//go:def.bzl",
2911
++    "go_library",
2912
++    "go_test",
2913
++)
2914
++
2915
++go_library(
2916
++    name = "go_default_library",
2917
++    srcs = [
2918
++        "attacher.go",
2919
++        "cascade_disk.go",
2920
++        "cascade_util.go",
2921
++    ],
2922
++    deps = [
2923
++        "//pkg/cloudprovider:go_default_library",
2924
++        "//pkg/cloudprovider/providers/cascade:go_default_library",
2925
++        "//pkg/util/mount:go_default_library",
2926
++        "//pkg/util/strings:go_default_library",
2927
++        "//pkg/volume:go_default_library",
2928
++        "//pkg/volume/util:go_default_library",
2929
++        "//pkg/volume/util/volumehelper:go_default_library",
2930
++        "//vendor/github.com/golang/glog:go_default_library",
2931
++        "//vendor/k8s.io/api/core/v1:go_default_library",
2932
++        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
2933
++        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2934
++        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
2935
++    ],
2936
++)
2937
++
2938
++filegroup(
2939
++    name = "package-srcs",
2940
++    srcs = glob(["**"]),
2941
++    tags = ["automanaged"],
2942
++    visibility = ["//visibility:private"],
2943
++)
2944
++
2945
++filegroup(
2946
++    name = "all-srcs",
2947
++    srcs = [":package-srcs"],
2948
++    tags = ["automanaged"],
2949
++)
2950
+diff --git a/pkg/volume/cascade_disk/OWNERS b/pkg/volume/cascade_disk/OWNERS
2951
+new file mode 100644
2952
+index 0000000..c3a4ed7
2953
+--- /dev/null
2954
+@@ -0,0 +1,2 @@
2955
++maintainers:
2956
++- ashokc
2957
+diff --git a/pkg/volume/cascade_disk/attacher.go b/pkg/volume/cascade_disk/attacher.go
2958
+new file mode 100644
2959
+index 0000000..80d8d3a
2960
+--- /dev/null
2904 2961
 @@ -0,0 +1,268 @@
2905 2962
 +package cascade_disk
2906 2963
 +
... ...
@@ -3171,56 +3378,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/attacher.go k
3171 3171
 +func (detacher *cascadeDiskDetacher) UnmountDevice(deviceMountPath string) error {
3172 3172
 +	return volumeutil.UnmountPath(deviceMountPath, detacher.mounter)
3173 3173
 +}
3174
-diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/BUILD kubernetes/pkg/volume/cascade_disk/BUILD
3175
-+++ kubernetes/pkg/volume/cascade_disk/BUILD	2018-05-17 00:03:37.000000000 +0000
3176
-@@ -0,0 +1,43 @@
3177
-+package(default_visibility = ["//visibility:public"])
3178
-+
3179
-+load(
3180
-+    "@io_bazel_rules_go//go:def.bzl",
3181
-+    "go_library",
3182
-+    "go_test",
3183
-+)
3184
-+
3185
-+go_library(
3186
-+    name = "go_default_library",
3187
-+    srcs = [
3188
-+        "attacher.go",
3189
-+        "cascade_disk.go",
3190
-+        "cascade_util.go",
3191
-+    ],
3192
-+    deps = [
3193
-+        "//pkg/cloudprovider:go_default_library",
3194
-+        "//pkg/cloudprovider/providers/cascade:go_default_library",
3195
-+        "//pkg/util/mount:go_default_library",
3196
-+        "//pkg/util/strings:go_default_library",
3197
-+        "//pkg/volume:go_default_library",
3198
-+        "//pkg/volume/util:go_default_library",
3199
-+        "//pkg/volume/util/volumehelper:go_default_library",
3200
-+        "//vendor/github.com/golang/glog:go_default_library",
3201
-+        "//vendor/k8s.io/api/core/v1:go_default_library",
3202
-+        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
3203
-+        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
3204
-+        "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
3205
-+    ],
3206
-+)
3207
-+
3208
-+filegroup(
3209
-+    name = "package-srcs",
3210
-+    srcs = glob(["**"]),
3211
-+    tags = ["automanaged"],
3212
-+    visibility = ["//visibility:private"],
3213
-+)
3214
-+
3215
-+filegroup(
3216
-+    name = "all-srcs",
3217
-+    srcs = [":package-srcs"],
3218
-+    tags = ["automanaged"],
3219
-+)
3220
-diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/cascade_disk.go kubernetes/pkg/volume/cascade_disk/cascade_disk.go
3221
-+++ kubernetes/pkg/volume/cascade_disk/cascade_disk.go	2018-05-17 00:03:37.000000000 +0000
3174
+diff --git a/pkg/volume/cascade_disk/cascade_disk.go b/pkg/volume/cascade_disk/cascade_disk.go
3175
+new file mode 100644
3176
+index 0000000..769c876
3177
+--- /dev/null
3222 3178
 @@ -0,0 +1,390 @@
3223 3179
 +package cascade_disk
3224 3180
 +
... ...
@@ -3612,9 +3774,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/cascade_disk.
3612 3612
 +
3613 3613
 +	return nil, false, fmt.Errorf("Spec does not reference a Cascade disk type")
3614 3614
 +}
3615
-diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/cascade_util.go kubernetes/pkg/volume/cascade_disk/cascade_util.go
3616
-+++ kubernetes/pkg/volume/cascade_disk/cascade_util.go	2018-05-17 00:03:37.000000000 +0000
3615
+diff --git a/pkg/volume/cascade_disk/cascade_util.go b/pkg/volume/cascade_disk/cascade_util.go
3616
+new file mode 100644
3617
+index 0000000..19ddb7f
3618
+--- /dev/null
3617 3619
 @@ -0,0 +1,107 @@
3618 3620
 +package cascade_disk
3619 3621
 +
... ...
@@ -3723,16 +3887,11 @@ diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/cascade_util.
3723 3723
 +	}
3724 3724
 +	return cc, nil
3725 3725
 +}
3726
-diff -uNr --no-dereference kubernetes-orig/pkg/volume/cascade_disk/OWNERS kubernetes/pkg/volume/cascade_disk/OWNERS
3727
-+++ kubernetes/pkg/volume/cascade_disk/OWNERS	2018-05-17 00:03:37.000000000 +0000
3728
-@@ -0,0 +1,2 @@
3729
-+maintainers:
3730
-+- ashokc
3731
-diff -uNr --no-dereference kubernetes-orig/plugin/pkg/admission/persistentvolume/label/admission.go kubernetes/plugin/pkg/admission/persistentvolume/label/admission.go
3732
-+++ kubernetes/plugin/pkg/admission/persistentvolume/label/admission.go	2018-05-17 00:03:37.000000000 +0000
3733
-@@ -27,6 +27,7 @@
3726
+diff --git a/plugin/pkg/admission/persistentvolume/label/admission.go b/plugin/pkg/admission/persistentvolume/label/admission.go
3727
+index 819adae..ef72cf5 100644
3728
+--- a/plugin/pkg/admission/persistentvolume/label/admission.go
3729
+@@ -27,6 +27,7 @@ import (
3734 3730
  	api "k8s.io/kubernetes/pkg/apis/core"
3735 3731
  	"k8s.io/kubernetes/pkg/cloudprovider"
3736 3732
  	"k8s.io/kubernetes/pkg/cloudprovider/providers/aws"
... ...
@@ -3740,7 +3899,7 @@ diff -uNr --no-dereference kubernetes-orig/plugin/pkg/admission/persistentvolume
3740 3740
  	"k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
3741 3741
  	kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
3742 3742
  	kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
3743
-@@ -52,6 +53,7 @@
3743
+@@ -52,6 +53,7 @@ type persistentVolumeLabel struct {
3744 3744
  	ebsVolumes       aws.Volumes
3745 3745
  	cloudConfig      []byte
3746 3746
  	gceCloudProvider *gce.GCECloud
... ...
@@ -3748,7 +3907,7 @@ diff -uNr --no-dereference kubernetes-orig/plugin/pkg/admission/persistentvolume
3748 3748
  }
3749 3749
  
3750 3750
  var _ admission.MutationInterface = &persistentVolumeLabel{}
3751
-@@ -104,6 +106,13 @@
3751
+@@ -104,6 +106,13 @@ func (l *persistentVolumeLabel) Admit(a admission.Attributes) (err error) {
3752 3752
  		}
3753 3753
  		volumeLabels = labels
3754 3754
  	}
... ...
@@ -3762,7 +3921,7 @@ diff -uNr --no-dereference kubernetes-orig/plugin/pkg/admission/persistentvolume
3762 3762
  
3763 3763
  	if len(volumeLabels) != 0 {
3764 3764
  		if volume.Labels == nil {
3765
-@@ -216,3 +225,48 @@
3765
+@@ -216,3 +225,48 @@ func (l *persistentVolumeLabel) getGCECloudProvider() (*gce.GCECloud, error) {
3766 3766
  	}
3767 3767
  	return l.gceCloudProvider, nil
3768 3768
  }
... ...
@@ -3811,10 +3970,1003 @@ diff -uNr --no-dereference kubernetes-orig/plugin/pkg/admission/persistentvolume
3811 3811
 +	}
3812 3812
 +	return l.cascadeDisks, nil
3813 3813
 +}
3814
-diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/generated.pb.go kubernetes/staging/src/k8s.io/api/core/v1/generated.pb.go
3815
-+++ kubernetes/staging/src/k8s.io/api/core/v1/generated.pb.go	2018-05-17 00:03:37.000000000 +0000
3816
-@@ -35,6 +35,7 @@
3814
+diff --git a/plugin/pkg/admission/vke/BUILD b/plugin/pkg/admission/vke/BUILD
3815
+new file mode 100644
3816
+index 0000000..b0a6026
3817
+--- /dev/null
3818
+@@ -0,0 +1,58 @@
3819
++package(default_visibility = ["//visibility:public"])
3820
++
3821
++load(
3822
++    "@io_bazel_rules_go//go:def.bzl",
3823
++    "go_library",
3824
++)
3825
++
3826
++go_library(
3827
++    name = "go_default_library",
3828
++    srcs = ["admission.go"],
3829
++    importpath = "k8s.io/kubernetes/plugin/pkg/admission/vke",
3830
++    deps = [
3831
++        "//pkg/apis/core:go_default_library",
3832
++        "//pkg/apis/extensions:go_default_library",
3833
++        "//pkg/apis/rbac:go_default_library",
3834
++        "//pkg/registry/rbac:go_default_library",
3835
++        "//pkg/security/podsecuritypolicy:go_default_library",
3836
++        "//vendor/github.com/golang/glog:go_default_library",
3837
++        "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
3838
++        "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
3839
++        "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
3840
++        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
3841
++        "//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
3842
++    ],
3843
++)
3844
++
3845
++go_test(
3846
++    name = "go_default_test",
3847
++    srcs = ["admission_test.go"],
3848
++    embed = [":go_default_library"],
3849
++    deps = [
3850
++        "//pkg/apis/core:go_default_library",
3851
++        "//pkg/apis/extensions:go_default_library",
3852
++        "//pkg/apis/rbac:go_default_library",
3853
++        "//pkg/registry/rbac:go_default_library",
3854
++        "//pkg/security/podsecuritypolicy:go_default_library",
3855
++        "//vendor/github.com/golang/glog:go_default_library",
3856
++        "//vendor/github.com/stretchr/testify/assert:go_default_library",
3857
++        "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
3858
++        "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
3859
++        "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
3860
++        "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
3861
++        "//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
3862
++    ],
3863
++)
3864
++
3865
++filegroup(
3866
++    name = "package-srcs",
3867
++    srcs = glob(["**"]),
3868
++    tags = ["automanaged"],
3869
++    visibility = ["//visibility:private"],
3870
++)
3871
++
3872
++filegroup(
3873
++    name = "all-srcs",
3874
++    srcs = [":package-srcs"],
3875
++    tags = ["automanaged"],
3876
++)
3877
+\ No newline at end of file
3878
+diff --git a/plugin/pkg/admission/vke/admission.go b/plugin/pkg/admission/vke/admission.go
3879
+new file mode 100644
3880
+index 0000000..e029ce6
3881
+--- /dev/null
3882
+@@ -0,0 +1,374 @@
3883
++package vke
3884
++
3885
++import (
3886
++	"fmt"
3887
++	"io"
3888
++	"strings"
3889
++
3890
++	"github.com/golang/glog"
3891
++	apiequality "k8s.io/apimachinery/pkg/api/equality"
3892
++	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3893
++	"k8s.io/apimachinery/pkg/util/validation/field"
3894
++	"k8s.io/apimachinery/pkg/util/yaml"
3895
++	"k8s.io/apiserver/pkg/admission"
3896
++	api "k8s.io/kubernetes/pkg/apis/core"
3897
++	"k8s.io/kubernetes/pkg/apis/extensions"
3898
++	"k8s.io/kubernetes/pkg/apis/rbac"
3899
++	rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
3900
++	"k8s.io/kubernetes/pkg/security/podsecuritypolicy"
3901
++)
3902
++
3903
++const (
3904
++	// PluginName indicates name of admission plugin.
3905
++	PluginName = "VMwareAdmissionController"
3906
++
3907
++	systemUnsecuredUser      = "system:unsecured"
3908
++	privilegedNamespace      = "vke-system"
3909
++	privilegedServiceAccount = "system:serviceaccount:" + privilegedNamespace + ":"
3910
++	reservedPrefix           = "vke"
3911
++	kubeletGroup             = "system:nodes"
3912
++	kubeProxyGroup           = "cascade:kube-proxies"
3913
++	dashboardPod             = "vke-dashboard-0"
3914
++	kubeSystemNamespace      = "kube-system"
3915
++)
3916
++
3917
++// Register registers a plugin.
3918
++func Register(plugins *admission.Plugins) {
3919
++	plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
3920
++		return NewVMwareAdmissionController(config)
3921
++	})
3922
++}
3923
++
3924
++// vmwareAdmissionController is an implementation of admission.Interface.
3925
++// It restricts access to VKE namespace for users and prevents the users from creating privileged pods.
3926
++type vmwareAdmissionController struct {
3927
++	psp             *extensions.PodSecurityPolicy
3928
++	strategyFactory podsecuritypolicy.StrategyFactory
3929
++	privilegedGroup string
3930
++}
3931
++
3932
++// vmwareAdmissionControllerConfig holds config data for VMwareAdmissionController.
3933
++type vmwareAdmissionControllerConfig struct {
3934
++	PrivilegedGroup string `yaml:"privilegedGroup"`
3935
++}
3936
++
3937
++// AdmissionConfig holds config data for admission controllers.
3938
++type AdmissionConfig struct {
3939
++	VMwareAdmissionController vmwareAdmissionControllerConfig `yaml:"vmwareAdmissionController"`
3940
++}
3941
++
3942
++var _ admission.ValidationInterface = &vmwareAdmissionController{}
3943
++
3944
++// Validate makes an admission decision based on the request attributes.  It is NOT allowed to mutate.
3945
++func (vac *vmwareAdmissionController) Validate(a admission.Attributes) (err error) {
3946
++	if isPrivilegedUser(vac, a) {
3947
++		return nil
3948
++	}
3949
++
3950
++	if isSystemUnsecuredUser(a) {
3951
++		return validateSystemUnsecuredUser(vac, a)
3952
++	}
3953
++
3954
++	if isPrivilegedNamespace(a) {
3955
++		return admission.NewForbidden(a,
3956
++			fmt.Errorf("%s validation failed: cannot modify resources in namespace %s", PluginName, a.GetNamespace()))
3957
++	}
3958
++
3959
++	switch a.GetResource().GroupResource() {
3960
++	case api.Resource("pods"):
3961
++		err = validatePods(vac, a)
3962
++	case api.Resource("nodes"):
3963
++		err = admission.NewForbidden(a, fmt.Errorf("%s validation failed: cannot modify nodes", PluginName))
3964
++	case rbac.Resource("clusterroles"):
3965
++		err = validateClusterRoles(a)
3966
++	case rbac.Resource("clusterrolebindings"):
3967
++		err = validateClusterRoleBindings(a)
3968
++	}
3969
++
3970
++	return err
3971
++}
3972
++
3973
++// Handles returns true if this admission controller can handle the given operation
3974
++// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT.
3975
++func (vac *vmwareAdmissionController) Handles(operation admission.Operation) bool {
3976
++	return true
3977
++}
3978
++
3979
++// NewVMwareAdmissionController creates a new VMwareAdmissionController.
3980
++func NewVMwareAdmissionController(configFile io.Reader) (*vmwareAdmissionController, error) {
3981
++	glog.V(2).Infof("%s is enabled", PluginName)
3982
++	if configFile == nil {
3983
++		glog.Warningf("No config specified for %s. Using default configuration", PluginName)
3984
++		return nil, fmt.Errorf("no config file specified for %s", PluginName)
3985
++	}
3986
++
3987
++	var config AdmissionConfig
3988
++	d := yaml.NewYAMLOrJSONDecoder(configFile, 4096)
3989
++	err := d.Decode(&config)
3990
++	if err != nil {
3991
++		return nil, err
3992
++	}
3993
++
3994
++	return &vmwareAdmissionController{
3995
++		psp:             getDefaultPSP(),
3996
++		strategyFactory: podsecuritypolicy.NewSimpleStrategyFactory(),
3997
++		privilegedGroup: config.VMwareAdmissionController.PrivilegedGroup,
3998
++	}, nil
3999
++}
4000
++
4001
++func getDefaultPSP() *extensions.PodSecurityPolicy {
4002
++	return &extensions.PodSecurityPolicy{
4003
++		TypeMeta: metav1.TypeMeta{
4004
++			Kind:       "PodSecurityPolicy",
4005
++			APIVersion: "extensions/v1beta1",
4006
++		},
4007
++		Spec: extensions.PodSecurityPolicySpec{
4008
++			Privileged:               false,
4009
++			HostNetwork:              false,
4010
++			HostIPC:                  false,
4011
++			HostPID:                  false,
4012
++			AllowPrivilegeEscalation: false,
4013
++			Volumes: []extensions.FSType{
4014
++				"emptyDir",
4015
++				"secret",
4016
++				"downwardAPI",
4017
++				"configMap",
4018
++				"persistentVolumeClaim",
4019
++				"projected",
4020
++			},
4021
++			FSGroup: extensions.FSGroupStrategyOptions{
4022
++				Rule: extensions.FSGroupStrategyRunAsAny,
4023
++			},
4024
++			RunAsUser: extensions.RunAsUserStrategyOptions{
4025
++				Rule: extensions.RunAsUserStrategyRunAsAny,
4026
++			},
4027
++			SELinux: extensions.SELinuxStrategyOptions{
4028
++				Rule: extensions.SELinuxStrategyRunAsAny,
4029
++			},
4030
++			SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
4031
++				Rule: extensions.SupplementalGroupsStrategyRunAsAny,
4032
++			},
4033
++		},
4034
++	}
4035
++}
4036
++
4037
++func isPrivilegedUser(vac *vmwareAdmissionController, a admission.Attributes) bool {
4038
++	// We need to allow the service accounts inside the privileged namespace to be able to access pods and nodes.
4039
++	// Node-monitor agent, Photon OS update controller and Cluster autoscaler depend on this.
4040
++	user := a.GetUserInfo().GetName()
4041
++	if strings.HasPrefix(user, privilegedServiceAccount) {
4042
++		return true
4043
++	}
4044
++
4045
++	// If the request comes from a user belonging to a privileged group, then we allow it. Only calls from Cascade
4046
++	// controller will belong to this privileged group.
4047
++	// If the request comes from kubelet or kube-proxy, we allow those too. We don't want to prevent kubelet from being
4048
++	// able to create a privileged pod or update nodes. The same way we don't want to prevent kube-proxy from creating
4049
++	// events.
4050
++	groups := a.GetUserInfo().GetGroups()
4051
++	for _, group := range groups {
4052
++		if group == vac.privilegedGroup || group == kubeletGroup || group == kubeProxyGroup {
4053
++			return true
4054
++		}
4055
++	}
4056
++
4057
++	return false
4058
++}
4059
++
4060
++func isSystemUnsecuredUser(a admission.Attributes) bool {
4061
++	return a.GetUserInfo().GetName() == systemUnsecuredUser
4062
++}
4063
++
4064
++func validateSystemUnsecuredUser(vac *vmwareAdmissionController, a admission.Attributes) (err error) {
4065
++	// Currently the insecure port 8080 is exposed to only localhost inside the Kubernetes master VMs. So it can be used
4066
++	// only by kube-controller-manager, kube-scheduler and cloud-init script which creates our pods and other resources.
4067
++	// When a call comes on insecure port 8080, Kubernetes assigns them system:unsecured user name. We need to allow
4068
++	// this so that our master components can be started successfully and kube-controller-manager and kube-scheduler can
4069
++	// work as expected.
4070
++	// But this needs to be allowed only inside our privileged namespace. If the request comes to any other namespace,
4071
++	// we need to make it go through our pod validation. This is needed because a user can create a deployment or
4072
++	// replica set which has a privileged pod. Since our admission controller does not look at deployments or replica
4073
++	// sets, we will allow it. The actual pod inside the deployment or replica set will be created by the
4074
++	// controller-manager and if we allow it to create pods in any namespace, then a user can create a privileged pod
4075
++	// totally bypassing our security checks.
4076
++	if !isPrivilegedNamespace(a) && (a.GetResource().GroupResource() == api.Resource("pods")) {
4077
++		return validatePods(vac, a)
4078
++	}
4079
++
4080
++	// For all other resources, allow.
4081
++	return nil
4082
++}
4083
++
4084
++func isPrivilegedNamespace(a admission.Attributes) bool {
4085
++	// If the namespace mentioned in the resource is privileged, return true. We will hit this for calls made to all
4086
++	// resources in this namespace and during delete and update operation on the namespace itself.
4087
++	if a.GetNamespace() == privilegedNamespace {
4088
++		return true
4089
++	}
4090
++
4091
++	// If the resource is a namespace and if its name matched the privileged namespace, return true. We will hit this
4092
++	// during creation of the namespace.
4093
++	if a.GetResource().GroupResource() == api.Resource("namespaces") {
4094
++		if namespace, ok := a.GetObject().(*api.Namespace); ok {
4095
++			if namespace.Name == privilegedNamespace {
4096
++				return true
4097
++			}
4098
++		}
4099
++	}
4100
++
4101
++	return false
4102
++}
4103
++
4104
++func validateClusterRoles(a admission.Attributes) error {
4105
++	// If the name in the request is not empty and has the reserved prefix, then fail. We will hit this during delete
4106
++	// and update operations on the cluster roles. If it does not have the reserved prefix, allow it. If the name is
4107
++	// empty then proceed to read it from the object in the request.
4108
++	if a.GetName() != "" {
4109
++		return checkReservedPrefix(a.GetName(), a)
4110
++	}
4111
++
4112
++	clusterRole, ok := a.GetObject().(*rbac.ClusterRole)
4113
++	// If we cannot get the cluster role binding object, fail.
4114
++	if !ok {
4115
++		return admission.NewForbidden(a,
4116
++			fmt.Errorf("%s validation failed: unexpected type %T", PluginName, a.GetObject()))
4117
++	}
4118
++	// If we get the object and the name has the reserved prefix, fail. We will hit this when someone tries to create a
4119
++	// cluster role with the reserved prefix.
4120
++	return checkReservedPrefix(clusterRole.Name, a)
4121
++}
4122
++
4123
++func validateClusterRoleBindings(a admission.Attributes) error {
4124
++	// If the name in the request is not empty and has the reserved prefix, then fail. We will hit this during delete
4125
++	// and update operations on the cluster role bindings. If it does not have the reserved prefix, allow it. If the
4126
++	// name is empty then proceed to read it from the object in the request.
4127
++	if a.GetName() != "" {
4128
++		return checkReservedPrefix(a.GetName(), a)
4129
++	}
4130
++
4131
++	clusterRoleBinding, ok := a.GetObject().(*rbac.ClusterRoleBinding)
4132
++	// If we cannot get the cluster role binding object, fail.
4133
++	if !ok {
4134
++		return admission.NewForbidden(a,
4135
++			fmt.Errorf("%s validation failed: unexpected type %T", PluginName, a.GetObject()))
4136
++	}
4137
++	// If we get the object and the name has the reserved prefix, fail. We will hit this when someone tries to create a
4138
++	// cluster role binding with the reserved prefix.
4139
++	return checkReservedPrefix(clusterRoleBinding.Name, a)
4140
++}
4141
++
4142
++func validatePods(vac *vmwareAdmissionController, a admission.Attributes) error {
4143
++	// If the request is acting on a sub resource of a pod then allow it. This request is not directly coming to a pod,
4144
++	// but to a sub-resource like pods/foo/status. So, this does not have to be blocked.
4145
++	if len(a.GetSubresource()) != 0 {
4146
++		return nil
4147
++	}
4148
++
4149
++	// If it is a Connect operation, allow it. We restrict access to connect to any pods in the vke-system namespace.
4150
++	// Also, DenyEscalatingExec admission controller denies access to connect to any privileged pod in general. So it is
4151
++	// OK to allow this.
4152
++	if a.GetOperation() == admission.Connect {
4153
++		return nil
4154
++	}
4155
++
4156
++	// If it is a Delete operation and it is not a pod with a reserved prefix, allow it. We restrict access to delete
4157
++	// any pods in the vke-system namespace. So it is OK to allow this.
4158
++	// TODO: Make sure we do not have a need to delete the dashboard stateful set. If we do then it will fail.
4159
++	if a.GetOperation() == admission.Delete {
4160
++		return checkReservedPrefix(a.GetName(), a)
4161
++	}
4162
++
4163
++	// If we cannot get the pod object, fail.
4164
++	if _, ok := a.GetObject().(*api.Pod); !ok {
4165
++		return admission.NewForbidden(a,
4166
++			fmt.Errorf("%s validation failed: unexpected type %T", PluginName, a.GetObject()))
4167
++	}
4168
++
4169
++	// If this is an update, see if we are only updating the ownerRef/finalizers.  Garbage collection does this
4170
++	// and we should allow it in general, since you had the power to update and the power to delete.
4171
++	// The worst that happens is that you delete something, but you aren't controlling the privileged object itself
4172
++	if a.GetOperation() == admission.Update &&
4173
++		rbacregistry.IsOnlyMutatingGCFields(a.GetObject(), a.GetOldObject(), apiequality.Semantic) {
4174
++		return nil
4175
++	}
4176
++
4177
++	errs := field.ErrorList{}
4178
++	originalPod := a.GetObject().(*api.Pod)
4179
++
4180
++	// If the pod is our dashboard pod, its namespace is kube-system and it is created by the controller-manager then
4181
++	// skip validation. This pod is in kube-system namespace which is not privileged. But we need to allow the dashboard
4182
++	// pod to be privileged because it has the OIDC proxy container which requires hostPath volume mount. Just to make
4183
++	// sure we allow only this one pod, we make sure that it is created by the controller manager and name matches the
4184
++	// dashboard pod and it is in kube-system.
4185
++	if a.GetUserInfo().GetName() == systemUnsecuredUser && a.GetNamespace() == kubeSystemNamespace &&
4186
++		(a.GetName() == dashboardPod || originalPod.Name == dashboardPod) {
4187
++		return nil
4188
++	}
4189
++
4190
++	// Check if the pod that needs to be created or updated has the reserved prefix. If it does, deny the request.
4191
++	podName := a.GetName()
4192
++	if podName == "" {
4193
++		podName = originalPod.Name
4194
++	}
4195
++	if err := checkReservedPrefix(podName, a); err != nil {
4196
++		return err
4197
++	}
4198
++
4199
++	// Generate a copy of the pod object because we are not allowed to mutate the pod object.
4200
++	pod := originalPod.DeepCopy()
4201
++
4202
++	provider, err := podsecuritypolicy.NewSimpleProvider(vac.psp, pod.Namespace, vac.strategyFactory)
4203
++	if err != nil {
4204
++		return admission.NewForbidden(a, fmt.Errorf("%s validation failed: %v", PluginName, err))
4205
++	}
4206
++
4207
++	// Set default security context for the pod. This fills in the defaults for the security context values that are not
4208
++	// provided. This is needed to validate the security context correctly.
4209
++	err = provider.DefaultPodSecurityContext(pod)
4210
++	if err != nil {
4211
++		errs = append(errs, field.Invalid(field.NewPath("spec", "securityContext"),
4212
++			pod.Spec.SecurityContext, err.Error()))
4213
++	}
4214
++
4215
++	// Validate the pod.
4216
++	errs = append(errs, provider.ValidatePod(pod, field.NewPath("spec", "securityContext"))...)
4217
++
4218
++	// Validate the initContainers that are part of the pod.
4219
++	for i := range pod.Spec.InitContainers {
4220
++		err := provider.DefaultContainerSecurityContext(pod, &pod.Spec.InitContainers[i])
4221
++		if err != nil {
4222
++			errs = append(errs, field.Invalid(field.NewPath("spec", "initContainers").Index(i).
4223
++				Child("securityContext"), "", err.Error()))
4224
++			continue
4225
++		}
4226
++		errs = append(errs, provider.ValidateContainerSecurityContext(pod, &pod.Spec.InitContainers[i],
4227
++			field.NewPath("spec", "initContainers").Index(i).Child("securityContext"))...)
4228
++	}
4229
++
4230
++	// Validate the containers that are part of the pod.
4231
++	for i := range pod.Spec.Containers {
4232
++		err := provider.DefaultContainerSecurityContext(pod, &pod.Spec.Containers[i])
4233
++		if err != nil {
4234
++			errs = append(errs, field.Invalid(field.NewPath("spec", "containers").Index(i).
4235
++				Child("securityContext"), "", err.Error()))
4236
++			continue
4237
++		}
4238
++		errs = append(errs, provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[i],
4239
++			field.NewPath("spec", "containers").Index(i).Child("securityContext"))...)
4240
++	}
4241
++
4242
++	if len(errs) > 0 {
4243
++		return admission.NewForbidden(a,
4244
++			fmt.Errorf("%s validation failed: %v", PluginName, errs))
4245
++	}
4246
++
4247
++	return nil
4248
++}
4249
++
4250
++func checkReservedPrefix(resourceName string, a admission.Attributes) error {
4251
++	if strings.HasPrefix(resourceName, reservedPrefix) {
4252
++		return admission.NewForbidden(a,
4253
++			fmt.Errorf("%s validation failed: cannot modify resources with prefix %s", PluginName, reservedPrefix))
4254
++	}
4255
++	return nil
4256
++}
4257
+diff --git a/plugin/pkg/admission/vke/admission_test.go b/plugin/pkg/admission/vke/admission_test.go
4258
+new file mode 100644
4259
+index 0000000..779f412
4260
+--- /dev/null
4261
+@@ -0,0 +1,541 @@
4262
++package vke
4263
++
4264
++import (
4265
++	"fmt"
4266
++	"strings"
4267
++	"testing"
4268
++
4269
++	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4270
++	kadmission "k8s.io/apiserver/pkg/admission"
4271
++	kapi "k8s.io/kubernetes/pkg/apis/core"
4272
++	"k8s.io/kubernetes/pkg/apis/rbac"
4273
++	"k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/authentication/user"
4274
++)
4275
++
4276
++const (
4277
++	testServiceAccountsGroup = "system.test\\cascade-controller-service-accounts"
4278
++	defaultConfigFileFormat  = `
4279
++vmwareAdmissionController:
4280
++  privilegedGroup: %s
4281
++`
4282
++)
4283
++
4284
++func TestAdmitPrivileged(t *testing.T) {
4285
++	tests := map[string]struct {
4286
++		operation          kadmission.Operation
4287
++		pod                *kapi.Pod
4288
++		name               string
4289
++		userInfo           user.Info
4290
++		shouldPassValidate bool
4291
++	}{
4292
++		"create pod with Privileged=nil allowed": {
4293
++			operation:          kadmission.Create,
4294
++			pod:                newTestPodBuilder().build(),
4295
++			userInfo:           newTestUserBuilder().build(),
4296
++			shouldPassValidate: true,
4297
++		},
4298
++		"create pod with Privileged=false allowed": {
4299
++			operation:          kadmission.Create,
4300
++			pod:                newTestPodBuilder().withPrivileged(false).build(),
4301
++			userInfo:           newTestUserBuilder().build(),
4302
++			shouldPassValidate: true,
4303
++		},
4304
++		"create pod with Privileged=true denied": {
4305
++			operation:          kadmission.Create,
4306
++			pod:                newTestPodBuilder().withPrivileged(true).build(),
4307
++			userInfo:           newTestUserBuilder().build(),
4308
++			shouldPassValidate: false,
4309
++		},
4310
++		"create pod with multiple containers, one has Privileged=true denied": {
4311
++			operation:          kadmission.Create,
4312
++			pod:                newTestPodBuilder().withPrivileged(true).withInitContainer().withContainer().build(),
4313
++			userInfo:           newTestUserBuilder().build(),
4314
++			shouldPassValidate: false,
4315
++		},
4316
++		"update pod with Privileged=true denied": {
4317
++			operation:          kadmission.Update,
4318
++			pod:                newTestPodBuilder().withPrivileged(true).build(),
4319
++			userInfo:           newTestUserBuilder().build(),
4320
++			shouldPassValidate: false,
4321
++		},
4322
++		"create pod with HostNetwork=true denied": {
4323
++			operation:          kadmission.Create,
4324
++			pod:                newTestPodBuilder().withHostNetwork(true).build(),
4325
++			userInfo:           newTestUserBuilder().build(),
4326
++			shouldPassValidate: false,
4327
++		},
4328
++		"create pod with HostIPC=true denied": {
4329
++			operation:          kadmission.Create,
4330
++			pod:                newTestPodBuilder().withHostIPC(true).build(),
4331
++			userInfo:           newTestUserBuilder().build(),
4332
++			shouldPassValidate: false,
4333
++		},
4334
++		"create pod with HostPID=true denied": {
4335
++			operation:          kadmission.Create,
4336
++			pod:                newTestPodBuilder().withHostPID(true).build(),
4337
++			userInfo:           newTestUserBuilder().build(),
4338
++			shouldPassValidate: false,
4339
++		},
4340
++		"create pod with HostVolume denied": {
4341
++			operation:          kadmission.Create,
4342
++			pod:                newTestPodBuilder().withHostVolume().build(),
4343
++			userInfo:           newTestUserBuilder().build(),
4344
++			shouldPassValidate: false,
4345
++		},
4346
++		"create pod with CascadeDisk allowed": {
4347
++			operation:          kadmission.Create,
4348
++			pod:                newTestPodBuilder().withCascadeDisk().build(),
4349
++			userInfo:           newTestUserBuilder().build(),
4350
++			shouldPassValidate: true,
4351
++		},
4352
++		"create pod with HostVolume and CascadeDisk denied": {
4353
++			operation:          kadmission.Create,
4354
++			pod:                newTestPodBuilder().withHostVolume().withCascadeDisk().build(),
4355
++			userInfo:           newTestUserBuilder().build(),
4356
++			shouldPassValidate: false,
4357
++		},
4358
++		"create pod with vke prefix denied": {
4359
++			operation:          kadmission.Create,
4360
++			pod:                newTestPodBuilder().build(),
4361
++			name:               "vke-dashboard",
4362
++			userInfo:           newTestUserBuilder().build(),
4363
++			shouldPassValidate: false,
4364
++		},
4365
++		"create dashboard pod with vke prefix by privileged user in kube-system allowed": {
4366
++			operation:          kadmission.Create,
4367
++			pod:                newTestPodBuilder().withNamespace(kubeSystemNamespace).build(),
4368
++			name:               "vke-dashboard-0",
4369
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4370
++			shouldPassValidate: true,
4371
++		},
4372
++		"connect pod allowed": {
4373
++			operation:          kadmission.Connect,
4374
++			pod:                newTestPodBuilder().build(),
4375
++			userInfo:           newTestUserBuilder().build(),
4376
++			shouldPassValidate: true,
4377
++		},
4378
++		"delete pod allowed": {
4379
++			operation:          kadmission.Delete,
4380
++			pod:                newTestPodBuilder().build(),
4381
++			userInfo:           newTestUserBuilder().build(),
4382
++			shouldPassValidate: true,
4383
++		},
4384
++		"delete pod with vke prefix denied": {
4385
++			operation:          kadmission.Delete,
4386
++			pod:                newTestPodBuilder().build(),
4387
++			name:               "vke-dashboard",
4388
++			userInfo:           newTestUserBuilder().build(),
4389
++			shouldPassValidate: false,
4390
++		},
4391
++	}
4392
++
4393
++	for k, v := range tests {
4394
++		testPodValidation(k, v.operation, v.pod, v.name, v.userInfo, v.shouldPassValidate, t)
4395
++	}
4396
++}
4397
++
4398
++func TestPrivilegedNamespace(t *testing.T) {
4399
++	tests := map[string]struct {
4400
++		operation          kadmission.Operation
4401
++		pod                *kapi.Pod
4402
++		name               string
4403
++		userInfo           user.Info
4404
++		shouldPassValidate bool
4405
++	}{
4406
++		"denied: regular lightwave user creates pod in vke-system namespace": {
4407
++			operation:          kadmission.Create,
4408
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4409
++			userInfo:           newTestUserBuilder().build(),
4410
++			shouldPassValidate: false,
4411
++		},
4412
++		"denied: regular lightwave user cannot escalate privilege using service account": {
4413
++			operation:          kadmission.Create,
4414
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).withServiceAccount("system:serviceaccount:" + privilegedNamespace + ":default").build(),
4415
++			userInfo:           newTestUserBuilder().build(),
4416
++			shouldPassValidate: false,
4417
++		},
4418
++		"denied: regular service account creates pod in vke-system namespace": {
4419
++			operation:          kadmission.Create,
4420
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4421
++			userInfo:           newTestUserBuilder().withName("system:serviceaccount:kube-system:default").build(),
4422
++			shouldPassValidate: false,
4423
++		},
4424
++		"allowed: regular user creates pod in other namespace": {
4425
++			operation:          kadmission.Create,
4426
++			pod:                newTestPodBuilder().withNamespace("default").build(),
4427
++			userInfo:           newTestUserBuilder().build(),
4428
++			shouldPassValidate: true,
4429
++		},
4430
++		"allowed: Cascade Controller Service Account creates pod in vke-system namespace": {
4431
++			operation:          kadmission.Create,
4432
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4433
++			userInfo:           newTestUserBuilder().withGroup(testServiceAccountsGroup).build(),
4434
++			shouldPassValidate: true,
4435
++		},
4436
++		"allowed: systemUnsecuredUser creates pod in vke-system namespace": {
4437
++			operation:          kadmission.Create,
4438
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4439
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4440
++			shouldPassValidate: true,
4441
++		},
4442
++		"allowed: vke-system service account creates pod in vke-system namespace": {
4443
++			operation:          kadmission.Create,
4444
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4445
++			userInfo:           newTestUserBuilder().withName("system:serviceaccount:" + privilegedNamespace + ":default").build(),
4446
++			shouldPassValidate: true,
4447
++		},
4448
++		"allowed: kubelet group creates pod in vke-system namespace": {
4449
++			operation:          kadmission.Create,
4450
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4451
++			userInfo:           newTestUserBuilder().withGroup(kubeletGroup).build(),
4452
++			shouldPassValidate: true,
4453
++		},
4454
++		"allowed: kubeProxy group creates pod in vke-system namespace": {
4455
++			operation:          kadmission.Create,
4456
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4457
++			userInfo:           newTestUserBuilder().withGroup(kubeProxyGroup).build(),
4458
++			shouldPassValidate: true,
4459
++		},
4460
++		"denied: regular lightwave group does not grant privileged access": {
4461
++			operation:          kadmission.Create,
4462
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4463
++			userInfo:           newTestUserBuilder().withGroup("test1\\group1").build(),
4464
++			shouldPassValidate: false,
4465
++		},
4466
++		"allowed: if user has multiple groups, any privileged group can grant privileged access": {
4467
++			operation:          kadmission.Create,
4468
++			pod:                newTestPodBuilder().withNamespace(privilegedNamespace).build(),
4469
++			userInfo:           newTestUserBuilder().withGroup("test1\\group1").withGroup(testServiceAccountsGroup).build(),
4470
++			shouldPassValidate: true,
4471
++		},
4472
++	}
4473
++	for k, v := range tests {
4474
++		testPodValidation(k, v.operation, v.pod, v.name, v.userInfo, v.shouldPassValidate, t)
4475
++	}
4476
++}
4477
++
4478
++func TestClusterLevelResources(t *testing.T) {
4479
++	tests := map[string]struct {
4480
++		operation          kadmission.Operation
4481
++		resource           string
4482
++		name               string
4483
++		namespace          string
4484
++		userInfo           user.Info
4485
++		shouldPassValidate bool
4486
++	}{
4487
++		"denied: regular lightwave user update configmaps in vke-system namespace": {
4488
++			operation:          kadmission.Update,
4489
++			resource:           "configmaps",
4490
++			namespace:          privilegedNamespace,
4491
++			userInfo:           newTestUserBuilder().build(),
4492
++			shouldPassValidate: false,
4493
++		},
4494
++		"denied: regular lightwave user delete daemonsets in vke-system namespace": {
4495
++			operation:          kadmission.Delete,
4496
++			resource:           "daemonsets",
4497
++			namespace:          privilegedNamespace,
4498
++			userInfo:           newTestUserBuilder().build(),
4499
++			shouldPassValidate: false,
4500
++		},
4501
++		"denied: regular lightwave user create deployments in vke-system namespace": {
4502
++			operation:          kadmission.Create,
4503
++			resource:           "deployments",
4504
++			namespace:          privilegedNamespace,
4505
++			userInfo:           newTestUserBuilder().build(),
4506
++			shouldPassValidate: false,
4507
++		},
4508
++		"denied: regular lightwave user create rolebindings in vke-system namespace": {
4509
++			operation:          kadmission.Create,
4510
++			resource:           "rolebindings",
4511
++			namespace:          privilegedNamespace,
4512
++			userInfo:           newTestUserBuilder().build(),
4513
++			shouldPassValidate: false,
4514
++		},
4515
++		"allowed: regular lightwave user create rolebindings in other namespace": {
4516
++			operation:          kadmission.Create,
4517
++			resource:           "rolebindings",
4518
++			namespace:          "default",
4519
++			userInfo:           newTestUserBuilder().build(),
4520
++			shouldPassValidate: true,
4521
++		},
4522
++		"allowed: regular lightwave user create clusterroles": {
4523
++			operation:          kadmission.Create,
4524
++			resource:           "clusterroles",
4525
++			name:               "cluster-role",
4526
++			namespace:          "",
4527
++			userInfo:           newTestUserBuilder().build(),
4528
++			shouldPassValidate: true,
4529
++		},
4530
++		"denied: regular lightwave user create clusterroles with vke: prefix": {
4531
++			operation:          kadmission.Create,
4532
++			resource:           "clusterroles",
4533
++			name:               "vke:clusterrole",
4534
++			namespace:          "",
4535
++			userInfo:           newTestUserBuilder().build(),
4536
++			shouldPassValidate: false,
4537
++		},
4538
++		"denied: regular lightwave user delete clusterroles with vke: prefix": {
4539
++			operation:          kadmission.Delete,
4540
++			resource:           "clusterroles",
4541
++			name:               "vke:clusterrole",
4542
++			namespace:          "",
4543
++			userInfo:           newTestUserBuilder().build(),
4544
++			shouldPassValidate: false,
4545
++		},
4546
++		"allowed: privileged user update clusterroles with vke: prefix": {
4547
++			operation:          kadmission.Update,
4548
++			resource:           "clusterroles",
4549
++			name:               "vke:clusterrole",
4550
++			namespace:          "",
4551
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4552
++			shouldPassValidate: true,
4553
++		},
4554
++		"allowed: regular lightwave user create clusterrolebindings": {
4555
++			operation:          kadmission.Create,
4556
++			resource:           "clusterrolebindings",
4557
++			name:               "cluster-role-binding",
4558
++			namespace:          "",
4559
++			userInfo:           newTestUserBuilder().build(),
4560
++			shouldPassValidate: true,
4561
++		},
4562
++		"denied: regular lightwave user create clusterrolebindings with vke: prefix": {
4563
++			operation:          kadmission.Create,
4564
++			resource:           "clusterrolebindings",
4565
++			name:               "vke:clusterrolebinding",
4566
++			namespace:          "",
4567
++			userInfo:           newTestUserBuilder().build(),
4568
++			shouldPassValidate: false,
4569
++		},
4570
++		"denied: regular lightwave user update clusterrolebindings with vke: prefix": {
4571
++			operation:          kadmission.Delete,
4572
++			resource:           "clusterrolebindings",
4573
++			name:               "vke:clusterrolebinding",
4574
++			namespace:          "",
4575
++			userInfo:           newTestUserBuilder().build(),
4576
++			shouldPassValidate: false,
4577
++		},
4578
++		"allowed: privileged user update clusterrolebindings with vke: prefix": {
4579
++			operation:          kadmission.Update,
4580
++			resource:           "clusterrolebindings",
4581
++			name:               "vke:clusterrolebinding",
4582
++			namespace:          "",
4583
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4584
++			shouldPassValidate: true,
4585
++		},
4586
++		"denied: regular lightwave user update nodes": {
4587
++			operation:          kadmission.Update,
4588
++			resource:           "nodes",
4589
++			namespace:          "",
4590
++			userInfo:           newTestUserBuilder().build(),
4591
++			shouldPassValidate: false,
4592
++		},
4593
++		"allowed: privileged user update nodes": {
4594
++			operation:          kadmission.Update,
4595
++			resource:           "nodes",
4596
++			namespace:          "",
4597
++			userInfo:           newTestUserBuilder().withName(systemUnsecuredUser).build(),
4598
++			shouldPassValidate: true,
4599
++		},
4600
++	}
4601
++	for k, v := range tests {
4602
++		testResourceValidation(k, v.operation, v.resource, v.name, v.namespace, v.userInfo, v.shouldPassValidate, t)
4603
++	}
4604
++}
4605
++
4606
++func testPodValidation(testCaseName string, op kadmission.Operation, pod *kapi.Pod, name string, userInfo user.Info,
4607
++	shouldPassValidate bool, t *testing.T) {
4608
++
4609
++	defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup)
4610
++	configFile := strings.NewReader(defaultConfigFile)
4611
++	plugin, err := NewVMwareAdmissionController(configFile)
4612
++	if err != nil {
4613
++		t.Errorf("%s: failed to create admission controller %v", testCaseName, err)
4614
++	}
4615
++
4616
++	attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"),
4617
++		pod.Namespace, name, kapi.Resource("pods").WithVersion("version"), "", op, userInfo)
4618
++
4619
++	err = plugin.Validate(attrs)
4620
++	if shouldPassValidate && err != nil {
4621
++		t.Errorf("%s: expected no errors on Validate but received %v", testCaseName, err)
4622
++	} else if !shouldPassValidate && err == nil {
4623
++		t.Errorf("%s: expected errors on Validate but received none", testCaseName)
4624
++	}
4625
++}
4626
++
4627
++func testResourceValidation(testCaseName string, op kadmission.Operation, resource string, name string,
4628
++	namespace string, userInfo user.Info, shouldPassValidate bool, t *testing.T) {
4629
++
4630
++	defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup)
4631
++	configFile := strings.NewReader(defaultConfigFile)
4632
++	plugin, err := NewVMwareAdmissionController(configFile)
4633
++	if err != nil {
4634
++		t.Errorf("%s: failed to create admission controller %v", testCaseName, err)
4635
++	}
4636
++
4637
++	groupResource := kapi.Resource(resource).WithVersion("version")
4638
++	if resource == "clusterroles" || resource == "clusterrolebindings" {
4639
++		groupResource = rbac.Resource(resource).WithVersion("version")
4640
++	}
4641
++
4642
++	attrs := kadmission.NewAttributesRecord(nil, nil, kapi.Kind("kind").WithVersion("version"),
4643
++		namespace, name, groupResource, "", op, userInfo)
4644
++
4645
++	err = plugin.Validate(attrs)
4646
++	if shouldPassValidate && err != nil {
4647
++		t.Errorf("%s: expected no errors on Validate but received %v", testCaseName, err)
4648
++	} else if !shouldPassValidate && err == nil {
4649
++		t.Errorf("%s: expected errors on Validate but received none", testCaseName)
4650
++	}
4651
++}
4652
++
4653
++// testPodBuilder
4654
++type testPodBuilder struct {
4655
++	pod kapi.Pod
4656
++}
4657
++
4658
++func newTestPodBuilder() *testPodBuilder {
4659
++	builder := new(testPodBuilder)
4660
++	return builder.init()
4661
++}
4662
++
4663
++func (p *testPodBuilder) init() *testPodBuilder {
4664
++	p.pod = kapi.Pod{
4665
++		ObjectMeta: metav1.ObjectMeta{
4666
++			Name:        "pod",
4667
++			Namespace:   "namespace",
4668
++			Annotations: map[string]string{},
4669
++		},
4670
++		Spec: kapi.PodSpec{
4671
++			ServiceAccountName: "default",
4672
++			SecurityContext:    &kapi.PodSecurityContext{},
4673
++			Containers: []kapi.Container{
4674
++				{
4675
++					Name:            "test-container-1",
4676
++					SecurityContext: &kapi.SecurityContext{},
4677
++				},
4678
++			},
4679
++		},
4680
++	}
4681
++	return p
4682
++}
4683
++
4684
++func (p *testPodBuilder) build() *kapi.Pod {
4685
++	return &p.pod
4686
++}
4687
++
4688
++func (p *testPodBuilder) withNamespace(namespace string) *testPodBuilder {
4689
++	p.pod.ObjectMeta.Namespace = namespace
4690
++	return p
4691
++}
4692
++
4693
++func (p *testPodBuilder) withServiceAccount(sa string) *testPodBuilder {
4694
++	p.pod.Spec.ServiceAccountName = sa
4695
++	return p
4696
++}
4697
++
4698
++func (p *testPodBuilder) withPrivileged(v bool) *testPodBuilder {
4699
++	p.pod.Spec.Containers[0].SecurityContext.Privileged = &v
4700
++	return p
4701
++}
4702
++
4703
++func (p *testPodBuilder) withHostNetwork(v bool) *testPodBuilder {
4704
++	p.pod.Spec.SecurityContext.HostNetwork = v
4705
++	return p
4706
++}
4707
++
4708
++func (p *testPodBuilder) withHostIPC(v bool) *testPodBuilder {
4709
++	p.pod.Spec.SecurityContext.HostIPC = v
4710
++	return p
4711
++}
4712
++
4713
++func (p *testPodBuilder) withHostPID(v bool) *testPodBuilder {
4714
++	p.pod.Spec.SecurityContext.HostPID = v
4715
++	return p
4716
++}
4717
++
4718
++func (p *testPodBuilder) withHostVolume() *testPodBuilder {
4719
++	volume := kapi.Volume{
4720
++		Name: "host",
4721
++		VolumeSource: kapi.VolumeSource{
4722
++			HostPath: &kapi.HostPathVolumeSource{
4723
++				Path: "/",
4724
++			},
4725
++		},
4726
++	}
4727
++	device := kapi.VolumeDevice{Name: "host", DevicePath: "/host"}
4728
++
4729
++	p.pod.Spec.Volumes = append(p.pod.Spec.Volumes, volume)
4730
++	p.pod.Spec.Containers[0].VolumeDevices = append(p.pod.Spec.Containers[0].VolumeDevices, device)
4731
++	return p
4732
++}
4733
++
4734
++func (p *testPodBuilder) withCascadeDisk() *testPodBuilder {
4735
++	volume := kapi.Volume{
4736
++		Name: "cascadeDisk",
4737
++		VolumeSource: kapi.VolumeSource{
4738
++			PersistentVolumeClaim: &kapi.PersistentVolumeClaimVolumeSource{
4739
++				ClaimName: "00000000-0000-0000-0000-000000000001",
4740
++				ReadOnly:  false,
4741
++			},
4742
++		},
4743
++	}
4744
++	device := kapi.VolumeDevice{Name: "cascadeDisk", DevicePath: "/cascadeDisk"}
4745
++
4746
++	p.pod.Spec.Volumes = append(p.pod.Spec.Volumes, volume)
4747
++	p.pod.Spec.Containers[0].VolumeDevices = append(p.pod.Spec.Containers[0].VolumeDevices, device)
4748
++	return p
4749
++}
4750
++
4751
++func (p *testPodBuilder) withContainer() *testPodBuilder {
4752
++	container := kapi.Container{
4753
++		Name:            "test-container-2",
4754
++		SecurityContext: &kapi.SecurityContext{},
4755
++	}
4756
++
4757
++	p.pod.Spec.Containers = append(p.pod.Spec.Containers, container)
4758
++	return p
4759
++}
4760
++
4761
++func (p *testPodBuilder) withInitContainer() *testPodBuilder {
4762
++	container := kapi.Container{
4763
++		Name:            "test-init-container",
4764
++		SecurityContext: &kapi.SecurityContext{},
4765
++	}
4766
++
4767
++	p.pod.Spec.Containers = append(p.pod.Spec.Containers, container)
4768
++	return p
4769
++}
4770
++
4771
++// testUserBuilder
4772
++type testUserBuilder struct {
4773
++	user *user.DefaultInfo
4774
++}
4775
++
4776
++func newTestUserBuilder() *testUserBuilder {
4777
++	builder := new(testUserBuilder)
4778
++	return builder.init()
4779
++}
4780
++
4781
++func (p *testUserBuilder) init() *testUserBuilder {
4782
++	p.user = &user.DefaultInfo{
4783
++		Name:   "https://lightwave.cascade-cloud.com/openidconnect/00000000-0000-0000-0000-000000000001#joe@vmware.com",
4784
++		UID:    "10001",
4785
++		Groups: []string{},
4786
++	}
4787
++	return p
4788
++}
4789
++
4790
++func (p *testUserBuilder) build() *user.DefaultInfo {
4791
++	return p.user
4792
++}
4793
++
4794
++func (p *testUserBuilder) withName(name string) *testUserBuilder {
4795
++	p.user.Name = name
4796
++	return p
4797
++}
4798
++
4799
++func (p *testUserBuilder) withGroup(group string) *testUserBuilder {
4800
++	p.user.Groups = append(p.user.Groups, group)
4801
++	return p
4802
++}
4803
+diff --git a/staging/src/k8s.io/api/core/v1/generated.pb.go b/staging/src/k8s.io/api/core/v1/generated.pb.go
4804
+index 85c7b63..b97b2f1 100644
4805
+--- a/staging/src/k8s.io/api/core/v1/generated.pb.go
4806
+@@ -35,6 +35,7 @@ limitations under the License.
3817 4807
  		Binding
3818 4808
  		CSIPersistentVolumeSource
3819 4809
  		Capabilities
... ...
@@ -3822,7 +4974,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3822 3822
  		CephFSPersistentVolumeSource
3823 3823
  		CephFSVolumeSource
3824 3824
  		CinderVolumeSource
3825
-@@ -262,9 +263,11 @@
3825
+@@ -262,9 +263,11 @@ func (m *AvoidPods) Reset()                    { *m = AvoidPods{} }
3826 3826
  func (*AvoidPods) ProtoMessage()               {}
3827 3827
  func (*AvoidPods) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} }
3828 3828
  
... ...
@@ -3837,7 +4989,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3837 3837
  
3838 3838
  func (m *AzureFilePersistentVolumeSource) Reset()      { *m = AzureFilePersistentVolumeSource{} }
3839 3839
  func (*AzureFilePersistentVolumeSource) ProtoMessage() {}
3840
-@@ -1052,6 +1055,11 @@
3840
+@@ -1052,6 +1055,11 @@ func (*WeightedPodAffinityTerm) Descriptor() ([]byte, []int) {
3841 3841
  	return fileDescriptorGenerated, []int{187}
3842 3842
  }
3843 3843
  
... ...
@@ -3849,7 +5001,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3849 3849
  func init() {
3850 3850
  	proto.RegisterType((*AWSElasticBlockStoreVolumeSource)(nil), "k8s.io.api.core.v1.AWSElasticBlockStoreVolumeSource")
3851 3851
  	proto.RegisterType((*Affinity)(nil), "k8s.io.api.core.v1.Affinity")
3852
-@@ -1063,6 +1071,7 @@
3852
+@@ -1063,6 +1071,7 @@ func init() {
3853 3853
  	proto.RegisterType((*Binding)(nil), "k8s.io.api.core.v1.Binding")
3854 3854
  	proto.RegisterType((*CSIPersistentVolumeSource)(nil), "k8s.io.api.core.v1.CSIPersistentVolumeSource")
3855 3855
  	proto.RegisterType((*Capabilities)(nil), "k8s.io.api.core.v1.Capabilities")
... ...
@@ -3857,7 +5009,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3857 3857
  	proto.RegisterType((*CephFSPersistentVolumeSource)(nil), "k8s.io.api.core.v1.CephFSPersistentVolumeSource")
3858 3858
  	proto.RegisterType((*CephFSVolumeSource)(nil), "k8s.io.api.core.v1.CephFSVolumeSource")
3859 3859
  	proto.RegisterType((*CinderVolumeSource)(nil), "k8s.io.api.core.v1.CinderVolumeSource")
3860
-@@ -1683,6 +1692,32 @@
3860
+@@ -1683,6 +1692,32 @@ func (m *Capabilities) MarshalTo(dAtA []byte) (int, error) {
3861 3861
  	return i, nil
3862 3862
  }
3863 3863
  
... ...
@@ -3890,7 +5042,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3890 3890
  func (m *CephFSPersistentVolumeSource) Marshal() (dAtA []byte, err error) {
3891 3891
  	size := m.Size()
3892 3892
  	dAtA = make([]byte, size)
3893
-@@ -6447,13 +6482,13 @@
3893
+@@ -6447,13 +6482,13 @@ func (m *PersistentVolumeSource) MarshalTo(dAtA []byte) (int, error) {
3894 3894
  		}
3895 3895
  		i += n124
3896 3896
  	}
... ...
@@ -3907,7 +5059,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3907 3907
  		if err != nil {
3908 3908
  			return 0, err
3909 3909
  		}
3910
-@@ -6531,6 +6566,18 @@
3910
+@@ -6531,6 +6566,18 @@ func (m *PersistentVolumeSource) MarshalTo(dAtA []byte) (int, error) {
3911 3911
  		}
3912 3912
  		i += n131
3913 3913
  	}
... ...
@@ -3926,7 +5078,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3926 3926
  	return i, nil
3927 3927
  }
3928 3928
  
3929
-@@ -10544,13 +10591,13 @@
3929
+@@ -10544,13 +10591,13 @@ func (m *VolumeSource) MarshalTo(dAtA []byte) (int, error) {
3930 3930
  		}
3931 3931
  		i += n229
3932 3932
  	}
... ...
@@ -3943,7 +5095,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3943 3943
  		if err != nil {
3944 3944
  			return 0, err
3945 3945
  		}
3946
-@@ -10616,6 +10663,18 @@
3946
+@@ -10616,6 +10663,18 @@ func (m *VolumeSource) MarshalTo(dAtA []byte) (int, error) {
3947 3947
  		}
3948 3948
  		i += n235
3949 3949
  	}
... ...
@@ -3962,7 +5114,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3962 3962
  	return i, nil
3963 3963
  }
3964 3964
  
3965
-@@ -10873,6 +10932,16 @@
3965
+@@ -10873,6 +10932,16 @@ func (m *Capabilities) Size() (n int) {
3966 3966
  	return n
3967 3967
  }
3968 3968
  
... ...
@@ -3979,7 +5131,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3979 3979
  func (m *CephFSPersistentVolumeSource) Size() (n int) {
3980 3980
  	var l int
3981 3981
  	_ = l
3982
-@@ -12616,8 +12685,8 @@
3982
+@@ -12616,8 +12685,8 @@ func (m *PersistentVolumeSource) Size() (n int) {
3983 3983
  		l = m.Quobyte.Size()
3984 3984
  		n += 1 + l + sovGenerated(uint64(l))
3985 3985
  	}
... ...
@@ -3990,7 +5142,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
3990 3990
  		n += 2 + l + sovGenerated(uint64(l))
3991 3991
  	}
3992 3992
  	if m.PhotonPersistentDisk != nil {
3993
-@@ -12644,6 +12713,10 @@
3993
+@@ -12644,6 +12713,10 @@ func (m *PersistentVolumeSource) Size() (n int) {
3994 3994
  		l = m.CSI.Size()
3995 3995
  		n += 2 + l + sovGenerated(uint64(l))
3996 3996
  	}
... ...
@@ -4001,7 +5153,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4001 4001
  	return n
4002 4002
  }
4003 4003
  
4004
-@@ -14098,8 +14171,8 @@
4004
+@@ -14098,8 +14171,8 @@ func (m *VolumeSource) Size() (n int) {
4005 4005
  		l = m.Quobyte.Size()
4006 4006
  		n += 2 + l + sovGenerated(uint64(l))
4007 4007
  	}
... ...
@@ -4012,7 +5164,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4012 4012
  		n += 2 + l + sovGenerated(uint64(l))
4013 4013
  	}
4014 4014
  	if m.PhotonPersistentDisk != nil {
4015
-@@ -14122,6 +14195,10 @@
4015
+@@ -14122,6 +14195,10 @@ func (m *VolumeSource) Size() (n int) {
4016 4016
  		l = m.StorageOS.Size()
4017 4017
  		n += 2 + l + sovGenerated(uint64(l))
4018 4018
  	}
... ...
@@ -4023,7 +5175,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4023 4023
  	return n
4024 4024
  }
4025 4025
  
4026
-@@ -14296,6 +14373,17 @@
4026
+@@ -14296,6 +14373,17 @@ func (this *Capabilities) String() string {
4027 4027
  	}, "")
4028 4028
  	return s
4029 4029
  }
... ...
@@ -4041,7 +5193,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4041 4041
  func (this *CephFSPersistentVolumeSource) String() string {
4042 4042
  	if this == nil {
4043 4043
  		return "nil"
4044
-@@ -15695,13 +15783,14 @@
4044
+@@ -15695,13 +15783,14 @@ func (this *PersistentVolumeSource) String() string {
4045 4045
  		`AzureFile:` + strings.Replace(fmt.Sprintf("%v", this.AzureFile), "AzureFilePersistentVolumeSource", "AzureFilePersistentVolumeSource", 1) + `,`,
4046 4046
  		`VsphereVolume:` + strings.Replace(fmt.Sprintf("%v", this.VsphereVolume), "VsphereVirtualDiskVolumeSource", "VsphereVirtualDiskVolumeSource", 1) + `,`,
4047 4047
  		`Quobyte:` + strings.Replace(fmt.Sprintf("%v", this.Quobyte), "QuobyteVolumeSource", "QuobyteVolumeSource", 1) + `,`,
... ...
@@ -4057,7 +5209,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4057 4057
  		`}`,
4058 4058
  	}, "")
4059 4059
  	return s
4060
-@@ -16843,12 +16932,13 @@
4060
+@@ -16843,12 +16932,13 @@ func (this *VolumeSource) String() string {
4061 4061
  		`ConfigMap:` + strings.Replace(fmt.Sprintf("%v", this.ConfigMap), "ConfigMapVolumeSource", "ConfigMapVolumeSource", 1) + `,`,
4062 4062
  		`VsphereVolume:` + strings.Replace(fmt.Sprintf("%v", this.VsphereVolume), "VsphereVirtualDiskVolumeSource", "VsphereVirtualDiskVolumeSource", 1) + `,`,
4063 4063
  		`Quobyte:` + strings.Replace(fmt.Sprintf("%v", this.Quobyte), "QuobyteVolumeSource", "QuobyteVolumeSource", 1) + `,`,
... ...
@@ -4072,7 +5224,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4072 4072
  		`}`,
4073 4073
  	}, "")
4074 4074
  	return s
4075
-@@ -35335,7 +35425,7 @@
4075
+@@ -35335,7 +35425,7 @@ func (m *PersistentVolumeSource) Unmarshal(dAtA []byte) error {
4076 4076
  			iNdEx = postIndex
4077 4077
  		case 16:
4078 4078
  			if wireType != 2 {
... ...
@@ -4081,7 +5233,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4081 4081
  			}
4082 4082
  			var msglen int
4083 4083
  			for shift := uint(0); ; shift += 7 {
4084
-@@ -35359,10 +35449,10 @@
4084
+@@ -35359,10 +35449,10 @@ func (m *PersistentVolumeSource) Unmarshal(dAtA []byte) error {
4085 4085
  			if postIndex > l {
4086 4086
  				return io.ErrUnexpectedEOF
4087 4087
  			}
... ...
@@ -4095,7 +5247,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4095 4095
  				return err
4096 4096
  			}
4097 4097
  			iNdEx = postIndex
4098
-@@ -35564,6 +35654,39 @@
4098
+@@ -35564,6 +35654,39 @@ func (m *PersistentVolumeSource) Unmarshal(dAtA []byte) error {
4099 4099
  				return err
4100 4100
  			}
4101 4101
  			iNdEx = postIndex
... ...
@@ -4135,7 +5287,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4135 4135
  		default:
4136 4136
  			iNdEx = preIndex
4137 4137
  			skippy, err := skipGenerated(dAtA[iNdEx:])
4138
-@@ -36135,6 +36258,114 @@
4138
+@@ -36135,6 +36258,114 @@ func (m *PersistentVolumeStatus) Unmarshal(dAtA []byte) error {
4139 4139
  	}
4140 4140
  	return nil
4141 4141
  }
... ...
@@ -4250,7 +5402,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4250 4250
  func (m *PhotonPersistentDiskVolumeSource) Unmarshal(dAtA []byte) error {
4251 4251
  	l := len(dAtA)
4252 4252
  	iNdEx := 0
4253
-@@ -49741,7 +49972,7 @@
4253
+@@ -49741,7 +49972,7 @@ func (m *VolumeSource) Unmarshal(dAtA []byte) error {
4254 4254
  			iNdEx = postIndex
4255 4255
  		case 22:
4256 4256
  			if wireType != 2 {
... ...
@@ -4259,7 +5411,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4259 4259
  			}
4260 4260
  			var msglen int
4261 4261
  			for shift := uint(0); ; shift += 7 {
4262
-@@ -49765,10 +49996,10 @@
4262
+@@ -49765,10 +49996,10 @@ func (m *VolumeSource) Unmarshal(dAtA []byte) error {
4263 4263
  			if postIndex > l {
4264 4264
  				return io.ErrUnexpectedEOF
4265 4265
  			}
... ...
@@ -4273,7 +5425,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4273 4273
  				return err
4274 4274
  			}
4275 4275
  			iNdEx = postIndex
4276
-@@ -49937,6 +50168,39 @@
4276
+@@ -49937,6 +50168,39 @@ func (m *VolumeSource) Unmarshal(dAtA []byte) error {
4277 4277
  				return err
4278 4278
  			}
4279 4279
  			iNdEx = postIndex
... ...
@@ -4313,10 +5465,11 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/genera
4313 4313
  		default:
4314 4314
  			iNdEx = preIndex
4315 4315
  			skippy, err := skipGenerated(dAtA[iNdEx:])
4316
-diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/types.go kubernetes/staging/src/k8s.io/api/core/v1/types.go
4317
-+++ kubernetes/staging/src/k8s.io/api/core/v1/types.go	2018-05-17 00:03:37.000000000 +0000
4318
-@@ -333,9 +333,9 @@
4316
+diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go
4317
+index 08ef419..19184ed 100644
4318
+--- a/staging/src/k8s.io/api/core/v1/types.go
4319
+@@ -333,9 +333,9 @@ type VolumeSource struct {
4319 4320
  	// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
4320 4321
  	// +optional
4321 4322
  	Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty" protobuf:"bytes,21,opt,name=quobyte"`
... ...
@@ -4328,7 +5481,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/types.
4328 4328
  	// PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine
4329 4329
  	PhotonPersistentDisk *PhotonPersistentDiskVolumeSource `json:"photonPersistentDisk,omitempty" protobuf:"bytes,23,opt,name=photonPersistentDisk"`
4330 4330
  	// Items for all in one resources secrets, configmaps, and downward API
4331
-@@ -349,6 +349,9 @@
4331
+@@ -349,6 +349,9 @@ type VolumeSource struct {
4332 4332
  	// StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.
4333 4333
  	// +optional
4334 4334
  	StorageOS *StorageOSVolumeSource `json:"storageos,omitempty" protobuf:"bytes,27,opt,name=storageos"`
... ...
@@ -4338,7 +5491,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/types.
4338 4338
  }
4339 4339
  
4340 4340
  // PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
4341
-@@ -428,9 +431,9 @@
4341
+@@ -428,9 +431,9 @@ type PersistentVolumeSource struct {
4342 4342
  	// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
4343 4343
  	// +optional
4344 4344
  	Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty" protobuf:"bytes,15,opt,name=quobyte"`
... ...
@@ -4350,7 +5503,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/types.
4350 4350
  	// PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine
4351 4351
  	PhotonPersistentDisk *PhotonPersistentDiskVolumeSource `json:"photonPersistentDisk,omitempty" protobuf:"bytes,17,opt,name=photonPersistentDisk"`
4352 4352
  	// PortworxVolume represents a portworx volume attached and mounted on kubelets host machine
4353
-@@ -449,6 +452,9 @@
4353
+@@ -449,6 +452,9 @@ type PersistentVolumeSource struct {
4354 4354
  	// CSI represents storage that handled by an external CSI driver (Beta feature).
4355 4355
  	// +optional
4356 4356
  	CSI *CSIPersistentVolumeSource `json:"csi,omitempty" protobuf:"bytes,22,opt,name=csi"`
... ...
@@ -4360,7 +5513,7 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/types.
4360 4360
  }
4361 4361
  
4362 4362
  const (
4363
-@@ -1617,6 +1623,16 @@
4363
+@@ -1617,6 +1623,16 @@ type StorageOSPersistentVolumeSource struct {
4364 4364
  	SecretRef *ObjectReference `json:"secretRef,omitempty" protobuf:"bytes,5,opt,name=secretRef"`
4365 4365
  }
4366 4366
  
... ...
@@ -4377,3 +5530,6 @@ diff -uNr --no-dereference kubernetes-orig/staging/src/k8s.io/api/core/v1/types.
4377 4377
  // Adapts a ConfigMap into a volume.
4378 4378
  //
4379 4379
  // The contents of the target ConfigMap's Data field will be presented in a
4380
+-- 
4381
+2.7.4
4382
+
... ...
@@ -1,7 +1,7 @@
1 1
 Summary:        Kubernetes cluster management
2 2
 Name:           kubernetes
3 3
 Version:        1.10.2
4
-Release:        3%{?dist}
4
+Release:        4%{?dist}
5 5
 License:        ASL 2.0
6 6
 URL:            https://github.com/kubernetes/kubernetes/archive/v%{version}.tar.gz
7 7
 Source0:        kubernetes-%{version}.tar.gz
... ...
@@ -207,6 +207,8 @@ fi
207 207
 /opt/vmware/kubernetes/windows/amd64/kubectl.exe
208 208
 
209 209
 %changelog
210
+*   Sat Jun 02 2018 Bo Gan <ganb@vmware.com> 1.10.2-4
211
+-   Update vke patch (7b1ec01)
210 212
 *   Tue May 23 2018 A. Walton <waltona@vmware.com> 1.10.2-3
211 213
 -   Add kubectl-extras package.
212 214
 *   Thu May 17 2018 Sharath George <sharathg@vmware.com> 1.10.2-2
... ...
@@ -1,7 +1,7 @@
1 1
 Summary:        Kubernetes cluster management
2 2
 Name:           kubernetes
3 3
 Version:        1.9.6
4
-Release:        2%{?dist}
4
+Release:        3%{?dist}
5 5
 License:        ASL 2.0
6 6
 URL:            https://github.com/kubernetes/kubernetes/archive/v%{version}.tar.gz
7 7
 Source0:        kubernetes-v%{version}.tar.gz
... ...
@@ -185,6 +185,8 @@ fi
185 185
 %{_bindir}/pause-amd64
186 186
 
187 187
 %changelog
188
+*   Sat Jun 02 2018 Bo Gan <ganb@vmware.com> 1.9.6-3
189
+-   Update vke patch (8ef8da7)
188 190
 *   Tue May 01 2018 Dheeraj Shetty <dheerajs@vmware.com> 1.9.6-2
189 191
 -   Enable TLS certificate validation in Cascade CLoud Provider
190 192
 *   Wed Mar 21 2018 Dheeraj Shetty <dheerajs@vmware.com> 1.9.6-1