generated from renoki-co/laravel-package-skeleton
-
-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathKubernetesCluster.php
398 lines (357 loc) · 20.2 KB
/
KubernetesCluster.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
<?php
namespace RenokiCo\PhpK8s;
use Closure;
use Illuminate\Support\Str;
use RenokiCo\PhpK8s\Exceptions\KubernetesAPIException;
use RenokiCo\PhpK8s\Kinds\K8sResource;
/**
* @method \RenokiCo\PhpK8s\Kinds\K8sNode node(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sNode getNodeByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllNodes(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sEvent event(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sEvent getEventByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllEventsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllEvents(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sNamespace namespace(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sNamespace getNamespaceByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllNamespaces(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sConfigMap configmap(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sConfigMap getConfigmapByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllConfigmapsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllConfigmaps(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sSecret secret(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sSecret getSecretByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllSecretsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllSecrets(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sIngress ingress(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sIngress getIngressByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllIngressesFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllIngresses(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sService service(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sService getServiceByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllServicesFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllServices(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sStorageClass storageClass(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sStorageClass getStorageClassByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllStorageClassesFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllStorageClasses(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sPersistentVolume persistentVolume(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sPersistentVolume getPersistentVolumeByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPersistentVolumesFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPersistentVolumes(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sPersistentVolumeClaim persistentVolumeClaim(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sPersistentVolumeClaim getPersistentVolumeClaimByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPersistentVolumeClaimsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPersistentVolumeClaims(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sPod pod(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sPod getPodByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPodsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPods(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sStatefulSet statefulSet(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sStatefulSet getStatefulSetByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllStatefulSetsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllStatefulSets(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sDeployment deployment(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sDeployment getDeploymentByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllDeploymentsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllDeployments(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sJob job(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sJob getJobByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllJobsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllJobs(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sCronJob cronjob(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sCronJob getCronjobByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllCronjobsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllCronjobs(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sDaemonSet daemonSet(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sDaemonSet getDaemonSetByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllDaemonSetsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllDaemonSets(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sHorizontalPodAutoscaler horizontalPodAutoscaler(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sHorizontalPodAutoscaler getHorizontalPodAutoscalerByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllHorizontalPodAutoscalersFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllHorizontalPodAutoscalers(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sServiceAccount serviceAccount(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sServiceAccount getServiceAccountByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllServiceAccountsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllServiceAccounts(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sRole role(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sRole getRoleByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllRolesFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllRoles(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sClusterRole clusterRole(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sClusterRole getClusterRoleByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllClusterRolesFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllClusterRoles(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sRoleBinding roleBinding(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sRoleBinding getRoleBindingByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllRoleBindingsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllRoleBindings(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sClusterRoleBinding clusterRoleBinding(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sClusterRoleBinding getClusterRoleBindingByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllClusterRoleBindingsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllClusterRoleBindings(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sPodDisruptionBudget podDisruptionBudget(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sPodDisruptionBudget getPodDisruptionBudgetByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPodDisruptionBudgetsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllPodDisruptionBudgets(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sValidatingWebhookConfiguration validatingWebhookConfiguration(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sValidatingWebhookConfiguration getValidatingWebhookConfigurationByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllValidatingWebhookConfigurationsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllValidatingWebhookConfiguration(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sMutatingWebhookConfiguration mutatingWebhookConfiguration(array $attributes = [])
* @method \RenokiCo\PhpK8s\Kinds\K8sMutatingWebhookConfiguration getMutatingWebhookConfigurationByName(string $name, string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllMutatingWebhookConfigurationsFromAllNamespaces(array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\ResourcesList getAllMutatingWebhookConfiguration(string $namespace = 'default', array $query = ['pretty' => 1])
* @method \RenokiCo\PhpK8s\Kinds\K8sResource|array[\RenokiCo\PhpK8s\Kinds\K8sResource] fromYaml(string $yaml)
* @method \RenokiCo\PhpK8s\Kinds\K8sResource|array[\RenokiCo\PhpK8s\Kinds\K8sResource] fromYamlFile(string $path, \Closure $callback = null)
* @method \RenokiCo\PhpK8s\Kinds\K8sResource|array[\RenokiCo\PhpK8s\Kinds\K8sResource] fromTemplatedYamlFile(string $path, array $replace, \Closure $callback = null)
* @method static void registerCrd(string $class, string $name = null)
*
* @see \RenokiCo\PhpK8s\K8s
*/
class KubernetesCluster
{
use Traits\Cluster\AuthenticatesCluster;
use Traits\Cluster\ChecksClusterVersion;
use Traits\Cluster\LoadsFromKubeConfig;
use Traits\Cluster\MakesHttpCalls;
use Traits\Cluster\MakesWebsocketCalls;
/**
* The Cluster API port.
*
* @var string
*/
protected $url;
/**
* The class name for the K8s resource.
*
* @var string
*/
protected $resourceClass;
/**
* List all named operations with
* their respective methods for the
* HTTP request.
*
* @var array
*/
protected static $operations = [
self::GET_OP => 'GET',
self::CREATE_OP => 'POST',
self::REPLACE_OP => 'PUT',
self::DELETE_OP => 'DELETE',
self::LOG_OP => 'GET',
self::WATCH_OP => 'GET',
self::WATCH_LOGS_OP => 'GET',
self::EXEC_OP => 'POST',
self::ATTACH_OP => 'POST',
];
const GET_OP = 'get';
const CREATE_OP = 'create';
const REPLACE_OP = 'replace';
const DELETE_OP = 'delete';
const LOG_OP = 'logs';
const WATCH_OP = 'watch';
const WATCH_LOGS_OP = 'watch_logs';
const EXEC_OP = 'exec';
const ATTACH_OP = 'attach';
/**
* Create a new class instance.
*
* @param string|null $url
* @return void
*/
public function __construct(string $url = null)
{
$this->url = $url;
}
/**
* Set the K8s resource class.
*
* @param string $resourceClass
* @return $this
*/
public function setResourceClass(string $resourceClass)
{
$this->resourceClass = $resourceClass;
return $this;
}
/**
* Run a specific operation for the API path with a specific payload.
*
* @param string $operation
* @param string $path
* @param string|null|Closure $payload
* @param array $query
* @return mixed
*
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesAPIException
*/
public function runOperation(string $operation, string $path, $payload = '', array $query = ['pretty' => 1])
{
switch ($operation) {
case static::WATCH_OP: return $this->watchPath($path, $payload, $query);
break;
case static::WATCH_LOGS_OP: return $this->watchLogsPath($path, $payload, $query);
break;
case static::EXEC_OP: return $this->execPath($path, $query);
break;
case static::ATTACH_OP: return $this->attachPath($path, $payload, $query);
break;
default: break;
}
$method = static::$operations[$operation] ?? static::$operations[static::GET_OP];
return $this->makeRequest($method, $path, $payload, $query);
}
/**
* Watch for the current resource or a resource list.
*
* @param string $path
* @param Closure $callback
* @param array $query
* @return bool
*/
protected function watchPath(string $path, Closure $callback, array $query = ['pretty' => 1])
{
$resourceClass = $this->resourceClass;
$sock = $this->createSocketConnection($this->getCallableUrl($path, $query));
$data = null;
while (($data = fgets($sock)) == true) {
$data = @json_decode($data, true);
['type' => $type, 'object' => $attributes] = $data;
$call = call_user_func(
$callback,
$type,
new $resourceClass($this, $attributes)
);
if (! is_null($call)) {
fclose($sock);
unset($data);
return $call;
}
}
}
/**
* Watch for the logs for the resource.
*
* @param string $path
* @param Closure $callback
* @param array $query
* @return bool
*/
protected function watchLogsPath(string $path, Closure $callback, array $query = ['pretty' => 1])
{
$sock = $this->createSocketConnection($this->getCallableUrl($path, $query));
$data = null;
while (($data = fgets($sock)) == true) {
$call = call_user_func($callback, $data);
if (! is_null($call)) {
fclose($sock);
unset($data);
return $call;
}
}
}
/**
* Call exec on the resource.
*
* @param string $path
* @param array $query
* @return mixed
*
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesAPIException
*/
protected function execPath(
string $path,
array $query = ['pretty' => 1, 'stdin' => 1, 'stdout' => 1, 'stderr' => 1, 'tty' => 1]
) {
try {
return $this->makeRequest(static::$operations[static::EXEC_OP], $path, '', $query);
} catch (KubernetesAPIException $e) {
$payload = $e->getPayload();
// Check of the request needs upgrade and make a call to WS if needed.
if (
$payload['code'] === 400 &&
$payload['status'] === 'Failure' &&
$payload['message'] === 'Upgrade request required'
) {
return $this->makeWsRequest($path, null, $query);
}
throw $e;
}
}
/**
* Call attach on the resource.
*
* @param string $path
* @param Closure $callback
* @param array $query
* @return mixed
*
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesAPIException
*/
protected function attachPath(
string $path,
Closure $callback,
array $query = ['pretty' => 1, 'stdin' => 1, 'stdout' => 1, 'stderr' => 1, 'tty' => 1]
) {
try {
return $this->makeRequest(static::$operations[static::ATTACH_OP], $path, '', $query);
} catch (KubernetesAPIException $e) {
$payload = $e->getPayload();
// Check of the request needs upgrade and make a call to WS if needed.
if (
$payload['code'] === 400 &&
$payload['status'] === 'Failure' &&
$payload['message'] === 'Upgrade request required'
) {
return $this->makeWsRequest($path, $callback, $query);
}
throw $e;
}
}
/**
* Proxy the custom method to the K8s class.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
// Proxy the ->get[Resource]ByName($name, $namespace = 'default')
// For example, ->getConfigMapByName('settings')
if (preg_match('/get(.+)ByName/', $method, $matches)) {
[$method, $resource] = $matches;
// Check the method from the proxied K8s::class exists.
// For example, the method ->configmap() should exist.
if (method_exists(K8s::class, $resource)) {
return $this->{$resource}()
->whereNamespace($parameters[1] ?? K8sResource::$defaultNamespace)
->getByName($parameters[0], $parameters[2] ?? ['pretty' => 1]);
}
}
// Proxy the ->getAll[Resources]FromAllNamespaces($query = [...])
// For example, ->getAllIngressesFromAllNamespaces()
if (preg_match('/getAll(.+)FromAllNamespaces/', $method, $matches)) {
[$method, $resourcePlural] = $matches;
$resource = Str::singular($resourcePlural);
if (method_exists(K8s::class, $resource)) {
return $this->{$resource}()->allNamespaces($parameters[0] ?? ['pretty' => 1]);
}
}
// Proxy the ->getAll[Resources]($namespace = 'default', $query = [...])
// For example, ->getAllServices('staging')
if (preg_match('/getAll(.+)/', $method, $matches)) {
[$method, $resourcePlural] = $matches;
$resource = Str::singular($resourcePlural);
if (method_exists(K8s::class, $resource)) {
return $this->{$resource}()
->whereNamespace($parameters[0] ?? K8sResource::$defaultNamespace)
->all($parameters[1] ?? ['pretty' => 1]);
}
}
return K8s::{$method}($this, ...$parameters);
}
}