|
14 | 14 | # See the License for the specific language governing permissions and
|
15 | 15 | # limitations under the License.
|
16 | 16 |
|
17 |
| -import json |
18 | 17 | import time
|
19 | 18 | import unittest
|
20 | 19 | import uuid
|
21 | 20 |
|
22 | 21 | from kubernetes.e2e_test import base
|
23 | 22 | from kubernetes.client import api_client
|
24 |
| -from kubernetes.dynamic import DynamicClient |
25 |
| -from kubernetes.stream import stream |
26 |
| -from kubernetes.stream.ws_client import ERROR_CHANNEL |
| 23 | + |
| 24 | +from . import DynamicClient |
| 25 | +from .exceptions import ResourceNotFoundError |
27 | 26 |
|
28 | 27 |
|
29 | 28 | def short_uuid():
|
30 | 29 | id = str(uuid.uuid4())
|
31 | 30 | return id[-12:]
|
32 | 31 |
|
33 | 32 |
|
34 |
| -class TestClient(unittest.TestCase): |
| 33 | +class TestDynamicClient(unittest.TestCase): |
35 | 34 |
|
36 | 35 | @classmethod
|
37 | 36 | def setUpClass(cls):
|
38 | 37 | cls.config = base.get_e2e_configuration()
|
39 | 38 |
|
40 |
| - def test_pod_apis(self): |
| 39 | + def test_cluster_custom_resources(self): |
41 | 40 | client = DynamicClient(api_client.ApiClient(configuration=self.config))
|
42 |
| - api = client.resources.get(api_version='v1', kind='Pod') |
43 | 41 |
|
44 |
| - name = 'busybox-test-' + short_uuid() |
45 |
| - pod_manifest = { |
46 |
| - 'apiVersion': 'v1', |
47 |
| - 'kind': 'Pod', |
| 42 | + with self.assertRaises(ResourceNotFoundError): |
| 43 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ClusterChangeMe') |
| 44 | + |
| 45 | + crd_api = client.resources.get(kind='CustomResourceDefinition') |
| 46 | + name = 'clusterchangemes.apps.example.com' |
| 47 | + crd_manifest = { |
| 48 | + 'apiVersion': 'apiextensions.k8s.io/v1beta1', |
| 49 | + 'kind': 'CustomResourceDefinition', |
| 50 | + 'metadata': { |
| 51 | + 'name': name, |
| 52 | + }, |
| 53 | + 'spec': { |
| 54 | + 'group': 'apps.example.com', |
| 55 | + 'names': { |
| 56 | + 'kind': 'ClusterChangeMe', |
| 57 | + 'listKind': 'ClusterChangeMeList', |
| 58 | + 'plural': 'clusterchangemes', |
| 59 | + 'singular': 'clusterchangeme', |
| 60 | + }, |
| 61 | + 'scope': 'Cluster', |
| 62 | + 'version': 'v1', |
| 63 | + 'subresources': { |
| 64 | + 'status': {} |
| 65 | + } |
| 66 | + } |
| 67 | + } |
| 68 | + resp = crd_api.create(crd_manifest) |
| 69 | + |
| 70 | + self.assertEqual(name, resp.metadata.name) |
| 71 | + self.assertTrue(resp.status) |
| 72 | + |
| 73 | + resp = crd_api.get( |
| 74 | + name=name, |
| 75 | + ) |
| 76 | + self.assertEqual(name, resp.metadata.name) |
| 77 | + self.assertTrue(resp.status) |
| 78 | + |
| 79 | + try: |
| 80 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ClusterChangeMe') |
| 81 | + except ResourceNotFoundError: |
| 82 | + # Sometimes need to wait a sec for the discovery layer to get updated |
| 83 | + time.sleep(2) |
| 84 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ClusterChangeMe') |
| 85 | + resp = changeme_api.get() |
| 86 | + self.assertEqual(resp.items, []) |
| 87 | + changeme_name = 'custom-resource' + short_uuid() |
| 88 | + changeme_manifest = { |
| 89 | + 'apiVersion': 'apps.example.com/v1', |
| 90 | + 'kind': 'ClusterChangeMe', |
| 91 | + 'metadata': { |
| 92 | + 'name': changeme_name, |
| 93 | + }, |
| 94 | + 'spec': {} |
| 95 | + } |
| 96 | + |
| 97 | + resp = changeme_api.create(body=changeme_manifest) |
| 98 | + self.assertEqual(resp.metadata.name, changeme_name) |
| 99 | + |
| 100 | + resp = changeme_api.get(name=changeme_name) |
| 101 | + self.assertEqual(resp.metadata.name, changeme_name) |
| 102 | + |
| 103 | + changeme_manifest['spec']['size'] = 3 |
| 104 | + resp = changeme_api.patch( |
| 105 | + body=changeme_manifest, |
| 106 | + content_type='application/merge-patch+json' |
| 107 | + ) |
| 108 | + self.assertEqual(resp.spec.size, 3) |
| 109 | + |
| 110 | + resp = changeme_api.get(name=changeme_name) |
| 111 | + self.assertEqual(resp.spec.size, 3) |
| 112 | + |
| 113 | + resp = changeme_api.get() |
| 114 | + self.assertEqual(len(resp.items), 1) |
| 115 | + |
| 116 | + resp = changeme_api.delete( |
| 117 | + name=changeme_name, |
| 118 | + ) |
| 119 | + |
| 120 | + resp = changeme_api.get() |
| 121 | + self.assertEqual(len(resp.items), 0) |
| 122 | + |
| 123 | + resp = crd_api.delete( |
| 124 | + name=name, |
| 125 | + ) |
| 126 | + |
| 127 | + time.sleep(2) |
| 128 | + client.resources.invalidate_cache() |
| 129 | + with self.assertRaises(ResourceNotFoundError): |
| 130 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ClusterChangeMe') |
| 131 | + |
| 132 | + def test_namespaced_custom_resources(self): |
| 133 | + client = DynamicClient(api_client.ApiClient(configuration=self.config)) |
| 134 | + |
| 135 | + with self.assertRaises(ResourceNotFoundError): |
| 136 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ChangeMe') |
| 137 | + |
| 138 | + crd_api = client.resources.get(kind='CustomResourceDefinition') |
| 139 | + name = 'changemes.apps.example.com' |
| 140 | + crd_manifest = { |
| 141 | + 'apiVersion': 'apiextensions.k8s.io/v1beta1', |
| 142 | + 'kind': 'CustomResourceDefinition', |
48 | 143 | 'metadata': {
|
49 |
| - 'name': name |
| 144 | + 'name': name, |
50 | 145 | },
|
51 | 146 | 'spec': {
|
52 |
| - 'containers': [{ |
53 |
| - 'image': 'busybox', |
54 |
| - 'name': 'sleep', |
55 |
| - "args": [ |
56 |
| - "/bin/sh", |
57 |
| - "-c", |
58 |
| - "while true;do date;sleep 5; done" |
59 |
| - ] |
60 |
| - }] |
| 147 | + 'group': 'apps.example.com', |
| 148 | + 'names': { |
| 149 | + 'kind': 'ChangeMe', |
| 150 | + 'listKind': 'ChangeMeList', |
| 151 | + 'plural': 'changemes', |
| 152 | + 'singular': 'changeme', |
| 153 | + }, |
| 154 | + 'scope': 'Namespaced', |
| 155 | + 'version': 'v1', |
| 156 | + 'subresources': { |
| 157 | + 'status': {} |
| 158 | + } |
61 | 159 | }
|
62 | 160 | }
|
| 161 | + resp = crd_api.create(crd_manifest) |
63 | 162 |
|
64 |
| - resp = api.create(body=pod_manifest, namespace='default') |
65 | 163 | self.assertEqual(name, resp.metadata.name)
|
66 |
| - self.assertTrue(resp.status.phase) |
67 |
| - |
68 |
| - while True: |
69 |
| - resp = api.get(name=name, namespace='default') |
70 |
| - self.assertEqual(name, resp.metadata.name) |
71 |
| - self.assertTrue(resp.status.phase) |
72 |
| - if resp.status.phase != 'Pending': |
73 |
| - break |
74 |
| - time.sleep(1) |
75 |
| - |
76 |
| - exec_command = ['/bin/sh', |
77 |
| - '-c', |
78 |
| - 'for i in $(seq 1 3); do date; done'] |
79 |
| - resp = stream( |
80 |
| - api.subresources['exec'], |
81 |
| - name, |
82 |
| - 'default', |
83 |
| - command=exec_command, |
84 |
| - stderr=False, stdin=False, |
85 |
| - stdout=True, tty=False |
| 164 | + self.assertTrue(resp.status) |
| 165 | + |
| 166 | + resp = crd_api.get( |
| 167 | + name=name, |
| 168 | + ) |
| 169 | + self.assertEqual(name, resp.metadata.name) |
| 170 | + self.assertTrue(resp.status) |
| 171 | + |
| 172 | + try: |
| 173 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ChangeMe') |
| 174 | + except ResourceNotFoundError: |
| 175 | + # Sometimes need to wait a sec for the discovery layer to get updated |
| 176 | + time.sleep(2) |
| 177 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ChangeMe') |
| 178 | + resp = changeme_api.get() |
| 179 | + self.assertEqual(resp.items, []) |
| 180 | + changeme_name = 'custom-resource' + short_uuid() |
| 181 | + changeme_manifest = { |
| 182 | + 'apiVersion': 'apps.example.com/v1', |
| 183 | + 'kind': 'ChangeMe', |
| 184 | + 'metadata': { |
| 185 | + 'name': changeme_name, |
| 186 | + }, |
| 187 | + 'spec': {} |
| 188 | + } |
| 189 | + |
| 190 | + resp = changeme_api.create(body=changeme_manifest, namespace='default') |
| 191 | + self.assertEqual(resp.metadata.name, changeme_name) |
| 192 | + |
| 193 | + resp = changeme_api.get(name=changeme_name, namespace='default') |
| 194 | + self.assertEqual(resp.metadata.name, changeme_name) |
| 195 | + |
| 196 | + changeme_manifest['spec']['size'] = 3 |
| 197 | + resp = changeme_api.patch( |
| 198 | + body=changeme_manifest, |
| 199 | + namespace='default', |
| 200 | + content_type='application/merge-patch+json' |
86 | 201 | )
|
87 |
| - print('EXEC response : %s' % resp) |
88 |
| - self.assertEqual(3, len(resp.splitlines())) |
89 |
| - |
90 |
| - exec_command = 'uptime' |
91 |
| - resp = stream( |
92 |
| - api.subresources['exec'], |
93 |
| - name, |
94 |
| - 'default', |
95 |
| - command=exec_command, |
96 |
| - stderr=False, stdin=False, |
97 |
| - stdout=True, tty=False |
| 202 | + self.assertEqual(resp.spec.size, 3) |
| 203 | + |
| 204 | + resp = changeme_api.get(name=changeme_name, namespace='default') |
| 205 | + self.assertEqual(resp.spec.size, 3) |
| 206 | + |
| 207 | + resp = changeme_api.get(namespace='default') |
| 208 | + self.assertEqual(len(resp.items), 1) |
| 209 | + |
| 210 | + resp = changeme_api.get() |
| 211 | + self.assertEqual(len(resp.items), 1) |
| 212 | + |
| 213 | + resp = changeme_api.delete( |
| 214 | + name=changeme_name, |
| 215 | + namespace='default' |
98 | 216 | )
|
99 |
| - print('EXEC response : %s' % resp) |
100 |
| - self.assertEqual(1, len(resp.splitlines())) |
101 |
| - |
102 |
| - resp = stream( |
103 |
| - api.subresources['exec'], |
104 |
| - name, |
105 |
| - 'default', |
106 |
| - command='/bin/sh', |
107 |
| - stderr=False, stdin=False, |
108 |
| - stdout=True, tty=False, |
109 |
| - _preload_content=False |
| 217 | + |
| 218 | + resp = changeme_api.get(namespace='default') |
| 219 | + self.assertEqual(len(resp.items), 0) |
| 220 | + |
| 221 | + resp = changeme_api.get() |
| 222 | + self.assertEqual(len(resp.items), 0) |
| 223 | + |
| 224 | + resp = crd_api.delete( |
| 225 | + name=name, |
110 | 226 | )
|
111 |
| - resp.write_stdin("echo test string 1\n") |
112 |
| - line = resp.readline_stdout(timeout=5) |
113 |
| - self.assertFalse(resp.peek_stderr()) |
114 |
| - self.assertEqual("test string 1", line) |
115 |
| - resp.write_stdin("echo test string 2 >&2\n") |
116 |
| - line = resp.readline_stderr(timeout=5) |
117 |
| - self.assertFalse(resp.peek_stdout()) |
118 |
| - self.assertEqual("test string 2", line) |
119 |
| - resp.write_stdin("exit\n") |
120 |
| - resp.update(timeout=5) |
121 |
| - line = resp.read_channel(ERROR_CHANNEL) |
122 |
| - status = json.loads(line) |
123 |
| - self.assertEqual(status['status'], 'Success') |
124 |
| - resp.update(timeout=5) |
125 |
| - self.assertFalse(resp.is_open()) |
126 |
| - |
127 |
| - number_of_pods = len(api.get().items) |
128 |
| - self.assertTrue(number_of_pods > 0) |
129 |
| - |
130 |
| - resp = api.delete(name=name, body={}, namespace='default') |
| 227 | + |
| 228 | + time.sleep(2) |
| 229 | + client.resources.invalidate_cache() |
| 230 | + with self.assertRaises(ResourceNotFoundError): |
| 231 | + changeme_api = client.resources.get(api_version='apps.example.com/v1', kind='ChangeMe') |
131 | 232 |
|
132 | 233 | def test_service_apis(self):
|
133 | 234 | client = DynamicClient(api_client.ApiClient(configuration=self.config))
|
@@ -242,14 +343,13 @@ def test_configmap_apis(self):
|
242 | 343 | resp = api.delete(
|
243 | 344 | name=name, body={}, namespace='default')
|
244 | 345 |
|
245 |
| - resp = api.get('default', pretty=True) |
| 346 | + resp = api.get(namespace='default', pretty=True) |
246 | 347 | self.assertEqual([], resp.items)
|
247 | 348 |
|
248 | 349 | def test_node_apis(self):
|
249 | 350 | client = DynamicClient(api_client.ApiClient(configuration=self.config))
|
250 | 351 | api = client.resources.get(api_version='v1', kind='Node')
|
251 | 352 |
|
252 | 353 | for item in api.get().items:
|
253 |
| - node = api.read_node(name=item.metadata.name) |
254 |
| - self.assertTrue(len(node.metadata.labels) > 0) |
255 |
| - self.assertTrue(isinstance(node.metadata.labels, dict)) |
| 354 | + node = api.get(name=item.metadata.name) |
| 355 | + self.assertTrue(len(dict(node.metadata.labels)) > 0) |
0 commit comments