From 26f5ca951b6ffc5e8d96054bcc220d255c8e61a6 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Wed, 23 Dec 2020 03:57:58 +0200 Subject: [PATCH 1/7] wip affinity --- docs/RESOURCES.md | 2 + docs/instances/Affinity.md | 43 ++++++++++++++ docs/instances/Expression.md | 31 ++++++++++ docs/kinds/Pod.md | 15 ++++- src/Instances/Affinity.php | 105 ++++++++++++++++++++++++++++++--- src/K8s.php | 22 +++++++ src/Kinds/K8sPod.php | 15 +++++ tests/AffinityTest.php | 109 +++++++++++++++++++++++++++++++++++ tests/ExpressionTest.php | 74 ++++++++++++++++++++++++ 9 files changed, 405 insertions(+), 11 deletions(-) create mode 100644 docs/instances/Affinity.md create mode 100644 docs/instances/Expression.md create mode 100644 tests/AffinityTest.php create mode 100644 tests/ExpressionTest.php diff --git a/docs/RESOURCES.md b/docs/RESOURCES.md index 9a3dabd1..a484dfaf 100644 --- a/docs/RESOURCES.md +++ b/docs/RESOURCES.md @@ -10,8 +10,10 @@ Instances are custom classes that makes the build of containers, for example, more object-oriented that passing an array. +- [Affinity](instances/Affinity.md) - used to declare affinities and anti-affinities - [Container](instances/Container.md) - used for Pods & Templates - [Container Probes](instances/Probes.md) - used for Pods' Probes +- [Expressions](instances/Expression.md) - used for various match/fields expressions - [Resource Metrics](instances/Metrics.md) - used for Horizontal Pod Autoscalers - [Rules](instances/Rules.md) - used for Roles & Cluster Roles - [Volumes](instances/Volumes.md) - used for mounting volumes in pods and containers diff --git a/docs/instances/Affinity.md b/docs/instances/Affinity.md new file mode 100644 index 00000000..df064bdc --- /dev/null +++ b/docs/instances/Affinity.md @@ -0,0 +1,43 @@ +# Affinity + +Affinities work with the help of [Expressions](Expression.md) to specify inclusions and exclusions for particular needs. + +## preferredDuringSchedulingIgnoredDuringExecution + +`preferredDuringSchedulingIgnoredDuringExecution` option is exposed in the affinity instance as `addPreference`: + +```php +use RenokiCo\PhpK8s\K8s; + +$az = K8s::expression()->in('azname', ['us-east-1a', 'us-east-1b']); +$tier = K8s::expression()->in('tier', ['backend']); + +$affinity = K8s::affinity()->addPreference([$az], [], 100); // weight: 100 +``` + +For `nodeSelectorTerms`, you can use `addNodeSelectorPreference()` with the same parameters. + +## requiredDuringSchedulingIgnoredDuringExecution + +`requiredDuringSchedulingIgnoredDuringExecution` option is exposed in the affinity instance as `addNodeRequirement`: + +```php +use RenokiCo\PhpK8s\K8s; + +$az = K8s::expression()->in('azname', ['us-east-1a', 'us-east-1b']); +$tier = K8s::expression()->in('tier', ['backend']); + +$affinity = K8s::affinity()->addNodeRequirement([$az], [$type]); // requires AZ and tier: backend +``` + +For Label Selector requirement, use `addLabelSelectorRequirement`: + +```php +use RenokiCo\PhpK8s\K8s; + +$az = K8s::expression()->in('azname', ['us-east-1a', 'us-east-1b']); +$tier = K8s::expression()->in('tier', ['backend']); + +// requires AZ and tier: backend with given topology +$affinity = K8s::affinity()->addLabelSelectorRequirement([$az], [$type], 'aws.amazonaws.io/some-topology'); +``` diff --git a/docs/instances/Expression.md b/docs/instances/Expression.md new file mode 100644 index 00000000..e696731e --- /dev/null +++ b/docs/instances/Expression.md @@ -0,0 +1,31 @@ +# Expression + +## In & Not In + +```php +use RenokiCo\PhpK8s\K8s; + +K8s::expression()->in('some-key', ['value1', 'value2']); + +K8s::expression()->notIn('some-key', ['value1', 'value2']); +``` + +## Exists & Does Not Exist + +```php +use RenokiCo\PhpK8s\K8s; + +K8s::expression()->exists('some-key'); + +K8s::expression()->doesNotexist('some-key'); +``` + +## Greater & Less Than + +```php +use RenokiCo\PhpK8s\K8s; + +K8s::expression()->greaterThan('some-key', '1'); + +K8s::expression()->lessThan('some-key', '1'); +``` diff --git a/docs/kinds/Pod.md b/docs/kinds/Pod.md index d85964ed..a5429859 100644 --- a/docs/kinds/Pod.md +++ b/docs/kinds/Pod.md @@ -35,6 +35,17 @@ $pod = $cluster->pod() Pods can attach volumes so that container can mount them. Please check the [Container documentation](../instances/Container.md) where you can find details on how to attach volumes for different drivers. +## Attaching affinities & anti-affinities + +Pods can declare `affinity` to handle pod and node affinities and anti-affinities. Check [Affinity documentation](../instances/Affinity.md) to read more about the pod affinity and anti-affinity declarations. + +You can simply attach affinities for both pod and node by calling specialized methods: + +```php +$pod->setPodAffinity($affinity); +$pod->setNodeAffinity($affinity); +``` + ## Container Retrieval Retrieving the containers and init containers can be retrieved as an array of `\RenokiCo\PhpK8s\Instances\Container` classes or as an array. @@ -59,9 +70,7 @@ foreach ($containers as $container) { ## Pod Logs -Pods can contain logs, and PHP K8s is good at it. Before checking how it works, please see the [Live Tracking](../../README.md#live-tracking) section from README to see how the closures really work at interpreting the real-time data in Kubernetes. - -Retrieve a single string with all logs until the point of call: +Pods can contain logs, and PHP K8s is good at it. You can retrieve a single string with all logs until the point of call: ```php // Simple logging, no watcher diff --git a/src/Instances/Affinity.php b/src/Instances/Affinity.php index 0dad4ab8..f77b6b94 100644 --- a/src/Instances/Affinity.php +++ b/src/Instances/Affinity.php @@ -8,10 +8,11 @@ class Affinity extends Instance * Add a preference affinity. * * @param array $expressions + * @param array $fieldsExpressions * @param int $weight * @return $this */ - public function addPreference(array $expressions, int $weight = 1) + public function addPreference(array $expressions, array $fieldsExpressions, int $weight = 1) { foreach ($expressions as &$expression) { if ($expression instanceof Expression) { @@ -19,22 +20,70 @@ public function addPreference(array $expressions, int $weight = 1) } } + foreach ($fieldsExpressions as &$expression) { + if ($expression instanceof Expression) { + $expression = $expression->toArray(); + } + } + + $preference = [ + 'matchExpressions' => $expressions, + ]; + + if ($fieldsExpressions) { + $preference['matchFields'] = $fieldsExpressions; + } + return $this->addToAttribute('preferredDuringSchedulingIgnoredDuringExecution', [ 'weight' => $weight, - 'preference' => [ - 'matchExpressions' => $expressions, - ], + 'preference' => $preference, + ]); + } + + /** + * Add a preference affinity for nodeSelector. + * + * @param array $expressions + * @param array $fieldsExpressions + * @param int $weight + * @return $this + */ + public function addNodeSelectorPreference(array $expressions, array $fieldsExpressions, int $weight = 1) + { + foreach ($expressions as &$expression) { + if ($expression instanceof Expression) { + $expression = $expression->toArray(); + } + } + + foreach ($fieldsExpressions as &$expression) { + if ($expression instanceof Expression) { + $expression = $expression->toArray(); + } + } + + $preference = [ + 'matchExpressions' => $expressions, + ]; + + if ($fieldsExpressions) { + $preference['matchFields'] = $fieldsExpressions; + } + + return $this->addToAttribute('preferredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms', [ + 'weight' => $weight, + 'preference' => $preference, ]); } /** - * Add a required affinity. + * Add a required affinity for nodeSelector. * * @param array $expressions * @param array $fieldsExpressions * @return $this */ - public function addRequire(array $expressions, array $fieldsExpressions) + public function addNodeRequirement(array $expressions, array $fieldsExpressions) { foreach ($expressions as &$expression) { if ($expression instanceof Expression) { @@ -48,10 +97,50 @@ public function addRequire(array $expressions, array $fieldsExpressions) } } + $requirement = [ + 'matchExpressions' => $expressions, + ]; + if ($fieldsExpressions) { - $this->addToAttribute('requiredDuringSchedulingIgnoredDuringExecution.matchFields', $fieldsExpressions); + $requirement['matchFields'] = $fieldsExpressions; } - return $this->addToAttribute('requiredDuringSchedulingIgnoredDuringExecution.matchExpressions', $expressions); + return $this->addToAttribute('requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms', $requirement); + } + + /** + * Add a required affinity for nodeSelector. + * + * @param array $expressions + * @param array $fieldsExpressions + * @param string $topologyKey + * @return $this + */ + public function addLabelSelectorRequirement(array $expressions, array $fieldsExpressions, string $topologyKey) + { + foreach ($expressions as &$expression) { + if ($expression instanceof Expression) { + $expression = $expression->toArray(); + } + } + + foreach ($fieldsExpressions as &$expression) { + if ($expression instanceof Expression) { + $expression = $expression->toArray(); + } + } + + $requirement = [ + 'matchExpressions' => $expressions, + ]; + + if ($fieldsExpressions) { + $requirement['matchFields'] = $fieldsExpressions; + } + + return $this->addToAttribute('requiredDuringSchedulingIgnoredDuringExecution', [ + 'labelSelector' => $requirement, + 'topologyKey' => $topologyKey, + ]); } } diff --git a/src/K8s.php b/src/K8s.php index 7c377e94..24e20f20 100644 --- a/src/K8s.php +++ b/src/K8s.php @@ -321,6 +321,28 @@ public static function volume(array $attributes = []) return new Instances\Volume($attributes); } + /** + * Create a new affinity instance. + * + * @param array $attributes + * @return \RenokiCo\PhpK8s\Instances\Affinity + */ + public static function affinity(array $attributes = []) + { + return new Instances\Affinity($attributes); + } + + /** + * Create a new expression instance. + * + * @param array $attributes + * @return \RenokiCo\PhpK8s\Instances\Expression + */ + public static function expression(array $attributes = []) + { + return new Instances\Expression($attributes); + } + /** * Load Kind configuration from an YAML text. * diff --git a/src/Kinds/K8sPod.php b/src/Kinds/K8sPod.php index 4f30c447..7bd5af70 100644 --- a/src/Kinds/K8sPod.php +++ b/src/Kinds/K8sPod.php @@ -253,6 +253,21 @@ public function setNodeAffinity($affinity) return $this->setSpec('affinity.nodeAffinity', $affinity); } + /** + * Set the pod affinity. + * + * @param \RenokiCo\PhpK8s\Instances\Affinity $affinity + * @return $this + */ + public function setPodAffinity($affinity) + { + if ($affinity instanceof Affinity) { + $affinity = $affinity->toArray(); + } + + return $this->setSpec('affinity.podAffinity', $affinity); + } + /** * Transform any Container instance to an array. * diff --git a/tests/AffinityTest.php b/tests/AffinityTest.php new file mode 100644 index 00000000..1eb3c931 --- /dev/null +++ b/tests/AffinityTest.php @@ -0,0 +1,109 @@ +addPreference( + [K8s::expression()->in('azname', ['us-east-1a'])], + [K8s::expression()->in('tier', ['backend'])], + 100 + ); + + $this->assertEquals([ + 'preferredDuringSchedulingIgnoredDuringExecution' => [ + [ + 'weight' => 100, + 'preference' => [ + 'matchExpressions' => [ + ['key' => 'azname', 'operator' => 'In', 'values' => ['us-east-1a']], + ], + 'matchFields' => [ + ['key' => 'tier', 'operator' => 'In', 'values' => ['backend']], + ], + ], + ], + ], + ], $affinity->toArray()); + } + + public function test_affinity_preferredDuringSchedulingIgnoredDuringExecution_with_node_selector() + { + $affinity = K8s::affinity()->addNodeSelectorPreference( + [K8s::expression()->in('azname', ['us-east-1a'])], + [K8s::expression()->in('tier', ['backend'])], + 100 + ); + + $this->assertEquals([ + 'preferredDuringSchedulingIgnoredDuringExecution' => [ + 'nodeSelectorTerms' => [ + [ + 'weight' => 100, + 'preference' => [ + 'matchExpressions' => [ + ['key' => 'azname', 'operator' => 'In', 'values' => ['us-east-1a']], + ], + 'matchFields' => [ + ['key' => 'tier', 'operator' => 'In', 'values' => ['backend']], + ], + ], + ], + ], + ], + ], $affinity->toArray()); + } + + public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_with_node_selector() + { + $affinity = K8s::affinity()->addNodeRequirement( + [K8s::expression()->in('azname', ['us-east-1a'])], + [K8s::expression()->in('tier', ['backend'])] + ); + + $this->assertEquals([ + 'requiredDuringSchedulingIgnoredDuringExecution' => [ + 'nodeSelectorTerms' => [ + [ + 'matchExpressions' => [ + ['key' => 'azname', 'operator' => 'In', 'values' => ['us-east-1a']], + ], + 'matchFields' => [ + ['key' => 'tier', 'operator' => 'In', 'values' => ['backend']], + ], + ], + ], + ], + ], $affinity->toArray()); + } + + public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_with_label_selector() + { + $affinity = K8s::affinity()->addLabelSelectorRequirement( + [K8s::expression()->in('azname', ['us-east-1a'])], + [K8s::expression()->in('tier', ['backend'])], + 'aws.amazonaws.com/some-topology' + ); + + $this->assertEquals([ + 'requiredDuringSchedulingIgnoredDuringExecution' => [ + [ + 'labelSelector' => [ + 'matchExpressions' => [ + ['key' => 'azname', 'operator' => 'In', 'values' => ['us-east-1a']], + ], + 'matchFields' => [ + ['key' => 'tier', 'operator' => 'In', 'values' => ['backend']], + ], + ], + 'topologyKey' => 'aws.amazonaws.com/some-topology', + ], + ], + ], $affinity->toArray()); + } +} diff --git a/tests/ExpressionTest.php b/tests/ExpressionTest.php new file mode 100644 index 00000000..7cb03836 --- /dev/null +++ b/tests/ExpressionTest.php @@ -0,0 +1,74 @@ +in('some-key', ['val1', 'val2']); + + $this->assertEquals([ + 'key' => 'some-key', + 'operator' => 'In', + 'values' => ['val1', 'val2'], + ], $expression->toArray()); + } + + public function test_expression_not_in() + { + $expression = K8s::expression()->notIn('some-key', ['val1', 'val2']); + + $this->assertEquals([ + 'key' => 'some-key', + 'operator' => 'NotIn', + 'values' => ['val1', 'val2'], + ], $expression->toArray()); + } + + public function test_expression_exists() + { + $expression = K8s::expression()->exists('some-key'); + + $this->assertEquals([ + 'key' => 'some-key', + 'operator' => 'Exists', + 'values' => [], + ], $expression->toArray()); + } + + public function test_expression_does_not_exist() + { + $expression = K8s::expression()->doesNotExist('some-key'); + + $this->assertEquals([ + 'key' => 'some-key', + 'operator' => 'DoesNotExists', + 'values' => [], + ], $expression->toArray()); + } + + public function test_expression_greater_than() + { + $expression = K8s::expression()->greaterThan('some-key', '1'); + + $this->assertEquals([ + 'key' => 'some-key', + 'operator' => 'Gt', + 'values' => ['1'], + ], $expression->toArray()); + } + + public function test_expression_less_than() + { + $expression = K8s::expression()->lessThan('some-key', '1'); + + $this->assertEquals([ + 'key' => 'some-key', + 'operator' => 'Lt', + 'values' => ['1'], + ], $expression->toArray()); + } +} From aa98704065b577ebaeec8316ec499ea99baca026 Mon Sep 17 00:00:00 2001 From: rennokki Date: Wed, 23 Dec 2020 15:52:57 +0000 Subject: [PATCH 2/7] Apply fixes from StyleCI --- tests/AffinityTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/AffinityTest.php b/tests/AffinityTest.php index 1eb3c931..0b7e6229 100644 --- a/tests/AffinityTest.php +++ b/tests/AffinityTest.php @@ -2,7 +2,6 @@ namespace RenokiCo\PhpK8s\Test; -use RenokiCo\PhpK8s\Instances\Affinity; use RenokiCo\PhpK8s\K8s; class AffinityTest extends TestCase From ca91858b5d37de3a6a1721ee71d7f347fde566d2 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Thu, 24 Dec 2020 17:24:16 +0200 Subject: [PATCH 3/7] Set node affinities on the pod --- src/Kinds/K8sPod.php | 34 ++++++++++++++++++++++++++++++++++ tests/AffinityTest.php | 16 ++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/Kinds/K8sPod.php b/src/Kinds/K8sPod.php index 7bd5af70..f0926dfe 100644 --- a/src/Kinds/K8sPod.php +++ b/src/Kinds/K8sPod.php @@ -253,6 +253,23 @@ public function setNodeAffinity($affinity) return $this->setSpec('affinity.nodeAffinity', $affinity); } + /** + * Get the node affinity. + * + * @param bool $asInstance + * @return array|\RenokiCo\PhpK8s\Instances\Affinity + */ + public function getNodeAffinity(bool $asInstance = true) + { + $affinity = $this->getSpec('affinity.nodeAffinity', null); + + if (! $affinity) { + return; + } + + return $asInstance ? new Affinity($affinity) : $affinity; + } + /** * Set the pod affinity. * @@ -268,6 +285,23 @@ public function setPodAffinity($affinity) return $this->setSpec('affinity.podAffinity', $affinity); } + /** + * Get the pod affinity. + * + * @param bool $asInstance + * @return array|\RenokiCo\PhpK8s\Instances\Affinity + */ + public function getPodAffinity(bool $asInstance = true) + { + $affinity = $this->getSpec('affinity.podAffinity', null); + + if (! $affinity) { + return; + } + + return $asInstance ? new Affinity($affinity) : $affinity; + } + /** * Transform any Container instance to an array. * diff --git a/tests/AffinityTest.php b/tests/AffinityTest.php index 1eb3c931..edcc6b29 100644 --- a/tests/AffinityTest.php +++ b/tests/AffinityTest.php @@ -15,6 +15,8 @@ public function test_affinity_preferredDuringSchedulingIgnoredDuringExecution_wi 100 ); + $pod = K8s::pod()->setPodAffinity($affinity); + $this->assertEquals([ 'preferredDuringSchedulingIgnoredDuringExecution' => [ [ @@ -29,7 +31,7 @@ public function test_affinity_preferredDuringSchedulingIgnoredDuringExecution_wi ], ], ], - ], $affinity->toArray()); + ], $pod->getPodAffinity()->toArray()); } public function test_affinity_preferredDuringSchedulingIgnoredDuringExecution_with_node_selector() @@ -40,6 +42,8 @@ public function test_affinity_preferredDuringSchedulingIgnoredDuringExecution_wi 100 ); + $pod = K8s::pod()->setNodeAffinity($affinity); + $this->assertEquals([ 'preferredDuringSchedulingIgnoredDuringExecution' => [ 'nodeSelectorTerms' => [ @@ -56,7 +60,7 @@ public function test_affinity_preferredDuringSchedulingIgnoredDuringExecution_wi ], ], ], - ], $affinity->toArray()); + ], $pod->getNodeAffinity()->toArray()); } public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_with_node_selector() @@ -66,6 +70,8 @@ public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_wit [K8s::expression()->in('tier', ['backend'])] ); + $pod = K8s::pod()->setNodeAffinity($affinity); + $this->assertEquals([ 'requiredDuringSchedulingIgnoredDuringExecution' => [ 'nodeSelectorTerms' => [ @@ -79,7 +85,7 @@ public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_wit ], ], ], - ], $affinity->toArray()); + ], $pod->getNodeAffinity()->toArray()); } public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_with_label_selector() @@ -90,6 +96,8 @@ public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_wit 'aws.amazonaws.com/some-topology' ); + $pod = K8s::pod()->setNodeAffinity($affinity); + $this->assertEquals([ 'requiredDuringSchedulingIgnoredDuringExecution' => [ [ @@ -104,6 +112,6 @@ public function test_affinity_requiredDuringSchedulingIgnoredDuringExecution_wit 'topologyKey' => 'aws.amazonaws.com/some-topology', ], ], - ], $affinity->toArray()); + ], $pod->getNodeAffinity()->toArray()); } } From 52e358586dc003a644f33e80cbf8f2ae898084ba Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Thu, 24 Dec 2020 17:55:37 +0200 Subject: [PATCH 4/7] Added nodes --- README.md | 1 + docs/RESOURCES.md | 6 +--- docs/kinds/Node.md | 19 ++++++++++++ src/K8s.php | 12 ++++++++ src/Kinds/K8sNode.php | 70 +++++++++++++++++++++++++++++++++++++++++++ tests/NodeTest.php | 66 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 docs/kinds/Node.md create mode 100644 src/Kinds/K8sNode.php create mode 100644 tests/NodeTest.php diff --git a/README.md b/README.md index 740444ce..8b9385eb 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ This package is Work in Progress and while there is in active development, PRs a Each existent resource has its own documentation, filled with examples: +- [Nodes](docs/kinds/Node.md) - [Namespaces](docs/kinds/Namespace.md) - [Config Maps](docs/kinds/ConfigMap.md) - [Secrets](docs/kinds/Secret.md) diff --git a/docs/RESOURCES.md b/docs/RESOURCES.md index a484dfaf..df86cf9f 100644 --- a/docs/RESOURCES.md +++ b/docs/RESOURCES.md @@ -24,6 +24,7 @@ Each resource inherits a default "base" class that is making the Resource build- **Check the documentation for [General Resources](kinds/Resource.md) and [K8s API Usage](Usage.md) before diving in to the actual resources documentation.** +- [Nodes](kinds/Node.md) - [Namespaces](kinds/Namespace.md) - [Config Maps](kinds/ConfigMap.md) - [Secrets](kinds/Secret.md) @@ -62,11 +63,6 @@ The following list of resources are work in progress and they will be available - poddisruptionbudgets - podsecuritypolicies -The following concepts are work in progress as instances: - -- pod affinity -- node affinity - # Discussable The following list of resources might not be useful for the basic needs, so they will be gladly accepted via PR in case there is a need of the resources or they might get discussed and implemented after further reasearch on the structure of the resource. diff --git a/docs/kinds/Node.md b/docs/kinds/Node.md new file mode 100644 index 00000000..62f2bb97 --- /dev/null +++ b/docs/kinds/Node.md @@ -0,0 +1,19 @@ +# Node + +- [Official Documentation](https://kubernetes.io/docs/concepts/architecture/nodes/) + +## Example + +```php +$nodes = K8s::node()->all(); + +foreach ($nodes as $node) { + $node->getInfo(); + + $node->getImages(); + + $node->getCapacity(); + + $node->getAllocatableInfo(); +} +``` diff --git a/src/K8s.php b/src/K8s.php index 24e20f20..bffc93f5 100644 --- a/src/K8s.php +++ b/src/K8s.php @@ -4,6 +4,18 @@ class K8s { + /** + * Create a new Node kind. + * + * @param \RenokiCo\PhpK8s\KubernetesCluster|null $cluster + * @param array $attributes + * @return \RenokiCo\PhpK8s\Kinds\K8sNode + */ + public static function node($cluster = null, array $attributes = []) + { + return new Kinds\K8sNode($cluster, $attributes); + } + /** * Create a new Namespace kind. * diff --git a/src/Kinds/K8sNode.php b/src/Kinds/K8sNode.php new file mode 100644 index 00000000..7bf9174d --- /dev/null +++ b/src/Kinds/K8sNode.php @@ -0,0 +1,70 @@ +getStatus('nodeInfo', []); + } + + /** + * Get the images existing on the node. + * + * @return array + */ + public function getImages(): array + { + return $this->getStatus('images', []); + } + + /** + * Get the total capacity info for the node. + * + * @return array + */ + public function getCapacity(): array + { + return $this->getStatus('capacity', []); + } + + /** + * Get the allocatable info. + * + * @return array + */ + public function getAllocatableInfo(): array + { + return $this->getStatus('allocatable', []); + } +} diff --git a/tests/NodeTest.php b/tests/NodeTest.php new file mode 100644 index 00000000..96e78abe --- /dev/null +++ b/tests/NodeTest.php @@ -0,0 +1,66 @@ +runGetAllTests(); + $this->runGetTests(); + $this->runWatchAllTests(); + $this->runWatchTests(); + } + + public function runGetAllTests() + { + $nodes = $this->cluster->getAllNodes(); + + $this->assertInstanceOf(ResourcesList::class, $nodes); + + foreach ($nodes as $node) { + $this->assertInstanceOf(K8sNode::class, $node); + + $this->assertNotNull($node->getName()); + } + } + + public function runGetTests() + { + $node = $this->cluster->getNodeByName('minikube'); + + $this->assertInstanceOf(K8sNode::class, $node); + + $this->assertTrue($node->isSynced()); + + $this->assertEquals('minikube', $node->getName()); + $this->assertNotEquals([], $node->getInfo()); + $this->assertTrue(is_array($node->getImages())); + $this->assertNotEquals([], $node->getCapacity()); + $this->assertNotEquals([], $node->getAllocatableInfo()); + } + + public function runWatchAllTests() + { + $watch = $this->cluster->node()->watchAll(function ($type, $node) { + if ($node->getName() === 'minikube') { + return true; + } + }, ['timeoutSeconds' => 10]); + + $this->assertTrue($watch); + } + + public function runWatchTests() + { + $watch = $this->cluster->node()->watchByName('minikube', function ($type, $node) { + return $node->getName() === 'minikube'; + }, ['timeoutSeconds' => 10]); + + $this->assertTrue($watch); + } +} From 61ed238098859853a5e262c45d613e6c1114d9c1 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Thu, 24 Dec 2020 17:56:22 +0200 Subject: [PATCH 5/7] csfixing --- tests/NodeTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/NodeTest.php b/tests/NodeTest.php index 96e78abe..f71d19f4 100644 --- a/tests/NodeTest.php +++ b/tests/NodeTest.php @@ -2,7 +2,6 @@ namespace RenokiCo\PhpK8s\Test; -use RenokiCo\PhpK8s\Exceptions\KubernetesAPIException; use RenokiCo\PhpK8s\Kinds\K8sNode; use RenokiCo\PhpK8s\ResourcesList; From 2c161a9874c43cc519d42021e874379d4744702a Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Thu, 24 Dec 2020 18:06:35 +0200 Subject: [PATCH 6/7] fixed test --- tests/NodeTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/NodeTest.php b/tests/NodeTest.php index f71d19f4..6d050775 100644 --- a/tests/NodeTest.php +++ b/tests/NodeTest.php @@ -30,13 +30,13 @@ public function runGetAllTests() public function runGetTests() { - $node = $this->cluster->getNodeByName('minikube'); + $node = $this->cluster->getNodeByName($this->cluster->getAllNodes()->first()->getName()); $this->assertInstanceOf(K8sNode::class, $node); $this->assertTrue($node->isSynced()); - $this->assertEquals('minikube', $node->getName()); + //$this->assertEquals('minikube', $node->getName()); $this->assertNotEquals([], $node->getInfo()); $this->assertTrue(is_array($node->getImages())); $this->assertNotEquals([], $node->getCapacity()); From 6129964c8a0b6311b44cfdf68cb584a686c8144e Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Thu, 24 Dec 2020 19:23:23 +0200 Subject: [PATCH 7/7] fixed node test for watch --- tests/NodeTest.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/NodeTest.php b/tests/NodeTest.php index 6d050775..44665dd8 100644 --- a/tests/NodeTest.php +++ b/tests/NodeTest.php @@ -30,7 +30,9 @@ public function runGetAllTests() public function runGetTests() { - $node = $this->cluster->getNodeByName($this->cluster->getAllNodes()->first()->getName()); + $nodeName = $this->cluster->getAllNodes()->first()->getName(); + + $node = $this->cluster->getNodeByName($nodeName); $this->assertInstanceOf(K8sNode::class, $node); @@ -45,8 +47,10 @@ public function runGetTests() public function runWatchAllTests() { - $watch = $this->cluster->node()->watchAll(function ($type, $node) { - if ($node->getName() === 'minikube') { + $nodeName = $this->cluster->getAllNodes()->first()->getName(); + + $watch = $this->cluster->node()->watchAll(function ($type, $node) use ($nodeName) { + if ($node->getName() === $nodeName) { return true; } }, ['timeoutSeconds' => 10]); @@ -56,8 +60,10 @@ public function runWatchAllTests() public function runWatchTests() { - $watch = $this->cluster->node()->watchByName('minikube', function ($type, $node) { - return $node->getName() === 'minikube'; + $nodeName = $this->cluster->getAllNodes()->first()->getName(); + + $watch = $this->cluster->node()->watchByName($nodeName, function ($type, $node) use ($nodeName) { + return $node->getName() === $nodeName; }, ['timeoutSeconds' => 10]); $this->assertTrue($watch);