From 50852371180e9852e4040d0212d72b3e2eea1871 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 16:15:55 +0200 Subject: [PATCH 01/22] pods status --- src/Instances/Container.php | 10 +++ src/Kinds/K8sPod.php | 169 ++++++++++++++++++++++++++++++++++++ tests/ContainerTest.php | 1 + tests/PodTest.php | 20 ++++- 4 files changed, 197 insertions(+), 3 deletions(-) diff --git a/src/Instances/Container.php b/src/Instances/Container.php index 42f71247..eb12cb63 100644 --- a/src/Instances/Container.php +++ b/src/Instances/Container.php @@ -53,6 +53,16 @@ public function addPort(int $containerPort, string $protocol = 'TCP', string $na return $this->setAttribute('ports', $ports); } + /** + * Check if the container is ready. + * + * @return bool + */ + public function isReady(): bool + { + return $this->getAttribute('ready', false); + } + /** * Get the instance as an array. * diff --git a/src/Kinds/K8sPod.php b/src/Kinds/K8sPod.php index 8e1c088d..125a6fa8 100644 --- a/src/Kinds/K8sPod.php +++ b/src/Kinds/K8sPod.php @@ -6,6 +6,7 @@ use RenokiCo\PhpK8s\Contracts\Loggable; use RenokiCo\PhpK8s\Contracts\Watchable; use RenokiCo\PhpK8s\Instances\Container; +use RenokiCo\PhpK8s\K8s; use RenokiCo\PhpK8s\Traits\HasAnnotations; use RenokiCo\PhpK8s\Traits\HasLabels; use RenokiCo\PhpK8s\Traits\HasSpec; @@ -198,4 +199,172 @@ public function resourceLogPath(): string { return "/api/{$this->getApiVersion()}/namespaces/{$this->getNamespace()}/pods/{$this->getIdentifier()}/log"; } + + /** + * Get the status phase for the pod. + * + * @return string|null + */ + public function getPhase() + { + return $this->getAttribute('status.phase', null); + } + + /** + * Get status conditions for the pod. + * + * @return array + */ + public function getConditions(): array + { + return $this->getAttribute('status.conditions', []); + } + + /** + * Get the assigned pod IPs. + * + * @return array + */ + public function getPodIps(): array + { + return $this->getAttribute('status.podIPs', []); + } + + /** + * Get the pod host IP. + * + * @return string\null + */ + public function getHostIp() + { + return $this->getAttribute('status.hostIP', null); + } + + /** + * Get the statuses for each container. + * + * @param bool $asInstance + * @return array + */ + public function getContainerStatuses(bool $asInstance = true): array + { + $containers = $this->getAttribute('status.containerStatuses', []); + + if ($asInstance) { + foreach ($containers as &$container) { + $container = K8s::container($container); + } + } + + return $containers; + } + + /** + * Get the statuses for each init container. + * + * @param bool $asInstance + * @return array + */ + public function getInitContainerStatuses(bool $asInstance = true): array + { + $containers = $this->getAttribute('status.initContainerStatuses', []); + + if ($asInstance) { + foreach ($containers as &$container) { + $container = K8s::container($container); + } + } + + return $containers; + } + + /** + * Get the container status for a specific container. + * + * @param string $containerName + * @param bool $asInstance + * @return array|null + */ + public function getContainer(string $containerName, bool $asInstance = true) + { + return collect($this->getContainerStatuses($asInstance))->filter(function ($container) use ($containerName) { + $name = $container instanceof Container + ? $container->getName() + : $container['name']; + + return $name === $containerName; + })->first(); + } + + /** + * Get the container status for a specific init container. + * + * @param string $containerName + * @param bool $asInstance + * @return \RenokiCo\PhpK8s\Instances\Container|array|null + */ + public function getInitContainer(string $containerName, bool $asInstance = true) + { + return collect($this->getInitContainerStatuses($asInstance))->filter(function ($container) use ($containerName) { + $name = $container instanceof Container + ? $container->getName() + : $container['name']; + + return $name === $containerName; + })->first(); + } + + /** + * Check if all containers are ready. + * + * @return bool + */ + public function containersAreReady(): bool + { + return collect($this->getContainerStatuses())->reject(function ($container) { + return $container->isReady(); + })->isEmpty(); + } + + /** + * Check if all init containers are ready. + * + * @return bool + */ + public function initContainersAreReady(): bool + { + return collect($this->getIniContainerStatuses())->reject(function ($container) { + return $container->isReady(); + })->isEmpty(); + } + + /** + * Get the QOS class for the resource. + * + * @return string + */ + public function getQos(): string + { + return $this->getAttribute('status.qosClass', 'BestEffort'); + } + + /** + * Check if the pod is running. + * + * @return bool + */ + public function isRunning(): bool + { + return $this->getPhase() === 'Running'; + } + + /** + * Check if the pod completed successfully. + * + * @return bool + */ + public function isSuccessful(): bool + { + return $this->getPhase() === 'Succeeded'; + } } diff --git a/tests/ContainerTest.php b/tests/ContainerTest.php index 9ff1f53b..c1e56ddc 100644 --- a/tests/ContainerTest.php +++ b/tests/ContainerTest.php @@ -26,6 +26,7 @@ public function test_container_build() $container->removeEnv(); + $this->assertFalse($container->isReady()); $this->assertEquals('nginx:1.4', $container->getImage()); $this->assertEquals([], $container->getEnv([])); $this->assertEquals(['--test'], $container->getArgs()); diff --git a/tests/PodTest.php b/tests/PodTest.php index a52036d5..a7c9f3f8 100644 --- a/tests/PodTest.php +++ b/tests/PodTest.php @@ -144,8 +144,19 @@ public function runCreationTests() $this->assertEquals(['tier' => 'backend'], $pod->getLabels()); $this->assertEquals(['mysql/annotation' => 'yes'], $pod->getAnnotations()); - // Wait for the pod to create entirely. - sleep(60); + while (! $pod->isRunning()) { + dump("Waiting for pod {$pod->getName()} to be up and running..."); + sleep(1); + $pod->refresh(); + } + + $pod->refresh(); + + $this->assertEquals('busybox:latest', $pod->getInitContainer('busybox')->getImage()); + $this->assertEquals('mysql:5.7', $pod->getContainer('mysql')->getImage()); + + $this->assertTrue($pod->containersAreReady()); + $this->assertTrue($pod->initContainersAreReady()); } public function runGetAllTests() @@ -200,7 +211,10 @@ public function runDeletionTests() $this->assertTrue($pod->delete()); - sleep(60); + while ($pod->exists()) { + dump("Awaiting for pod {$pod->getName()} to be deleted..."); + sleep(1); + } $this->expectException(KubernetesAPIException::class); From c3eee0847ebae71ff5e850043be10c3b9f2a6dd5 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 16:16:08 +0200 Subject: [PATCH 02/22] using refreshVersions and refresh --- src/Kinds/K8sResource.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Kinds/K8sResource.php b/src/Kinds/K8sResource.php index fd69ee85..be1fcdf0 100644 --- a/src/Kinds/K8sResource.php +++ b/src/Kinds/K8sResource.php @@ -455,7 +455,7 @@ public function update(array $query = ['pretty' => 1]): bool return true; } - $this->refresh(); + $this->refreshVersions(); $instance = $this ->cluster @@ -493,7 +493,7 @@ public function delete(array $query = ['pretty' => 1], $gracePeriod = null, stri 'gracePeriodSeconds' => $gracePeriod, ]); - $this->refresh(); + $this->refreshVersions(); $this ->cluster @@ -517,7 +517,7 @@ public function delete(array $query = ['pretty' => 1], $gracePeriod = null, stri * @param array $query * @return $this */ - public function refresh(array $query = ['pretty' => 1]) + public function refreshVersions(array $query = ['pretty' => 1]) { $instance = $this->get($query); @@ -528,6 +528,17 @@ public function refresh(array $query = ['pretty' => 1]) return $this; } + /** + * Make a call to the cluster to get a fresh instance. + * + * @param array $query + * @return $this + */ + public function refresh(array $query = ['pretty' => 1]) + { + return $this->syncWith($this->get($query)->toArray()); + } + /** * Watch the resources list until the closure returns true or false. * From d43e15cd521e00416eb4592a951be34129c80ebc Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 16:16:16 +0200 Subject: [PATCH 03/22] Deployment status --- src/Kinds/K8sDeployment.php | 64 +++++++++++++++++++++++++++++++++++++ tests/DeploymentTest.php | 24 +++++++++++--- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/Kinds/K8sDeployment.php b/src/Kinds/K8sDeployment.php index c0621f80..d73f5346 100644 --- a/src/Kinds/K8sDeployment.php +++ b/src/Kinds/K8sDeployment.php @@ -109,4 +109,68 @@ public function podsSelector(): array 'deployment-name' => $this->getName(), ]; } + + /** + * Get the deployment conditions. + * + * @return array + */ + public function getConditions(): array + { + return $this->getAttribute('status.conditions', []); + } + + /** + * Get the available replicas. + * + * @return int + */ + public function getAvailableReplicas(): int + { + return $this->getAttribute('status.replicas', 0); + } + + /** + * Get the ready replicas. + * + * @return int + */ + public function getReadyReplicas(): int + { + return $this->getAttribute('status.readyReplicas', 0); + } + + /** + * Get the total desired replicas. + * + * @return int + */ + public function getDesiredReplicas(): int + { + return $this->getAttribute('status.replicas', 0); + } + + /** + * Get the total unavailable replicas. + * + * @return int + */ + public function getUnavailableReplicas(): int + { + return $this->getAttribute('status.unavailableReplicas', 0); + } + + /** + * Check if all scheduled pods are running. + * + * @return bool + */ + public function allPodsAreRunning(): bool + { + $pods = $this->getPods(); + + return $pods->count() > 0 && $pods->reject(function ($pod) { + return $pod->isReady(); + })->isEmpty(); + } } diff --git a/tests/DeploymentTest.php b/tests/DeploymentTest.php index d0e871bc..97aab18c 100644 --- a/tests/DeploymentTest.php +++ b/tests/DeploymentTest.php @@ -123,7 +123,10 @@ public function runCreationTests() $this->assertInstanceOf(K8sPod::class, $dep->getTemplate()); - sleep(10); + while (! $dep->allPodsAreRunning()) { + dump("Waiting for pods of {$dep->getName()} to be up and running..."); + sleep(1); + } $pods = $dep->getPods(); @@ -133,8 +136,18 @@ public function runCreationTests() $this->assertInstanceOf(K8sPod::class, $pod); } - // Wait for the pod to create entirely. - sleep(60); + $dep->refresh(); + + while ($dep->getReadyReplicas() === 0) { + dump("Waiting for pods of {$dep->getName()} to have ready replicas..."); + sleep(1); + $dep->refresh(); + } + + $this->assertEquals(1, $dep->getAvailableReplicas()); + $this->assertEquals(1, $dep->getReadyReplicas()); + $this->assertEquals(1, $dep->getDesiredReplicas()); + $this->assertEquals(0, $dep->getUnavailableReplicas()); } public function runGetAllTests() @@ -194,7 +207,10 @@ public function runDeletionTests() $this->assertTrue($dep->delete()); - sleep(60); + while ($dep->exists()) { + dump("Awaiting for deployment {$dep->getName()} to be deleted..."); + sleep(1); + } $this->expectException(KubernetesAPIException::class); From 9545b92c983357a25372a0b15cc32702b24802fa Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 17:03:44 +0200 Subject: [PATCH 04/22] Fixed namings to reflect counts --- src/Kinds/K8sDeployment.php | 8 ++++---- tests/DeploymentTest.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Kinds/K8sDeployment.php b/src/Kinds/K8sDeployment.php index d73f5346..d0ea7f15 100644 --- a/src/Kinds/K8sDeployment.php +++ b/src/Kinds/K8sDeployment.php @@ -125,7 +125,7 @@ public function getConditions(): array * * @return int */ - public function getAvailableReplicas(): int + public function getAvailableReplicasCount(): int { return $this->getAttribute('status.replicas', 0); } @@ -135,7 +135,7 @@ public function getAvailableReplicas(): int * * @return int */ - public function getReadyReplicas(): int + public function getReadyReplicasCount(): int { return $this->getAttribute('status.readyReplicas', 0); } @@ -145,7 +145,7 @@ public function getReadyReplicas(): int * * @return int */ - public function getDesiredReplicas(): int + public function getDesiredReplicasCount(): int { return $this->getAttribute('status.replicas', 0); } @@ -155,7 +155,7 @@ public function getDesiredReplicas(): int * * @return int */ - public function getUnavailableReplicas(): int + public function getUnavailableReplicasCount(): int { return $this->getAttribute('status.unavailableReplicas', 0); } diff --git a/tests/DeploymentTest.php b/tests/DeploymentTest.php index 97aab18c..1df002e4 100644 --- a/tests/DeploymentTest.php +++ b/tests/DeploymentTest.php @@ -144,10 +144,10 @@ public function runCreationTests() $dep->refresh(); } - $this->assertEquals(1, $dep->getAvailableReplicas()); - $this->assertEquals(1, $dep->getReadyReplicas()); - $this->assertEquals(1, $dep->getDesiredReplicas()); - $this->assertEquals(0, $dep->getUnavailableReplicas()); + $this->assertEquals(1, $dep->getAvailableReplicasCount()); + $this->assertEquals(1, $dep->getReadyReplicasCount()); + $this->assertEquals(1, $dep->getDesiredReplicasCount()); + $this->assertEquals(0, $dep->getUnavailableReplicasCount()); } public function runGetAllTests() From ec1816ae7fe70afc990a54afbf7570ccc4056323 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 17:15:59 +0200 Subject: [PATCH 05/22] jobs status --- src/Kinds/K8sJob.php | 90 ++++++++++++++++++++++++++++++++++++++++++++ tests/JobTest.php | 28 ++++++++++++-- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/Kinds/K8sJob.php b/src/Kinds/K8sJob.php index 9328e770..987c4dfa 100644 --- a/src/Kinds/K8sJob.php +++ b/src/Kinds/K8sJob.php @@ -2,6 +2,7 @@ namespace RenokiCo\PhpK8s\Kinds; +use Carbon\Carbon; use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; use RenokiCo\PhpK8s\Contracts\Podable; use RenokiCo\PhpK8s\Contracts\Watchable; @@ -99,4 +100,93 @@ public function podsSelector(): array 'job-name' => $this->getName(), ]; } + + /** + * Get the job conditions. + * + * @return array + */ + public function getConditions(): array + { + return $this->getAttribute('status.conditions', []); + } + + /** + * Get the amount of active pods. + * + * @return int + */ + public function getActivePodsCount(): int + { + return $this->getAttribute('status.active', 0); + } + + /** + * Get the amount of failed pods. + * + * @return int + */ + public function getFailedPodsCount(): int + { + return $this->getAttribute('status.failed', 0); + } + + /** + * Get the amount of succeded pods. + * + * @return int + */ + public function getSuccededPodsCount(): int + { + return $this->getAttribute('status.succeeded', 0); + } + + /** + * Get the start time. + * + * @return \DateTime|null + */ + public function getStartTime() + { + $time = $this->getAttribute('status.startTime', null); + + return $time ? Carbon::parse($time) : null; + } + + /** + * Get the completion time. + * + * @return \DateTime|null + */ + public function getCompletionTime() + { + $time = $this->getAttribute('status.completionTime', null); + + return $time ? Carbon::parse($time) : null; + } + + /** + * Get the total run time, in seconds. + * + * @return int + */ + public function getDurationInSeconds(): int + { + $startTime = $this->getStartTime(); + $completionTime = $this->getCompletionTime(); + + return $startTime && $completionTime + ? $startTime->diffInSeconds($completionTime) + : 0; + } + + /** + * Check if the job has completed. + * + * @return bool + */ + public function hasCompleted(): bool + { + return $this->getActivePodsCount() === 0; + } } diff --git a/tests/JobTest.php b/tests/JobTest.php index 0ca1c924..050ac44d 100644 --- a/tests/JobTest.php +++ b/tests/JobTest.php @@ -113,7 +113,13 @@ public function runCreationTests() $this->assertInstanceOf(K8sPod::class, $job->getTemplate()); - sleep(10); + $job->refresh(); + + while (! $job->hasCompleted()) { + dump("Waiting for pods of {$job->getName()} to finish executing..."); + sleep(1); + $job->refresh(); + } $pods = $job->getPods(); @@ -123,8 +129,18 @@ public function runCreationTests() $this->assertInstanceOf(K8sPod::class, $pod); } - // Wait for the pod to create entirely. - sleep(20); + $job->refresh(); + + while (! $completionTime = $job->getCompletionTime()) { + dump("Waiting for the competion time report of {$job->getName()}..."); + sleep(1); + $job->refresh(); + } + + $this->assertTrue($job->getDurationInSeconds() > 0); + $this->assertEquals(0, $job->getActivePodsCount()); + $this->assertEquals(0, $job->getFailedPodsCount()); + $this->assertEquals(1, $job->getSuccededPodsCount()); } public function runGetAllTests() @@ -182,7 +198,11 @@ public function runDeletionTests() $this->assertTrue($job->delete()); - sleep(20); + while ($job->exists()) { + dump("Awaiting for job {$job->getName()} to be deleted..."); + sleep(1); + } + $this->expectException(KubernetesAPIException::class); From edabe5c0701629ae9c46923e6976d64a3cf07d54 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 17:28:44 +0200 Subject: [PATCH 06/22] namespace status --- src/Kinds/K8sNamespace.php | 30 ++++++++++++++++++++++++++++++ tests/NamespaceTest.php | 9 ++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Kinds/K8sNamespace.php b/src/Kinds/K8sNamespace.php index f70ac0ad..9c7335df 100644 --- a/src/Kinds/K8sNamespace.php +++ b/src/Kinds/K8sNamespace.php @@ -53,4 +53,34 @@ public function resourceWatchPath(): string { return "/api/{$this->getApiVersion()}/watch/namespaces/{$this->getIdentifier()}"; } + + /** + * Get the status phase for the namespace. + * + * @return string|null + */ + public function getPhase() + { + return $this->getAttribute('status.phase', null); + } + + /** + * Check if the namespace is active. + * + * @return bool + */ + public function isActive(): bool + { + return $this->getPhase() === 'Active'; + } + + /** + * Check if the namespace is pending termination. + * + * @return bool + */ + public function isTerminating(): bool + { + return $this->getPhase() === 'Terminating'; + } } diff --git a/tests/NamespaceTest.php b/tests/NamespaceTest.php index 14cbdc5c..8df46973 100644 --- a/tests/NamespaceTest.php +++ b/tests/NamespaceTest.php @@ -76,6 +76,10 @@ public function runCreationTests() $this->assertInstanceOf(K8sNamespace::class, $ns); $this->assertEquals('production', $ns->getName()); + + $ns->refresh(); + + $this->assertTrue($ns->isActive()); } public function runUpdateTests() @@ -95,7 +99,10 @@ public function runDeletionTests() $this->assertTrue($ns->delete()); - sleep(10); + while ($ns->exists()) { + dump("Awaiting for namespace {$ns->getName()} to be deleted..."); + sleep(1); + } $this->expectException(KubernetesAPIException::class); From 283d6441a236d18599b5493135f37170147cb71d Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 17:34:36 +0200 Subject: [PATCH 07/22] Status for PV --- src/Kinds/K8sPersistentVolume.php | 30 ++++++++++++++++++++++++++++++ tests/PersistentVolumeTest.php | 14 +++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Kinds/K8sPersistentVolume.php b/src/Kinds/K8sPersistentVolume.php index fb5c46bd..0e59d591 100644 --- a/src/Kinds/K8sPersistentVolume.php +++ b/src/Kinds/K8sPersistentVolume.php @@ -94,4 +94,34 @@ public function resourceWatchPath(): string { return "/api/{$this->getApiVersion()}/watch/persistentvolumes/{$this->getIdentifier()}"; } + + /** + * Get the status phase for the persistent volume. + * + * @return string|null + */ + public function getPhase() + { + return $this->getAttribute('status.phase', null); + } + + /** + * Check if the PV is available to be used. + * + * @return bool + */ + public function isAvailable(): bool + { + return $this->getPhase() === 'Available'; + } + + /** + * Check if the PV is bound. + * + * @return bool + */ + public function isBound(): bool + { + return $this->getPhase() === 'Bound'; + } } diff --git a/tests/PersistentVolumeTest.php b/tests/PersistentVolumeTest.php index 9e473583..545b715b 100644 --- a/tests/PersistentVolumeTest.php +++ b/tests/PersistentVolumeTest.php @@ -90,6 +90,15 @@ public function runCreationTests() $this->assertEquals(['ReadWriteOnce'], $pv->getAccessModes()); $this->assertEquals(['debug'], $pv->getMountOptions()); $this->assertEquals('sc1', $pv->getStorageClass()); + + while (! $pv->isAvailable()) { + dump("Waiting for PV {$pv->getName()} to be available..."); + sleep(1); + $pv->refresh(); + } + + $this->assertTrue($pv->isAvailable()); + $this->assertFalse($pv->isBound()); } public function runGetAllTests() @@ -149,7 +158,10 @@ public function runDeletionTests() $this->assertTrue($pv->delete()); - sleep(3); + while ($pv->exists()) { + dump("Awaiting for PV {$pv->getName()} to be deleted..."); + sleep(1); + } $this->expectException(KubernetesAPIException::class); From e9d328b73432b9d656b43b8c299904c1584db3c0 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 18:43:52 +0200 Subject: [PATCH 08/22] PVC status --- src/Kinds/K8sPersistentVolumeClaim.php | 30 ++++++++++++++++++++ tests/PersistentVolumeClaimTest.php | 39 +++++++++++++++----------- tests/yaml/persistentvolumeclaim.yaml | 2 +- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/Kinds/K8sPersistentVolumeClaim.php b/src/Kinds/K8sPersistentVolumeClaim.php index 3d5c13ce..7e3a2175 100644 --- a/src/Kinds/K8sPersistentVolumeClaim.php +++ b/src/Kinds/K8sPersistentVolumeClaim.php @@ -81,4 +81,34 @@ public function resourceWatchPath(): string { return "/api/{$this->getApiVersion()}/watch/namespaces/{$this->getNamespace()}/persistentvolumeclaims/{$this->getIdentifier()}"; } + + /** + * Get the status phase for the persistent volume. + * + * @return string|null + */ + public function getPhase() + { + return $this->getAttribute('status.phase', null); + } + + /** + * Check if the PV is available to be used. + * + * @return bool + */ + public function isAvailable(): bool + { + return $this->getPhase() === 'Available'; + } + + /** + * Check if the PV is bound. + * + * @return bool + */ + public function isBound(): bool + { + return $this->getPhase() === 'Bound'; + } } diff --git a/tests/PersistentVolumeClaimTest.php b/tests/PersistentVolumeClaimTest.php index 79664ab3..d56f3cea 100644 --- a/tests/PersistentVolumeClaimTest.php +++ b/tests/PersistentVolumeClaimTest.php @@ -10,23 +10,19 @@ class PersistentVolumeClaimTest extends TestCase { public function test_persistent_volume_claim_build() { - $gp2 = $this->cluster->storageClass() - ->setName('gp2') - ->setProvisioner('csi.aws.amazon.com') - ->setParameters(['type' => 'gp2']) - ->setMountOptions(['debug']); + $standard = $this->cluster->getStorageClassByName('standard'); $pvc = $this->cluster->persistentVolumeClaim() ->setName('app-pvc') ->setCapacity(1, 'Gi') ->setAccessModes(['ReadWriteOnce']) - ->setStorageClass($gp2); + ->setStorageClass($standard); $this->assertEquals('v1', $pvc->getApiVersion()); $this->assertEquals('app-pvc', $pvc->getName()); $this->assertEquals('1Gi', $pvc->getCapacity()); $this->assertEquals(['ReadWriteOnce'], $pvc->getAccessModes()); - $this->assertEquals('gp2', $pvc->getStorageClass()); + $this->assertEquals('standard', $pvc->getStorageClass()); } public function test_persistent_volume_claim_from_yaml() @@ -37,7 +33,7 @@ public function test_persistent_volume_claim_from_yaml() $this->assertEquals('app-pvc', $pvc->getName()); $this->assertEquals('1Gi', $pvc->getCapacity()); $this->assertEquals(['ReadWriteOnce'], $pvc->getAccessModes()); - $this->assertEquals('gp2', $pvc->getStorageClass()); + $this->assertEquals('standard', $pvc->getStorageClass()); } public function test_persistent_volume_claim_api_interaction() @@ -53,16 +49,13 @@ public function test_persistent_volume_claim_api_interaction() public function runCreationTests() { - $gp2 = $this->cluster->storageClass() - ->setName('gp2') - ->setProvisioner('csi.aws.amazon.com') - ->setParameters(['type' => 'gp2']); + $standard = $this->cluster->getStorageClassByName('standard'); $pvc = $this->cluster->persistentVolumeClaim() ->setName('app-pvc') ->setCapacity(1, 'Gi') ->setAccessModes(['ReadWriteOnce']) - ->setStorageClass($gp2); + ->setStorageClass($standard); $this->assertFalse($pvc->isSynced()); $this->assertFalse($pvc->exists()); @@ -78,7 +71,16 @@ public function runCreationTests() $this->assertEquals('app-pvc', $pvc->getName()); $this->assertEquals('1Gi', $pvc->getCapacity()); $this->assertEquals(['ReadWriteOnce'], $pvc->getAccessModes()); - $this->assertEquals('gp2', $pvc->getStorageClass()); + $this->assertEquals('standard', $pvc->getStorageClass()); + + while (! $pvc->isBound()) { + dump("Waiting for PVC {$pvc->getName()} to be bound..."); + sleep(1); + $pvc->refresh(); + } + + $this->assertFalse($pvc->isAvailable()); + $this->assertTrue($pvc->isBound()); } public function runGetAllTests() @@ -106,7 +108,7 @@ public function runGetTests() $this->assertEquals('app-pvc', $pvc->getName()); $this->assertEquals('1Gi', $pvc->getCapacity()); $this->assertEquals(['ReadWriteOnce'], $pvc->getAccessModes()); - $this->assertEquals('gp2', $pvc->getStorageClass()); + $this->assertEquals('standard', $pvc->getStorageClass()); } public function runUpdateTests() @@ -123,7 +125,7 @@ public function runUpdateTests() $this->assertEquals('app-pvc', $pvc->getName()); $this->assertEquals('1Gi', $pvc->getCapacity()); $this->assertEquals(['ReadWriteOnce'], $pvc->getAccessModes()); - $this->assertEquals('gp2', $pvc->getStorageClass()); + $this->assertEquals('standard', $pvc->getStorageClass()); } public function runDeletionTests() @@ -132,7 +134,10 @@ public function runDeletionTests() $this->assertTrue($pvc->delete()); - sleep(3); + while ($pvc->exists()) { + dump("Awaiting for PVC {$pvc->getName()} to be deleted..."); + sleep(1); + } $this->expectException(KubernetesAPIException::class); diff --git a/tests/yaml/persistentvolumeclaim.yaml b/tests/yaml/persistentvolumeclaim.yaml index c86c7e5b..003ac612 100644 --- a/tests/yaml/persistentvolumeclaim.yaml +++ b/tests/yaml/persistentvolumeclaim.yaml @@ -8,4 +8,4 @@ spec: storage: 1Gi accessModes: - ReadWriteOnce - storageClassName: gp2 + storageClassName: standard From 5365aea1211c1a55e1205c39e6df2b7ce9158576 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 18:47:03 +0200 Subject: [PATCH 09/22] Fixed typo --- src/Kinds/K8sDeployment.php | 2 +- tests/DeploymentTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kinds/K8sDeployment.php b/src/Kinds/K8sDeployment.php index d0ea7f15..1cedd8b0 100644 --- a/src/Kinds/K8sDeployment.php +++ b/src/Kinds/K8sDeployment.php @@ -127,7 +127,7 @@ public function getConditions(): array */ public function getAvailableReplicasCount(): int { - return $this->getAttribute('status.replicas', 0); + return $this->getAttribute('status.availableReplicas', 0); } /** diff --git a/tests/DeploymentTest.php b/tests/DeploymentTest.php index 1df002e4..318b3aaf 100644 --- a/tests/DeploymentTest.php +++ b/tests/DeploymentTest.php @@ -138,7 +138,7 @@ public function runCreationTests() $dep->refresh(); - while ($dep->getReadyReplicas() === 0) { + while ($dep->getReadyReplicasCount() === 0) { dump("Waiting for pods of {$dep->getName()} to have ready replicas..."); sleep(1); $dep->refresh(); From 840ba7001bd2a0b96311698b94cb28ec4ca9e917 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 18:47:11 +0200 Subject: [PATCH 10/22] sts status --- src/Kinds/K8sStatefulSet.php | 54 ++++++++++++++++++++++++++++++++++++ tests/StatefulSetTest.php | 35 ++++++++++++++++++----- tests/yaml/statefulset.yaml | 2 +- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/Kinds/K8sStatefulSet.php b/src/Kinds/K8sStatefulSet.php index dc922cf1..1382cc10 100644 --- a/src/Kinds/K8sStatefulSet.php +++ b/src/Kinds/K8sStatefulSet.php @@ -170,4 +170,58 @@ public function podsSelector(): array 'statefulset-name' => $this->getName(), ]; } + + /** + * Get the deployment conditions. + * + * @return array + */ + public function getConditions(): array + { + return $this->getAttribute('status.conditions', []); + } + + /** + * Get the current replicas. + * + * @return int + */ + public function getCurrentReplicasCount(): int + { + return $this->getAttribute('status.currentReplicas', 0); + } + + /** + * Get the ready replicas. + * + * @return int + */ + public function getReadyReplicasCount(): int + { + return $this->getAttribute('status.readyReplicas', 0); + } + + /** + * Get the total desired replicas. + * + * @return int + */ + public function getDesiredReplicasCount(): int + { + return $this->getAttribute('status.replicas', 0); + } + + /** + * Check if all scheduled pods are running. + * + * @return bool + */ + public function allPodsAreRunning(): bool + { + $pods = $this->getPods(); + + return $pods->count() > 0 && $pods->reject(function ($pod) { + return $pod->isReady(); + })->isEmpty(); + } } diff --git a/tests/StatefulSetTest.php b/tests/StatefulSetTest.php index 571158c1..949a49ff 100644 --- a/tests/StatefulSetTest.php +++ b/tests/StatefulSetTest.php @@ -30,11 +30,13 @@ public function test_stateful_set_build() ['protocol' => 'TCP', 'port' => 3306, 'targetPort' => 3306], ]); + $standard = $this->cluster->getStorageClassByName('standard'); + $pvc = $this->cluster->persistentVolumeClaim() ->setName('mysql-pvc') ->setCapacity(1, 'Gi') ->setAccessModes(['ReadWriteOnce']) - ->setStorageClass('gp2'); + ->setStorageClass($standard); $sts = $this->cluster->statefulSet() ->setName('mysql') @@ -77,11 +79,13 @@ public function test_stateful_set_from_yaml() ['protocol' => 'TCP', 'port' => 3306, 'targetPort' => 3306], ]); + $standard = $this->cluster->getStorageClassByName('standard'); + $pvc = $this->cluster->persistentVolumeClaim() ->setName('mysql-pvc') ->setCapacity(1, 'Gi') ->setAccessModes(['ReadWriteOnce']) - ->setStorageClass('gp2'); + ->setStorageClass($standard); $sts = $this->cluster->fromYamlFile(__DIR__.'/yaml/statefulset.yaml'); @@ -136,11 +140,13 @@ public function runCreationTests() ]) ->syncWithCluster(); + $standard = $this->cluster->getStorageClassByName('standard'); + $pvc = $this->cluster->persistentVolumeClaim() ->setName('mysql-pvc') ->setCapacity(1, 'Gi') ->setAccessModes(['ReadWriteOnce']) - ->setStorageClass('gp2'); + ->setStorageClass($standard); $sts = $this->cluster->statefulSet() ->setName('mysql') @@ -174,7 +180,10 @@ public function runCreationTests() $this->assertInstanceOf(K8sPod::class, $sts->getTemplate()); $this->assertInstanceOf(K8sPersistentVolumeClaim::class, $sts->getVolumeClaims()[0]); - sleep(10); + while (! $sts->allPodsAreRunning()) { + dump("Waiting for pods of {$sts->getName()} to be up and running..."); + sleep(1); + } $pods = $sts->getPods(); @@ -184,8 +193,17 @@ public function runCreationTests() $this->assertInstanceOf(K8sPod::class, $pod); } - // Wait for the pod to create entirely. - sleep(60); + $sts->refresh(); + + while ($sts->getReadyReplicasCount() === 0) { + dump("Waiting for pods of {$sts->getName()} to have ready replicas..."); + sleep(1); + $sts->refresh(); + } + + $this->assertEquals(1, $sts->getCurrentReplicasCount()); + $this->assertEquals(1, $sts->getReadyReplicasCount()); + $this->assertEquals(1, $sts->getDesiredReplicasCount()); } public function runGetAllTests() @@ -247,7 +265,10 @@ public function runDeletionTests() $this->assertTrue($sts->delete()); - sleep(60); + while ($sts->exists()) { + dump("Awaiting for statefulset {$sts->getName()} to be deleted..."); + sleep(1); + } $this->expectException(KubernetesAPIException::class); diff --git a/tests/yaml/statefulset.yaml b/tests/yaml/statefulset.yaml index 53fd2a67..8d59aadf 100644 --- a/tests/yaml/statefulset.yaml +++ b/tests/yaml/statefulset.yaml @@ -29,6 +29,6 @@ spec: storage: 1Gi accessModes: - ReadWriteOnce - storageClassName: gp2 + storageClassName: standard kind: PersistentVolumeClaim apiVersion: v1 From 1c16eabf4a22283b6044c7c1e21095fa4c87187b Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 19:09:08 +0200 Subject: [PATCH 11/22] Added docs --- docs/kinds/Deployment.md | 20 +++++++++ docs/kinds/Job.md | 33 +++++++++++++++ docs/kinds/Namespace.md | 20 +++++++++ docs/kinds/PersistentVolume.md | 20 +++++++++ docs/kinds/PersistentVolumeClaim.md | 20 +++++++++ docs/kinds/Pod.md | 64 +++++++++++++++++++++++++++++ docs/kinds/StatefulSet.md | 20 +++++++++ 7 files changed, 197 insertions(+) diff --git a/docs/kinds/Deployment.md b/docs/kinds/Deployment.md index 2bb9f9d2..7e3d2a9b 100644 --- a/docs/kinds/Deployment.md +++ b/docs/kinds/Deployment.md @@ -110,3 +110,23 @@ foreach ($dep->getPods() as $pod) { // $pod->logs() } ``` + +### Deployment Status + +The Status API is available to be accessed for fresh instances: + +```php +$dep->refresh(); + +$dep->getReadyReplicasCount(); +$dep->getDesiredReplicasCount(); +$dep->getUnavailableReplicasCount(); +``` + +You can check if all the pods within the Deployment are running: + +```php +if ($dep->allPodsAreRunning()) { + // +} +``` diff --git a/docs/kinds/Job.md b/docs/kinds/Job.md index 272cf16b..82ab2922 100644 --- a/docs/kinds/Job.md +++ b/docs/kinds/Job.md @@ -135,3 +135,36 @@ foreach ($job->getPods() as $pod) { // $pod->logs() } ``` + +### Job Status + +The Status API is available to be accessed for fresh instances: + +```php +$job->refresh(); + +$job->getActivePodsCount(); +$job->getFailedPodsCount(); +$job->getSuccededPodsCount(); +``` + +You can check if the job completed: + +```php +if ($job->hasCompleted()) { + // +} +``` + +You can retrieve the `null`/`\DateTime` instance for start and end times for the job: + +```php +$start = $job->getStartTime(); +$end = $job->getCompletionTime(); +``` + +You can also retrieve the amount of time the job ran for: + +```php +$seconds = $job->getDurationInSeconds(); +``` diff --git a/docs/kinds/Namespace.md b/docs/kinds/Namespace.md index 3084a5a6..31751f36 100644 --- a/docs/kinds/Namespace.md +++ b/docs/kinds/Namespace.md @@ -17,3 +17,23 @@ $ns = $cluster->namespace() ```php $ns = $cluster->getNamespaceByName('staging'); ``` + +### Namespace Status + +The Status API is available to be accessed for fresh instances: + +```php +$ns->refresh(); + +if ($ns->isActive()) { + // +} +``` + +You can also check if the namespace is terminating: + +```php +if ($ns->isTerminating()) { + // +} +``` diff --git a/docs/kinds/PersistentVolume.md b/docs/kinds/PersistentVolume.md index 12f2333d..8427ff61 100644 --- a/docs/kinds/PersistentVolume.md +++ b/docs/kinds/PersistentVolume.md @@ -85,3 +85,23 @@ Dot notation is supported: ```php $pv->getSpec('some.nested.path', []); ``` + +### Persistent Volume Status + +The Status API is available to be accessed for fresh instances: + +```php +$pv->refresh(); + +if ($pv->isAvailable()) { + // +} +``` + +You can also check if the PV is bound: + +```php +if ($pv->isBound()) { + // +} +``` diff --git a/docs/kinds/PersistentVolumeClaim.md b/docs/kinds/PersistentVolumeClaim.md index 3e19ce97..d11a3f7a 100644 --- a/docs/kinds/PersistentVolumeClaim.md +++ b/docs/kinds/PersistentVolumeClaim.md @@ -74,3 +74,23 @@ Dot notation is supported: ```php $pvc->getSpec('some.nested.path', []); ``` + +### Persistent Volume Claim Status + +The Status API is available to be accessed for fresh instances: + +```php +$pvc->refresh(); + +if ($pvc->isAvailable()) { + // +} +``` + +You can also check if the PVC is bound: + +```php +if ($pvc->isBound()) { + // +} +``` diff --git a/docs/kinds/Pod.md b/docs/kinds/Pod.md index 0b80e207..9f409b31 100644 --- a/docs/kinds/Pod.md +++ b/docs/kinds/Pod.md @@ -135,3 +135,67 @@ $pod->watchLogs(function ($line) { // with the given line. }); ``` + +### Pod Status + +The Status API is available to be accessed for fresh instances: + +```php +$pod->refresh(); + +$pod->getPodIps(); +$pod->getHostIp(); +$pod->getQos(); +``` + +You can also check if the pod is running + +```php +if ($pod->isRunning()) { + // +} +``` + +For [Job](Job.md) support, you may also check if the pod ran successfully: + +```php +foreach ($job->getPods() as $pod) { + if ($pod->isSuccessful()) { + // + } +} +``` + +You can check the container statuses: + +```php +foreach ($pod->getContainerStatuses() as $container) { + // $container->getName(); +} + +foreach ($pod->getInitContainerStatuses() as $container) { + // $container->getName(); +} +``` + +You may also get a container by its name: + +```php +$mysql = $pod->getContainer('mysql'); +$busybox = $pod->getInitContainer('busybox'); + +// $mysql->getName(); +// $busybox->getName(); +``` + +Check if the containers are ready: + +```php +if ($pod->containersAreReady()) { + // +} + +if ($pod->initContainersAreReady()) { + // +} +``` diff --git a/docs/kinds/StatefulSet.md b/docs/kinds/StatefulSet.md index 9723d993..57fd7061 100644 --- a/docs/kinds/StatefulSet.md +++ b/docs/kinds/StatefulSet.md @@ -126,3 +126,23 @@ foreach ($sts->getPods() as $pod) { // $pod->logs() } ``` + +### StatefulSet Status + +The Status API is available to be accessed for fresh instances: + +```php +$sts->refresh(); + +$sts->getCurrentReplicasCount(); +$sts->getReadyReplicasCount(); +$sts->getDesiredReplicasCount(); +``` + +You can check if all the pods within the StatefulSet are running: + +```php +if ($sts->allPodsAreRunning()) { + // +} +``` From 81024a44627f44d6c5743f673236bfb7bd5eeae4 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 21:20:12 +0200 Subject: [PATCH 12/22] Added 5 seconds delay between tests. --- tests/TestCase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/TestCase.php b/tests/TestCase.php index 7960afdd..21a6ab56 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -26,6 +26,9 @@ public function setUp(): void $this->cluster = new KubernetesCluster('http://127.0.0.1'); $this->cluster->withoutSslChecks(); + + // Wait 5 seconds between tests. + sleep(5); } /** From 1988b35add810eac0a5957148722839732952b2d Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 21:44:47 +0200 Subject: [PATCH 13/22] Added extra checks --- src/Kinds/K8sResource.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Kinds/K8sResource.php b/src/Kinds/K8sResource.php index be1fcdf0..fb01eded 100644 --- a/src/Kinds/K8sResource.php +++ b/src/Kinds/K8sResource.php @@ -455,10 +455,13 @@ public function update(array $query = ['pretty' => 1]): bool return true; } + if (! $this->exists()) { + return false; + } + $this->refreshVersions(); - $instance = $this - ->cluster + $instance = $this->cluster ->setResourceClass(get_class($this)) ->runOperation( KubernetesCluster::REPLACE_OP, @@ -486,6 +489,10 @@ public function delete(array $query = ['pretty' => 1], $gracePeriod = null, stri return true; } + if ($this->exists()) { + return false; + } + $this->setAttribute('preconditions', [ 'resourceVersion' => $this->getResourceVersion(), 'uid' => $this->getResourceUid(), @@ -495,8 +502,7 @@ public function delete(array $query = ['pretty' => 1], $gracePeriod = null, stri $this->refreshVersions(); - $this - ->cluster + $this->cluster ->setResourceClass(get_class($this)) ->runOperation( KubernetesCluster::DELETE_OP, From 57344d01ac31c1980ed3f58c43e82a47e95097e5 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 21:49:12 +0200 Subject: [PATCH 14/22] csfixing --- tests/ConfigMapTest.php | 2 +- tests/DeploymentTest.php | 2 +- tests/IngressTest.php | 2 +- tests/JobTest.php | 3 +-- tests/NamespaceTest.php | 2 +- tests/PersistentVolumeClaimTest.php | 2 +- tests/PersistentVolumeTest.php | 2 +- tests/PodTest.php | 2 +- tests/SecretTest.php | 2 +- tests/ServiceTest.php | 2 +- tests/StatefulSetTest.php | 2 +- tests/StorageClassTest.php | 2 +- 12 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/ConfigMapTest.php b/tests/ConfigMapTest.php index d8232be8..fcc25bd7 100644 --- a/tests/ConfigMapTest.php +++ b/tests/ConfigMapTest.php @@ -119,7 +119,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $cm = $this->cluster->getConfigmapByName('settings'); + $this->cluster->getConfigmapByName('settings'); } public function runWatchAllTests() diff --git a/tests/DeploymentTest.php b/tests/DeploymentTest.php index 318b3aaf..ec3fcf54 100644 --- a/tests/DeploymentTest.php +++ b/tests/DeploymentTest.php @@ -214,7 +214,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $pod = $this->cluster->getDeploymentByName('mysql'); + $this->cluster->getDeploymentByName('mysql'); } public function runWatchAllTests() diff --git a/tests/IngressTest.php b/tests/IngressTest.php index 5ff1a0da..74b1293b 100644 --- a/tests/IngressTest.php +++ b/tests/IngressTest.php @@ -163,7 +163,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $ingress = $this->cluster->getIngressByName('nginx'); + $this->cluster->getIngressByName('nginx'); } public function runWatchAllTests() diff --git a/tests/JobTest.php b/tests/JobTest.php index 050ac44d..b6389642 100644 --- a/tests/JobTest.php +++ b/tests/JobTest.php @@ -203,10 +203,9 @@ public function runDeletionTests() sleep(1); } - $this->expectException(KubernetesAPIException::class); - $pod = $this->cluster->getJobByName('pi'); + $this->cluster->getJobByName('pi'); } public function runWatchAllTests() diff --git a/tests/NamespaceTest.php b/tests/NamespaceTest.php index 8df46973..7fd3daea 100644 --- a/tests/NamespaceTest.php +++ b/tests/NamespaceTest.php @@ -106,7 +106,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $ns = $this->cluster->getNamespaceByName('production'); + $this->cluster->getNamespaceByName('production'); } public function runWatchAllTests() diff --git a/tests/PersistentVolumeClaimTest.php b/tests/PersistentVolumeClaimTest.php index d56f3cea..d2a65569 100644 --- a/tests/PersistentVolumeClaimTest.php +++ b/tests/PersistentVolumeClaimTest.php @@ -141,7 +141,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $pvc = $this->cluster->getPersistentVolumeClaimByName('app-pvc'); + $this->cluster->getPersistentVolumeClaimByName('app-pvc'); } public function runWatchAllTests() diff --git a/tests/PersistentVolumeTest.php b/tests/PersistentVolumeTest.php index 545b715b..0a965c34 100644 --- a/tests/PersistentVolumeTest.php +++ b/tests/PersistentVolumeTest.php @@ -165,7 +165,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $pv = $this->cluster->getPersistentVolumeByName('app'); + $this->cluster->getPersistentVolumeByName('app'); } public function runWatchAllTests() diff --git a/tests/PodTest.php b/tests/PodTest.php index a7c9f3f8..7372c21e 100644 --- a/tests/PodTest.php +++ b/tests/PodTest.php @@ -218,7 +218,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $pod = $this->cluster->getPodByName('mysql'); + $this->cluster->getPodByName('mysql'); } public function runWatchAllTests() diff --git a/tests/SecretTest.php b/tests/SecretTest.php index 03b1d8c3..96528221 100644 --- a/tests/SecretTest.php +++ b/tests/SecretTest.php @@ -122,7 +122,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $secret = $this->cluster->getSecretByName('passwords'); + $this->cluster->getSecretByName('passwords'); } public function runWatchAllTests() diff --git a/tests/ServiceTest.php b/tests/ServiceTest.php index b1556e6e..dff815fd 100644 --- a/tests/ServiceTest.php +++ b/tests/ServiceTest.php @@ -139,7 +139,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $service = $this->cluster->getSecretByName('nginx'); + $this->cluster->getSecretByName('nginx'); } public function runWatchAllTests() diff --git a/tests/StatefulSetTest.php b/tests/StatefulSetTest.php index 949a49ff..ea5c5967 100644 --- a/tests/StatefulSetTest.php +++ b/tests/StatefulSetTest.php @@ -272,7 +272,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $pod = $this->cluster->getStatefulSetByName('mysql'); + $this->cluster->getStatefulSetByName('mysql'); } public function runWatchAllTests() diff --git a/tests/StorageClassTest.php b/tests/StorageClassTest.php index 19a73cf2..69c80c61 100644 --- a/tests/StorageClassTest.php +++ b/tests/StorageClassTest.php @@ -125,7 +125,7 @@ public function runDeletionTests() $this->expectException(KubernetesAPIException::class); - $sc = $this->cluster->getStorageClassByName('io1'); + $this->cluster->getStorageClassByName('io1'); } public function runWatchAllTests() From d2780658f3112550b221a458200b7be84f19ee9e Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 22:31:20 +0200 Subject: [PATCH 15/22] Reverted extra checks --- src/Kinds/K8sResource.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Kinds/K8sResource.php b/src/Kinds/K8sResource.php index fb01eded..9234453f 100644 --- a/src/Kinds/K8sResource.php +++ b/src/Kinds/K8sResource.php @@ -455,10 +455,6 @@ public function update(array $query = ['pretty' => 1]): bool return true; } - if (! $this->exists()) { - return false; - } - $this->refreshVersions(); $instance = $this->cluster @@ -489,10 +485,6 @@ public function delete(array $query = ['pretty' => 1], $gracePeriod = null, stri return true; } - if ($this->exists()) { - return false; - } - $this->setAttribute('preconditions', [ 'resourceVersion' => $this->getResourceVersion(), 'uid' => $this->getResourceUid(), From 9d46f3c6d3857e173f3851a1cc587051db632234 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 22:32:29 +0200 Subject: [PATCH 16/22] Extra existing check --- tests/ConfigMapTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/ConfigMapTest.php b/tests/ConfigMapTest.php index fcc25bd7..32f153ac 100644 --- a/tests/ConfigMapTest.php +++ b/tests/ConfigMapTest.php @@ -117,6 +117,10 @@ public function runDeletionTests() $this->assertTrue($cm->delete()); + while ($cm->exists()) { + sleep(1); + } + $this->expectException(KubernetesAPIException::class); $this->cluster->getConfigmapByName('settings'); From fc8ed2124e81d36089c71a282b0ddb9f938f77cf Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Fri, 30 Oct 2020 22:32:36 +0200 Subject: [PATCH 17/22] Reverted sleep between tests --- tests/TestCase.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 21a6ab56..7960afdd 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -26,9 +26,6 @@ public function setUp(): void $this->cluster = new KubernetesCluster('http://127.0.0.1'); $this->cluster->withoutSslChecks(); - - // Wait 5 seconds between tests. - sleep(5); } /** From c0517e499fb89d7a58dfdc3de1e748f296be1a63 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 31 Oct 2020 11:34:11 +0200 Subject: [PATCH 18/22] Allow failure --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6616378a..7ced9c9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,7 @@ on: jobs: build: if: "!contains(github.event.head_commit.message, 'skip ci')" + continue-on-error: true runs-on: ubuntu-latest From 3abfccd467a03e89d6ec5e5f7ade41155d1e073d Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 31 Oct 2020 11:55:21 +0200 Subject: [PATCH 19/22] debugging --- tests/DeploymentTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/DeploymentTest.php b/tests/DeploymentTest.php index ec3fcf54..13dcdc0a 100644 --- a/tests/DeploymentTest.php +++ b/tests/DeploymentTest.php @@ -205,7 +205,11 @@ public function runDeletionTests() { $dep = $this->cluster->getDeploymentByName('mysql'); - $this->assertTrue($dep->delete()); + try { + $this->assertTrue($dep->delete()); + } catch (\Exception $e) { + dd($e->getPayload()); + } while ($dep->exists()) { dump("Awaiting for deployment {$dep->getName()} to be deleted..."); From 8a84d53e26f7a97f50cd6d19736e56465cc6f611 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 31 Oct 2020 12:34:36 +0200 Subject: [PATCH 20/22] Refresh before deleting --- src/Kinds/K8sResource.php | 2 +- tests/DeploymentTest.php | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Kinds/K8sResource.php b/src/Kinds/K8sResource.php index 9234453f..b6542b10 100644 --- a/src/Kinds/K8sResource.php +++ b/src/Kinds/K8sResource.php @@ -492,7 +492,7 @@ public function delete(array $query = ['pretty' => 1], $gracePeriod = null, stri 'gracePeriodSeconds' => $gracePeriod, ]); - $this->refreshVersions(); + $this->refresh(); $this->cluster ->setResourceClass(get_class($this)) diff --git a/tests/DeploymentTest.php b/tests/DeploymentTest.php index 13dcdc0a..ec3fcf54 100644 --- a/tests/DeploymentTest.php +++ b/tests/DeploymentTest.php @@ -205,11 +205,7 @@ public function runDeletionTests() { $dep = $this->cluster->getDeploymentByName('mysql'); - try { - $this->assertTrue($dep->delete()); - } catch (\Exception $e) { - dd($e->getPayload()); - } + $this->assertTrue($dep->delete()); while ($dep->exists()) { dump("Awaiting for deployment {$dep->getName()} to be deleted..."); From e1e16fb30d9b76ead679fa981ec1d61970b89142 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 31 Oct 2020 12:37:37 +0200 Subject: [PATCH 21/22] Added syncer for originals --- src/Kinds/K8sResource.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Kinds/K8sResource.php b/src/Kinds/K8sResource.php index b6542b10..5b3535f3 100644 --- a/src/Kinds/K8sResource.php +++ b/src/Kinds/K8sResource.php @@ -116,9 +116,23 @@ public function isSynced(): bool */ public function syncWith(array $attributes = []) { - $this->original = $attributes; $this->attributes = $attributes; + $this->syncOriginalWith($attributes); + + return $this; + } + + /** + * Hydrate the current original details with a payload. + * + * @param array $instance + * @return $this + */ + public function syncOriginalWith(array $attributes = []) + { + $this->original = $attributes; + $this->synced(); return $this; @@ -455,7 +469,7 @@ public function update(array $query = ['pretty' => 1]): bool return true; } - $this->refreshVersions(); + $this->refreshOriginal(); $instance = $this->cluster ->setResourceClass(get_class($this)) @@ -537,6 +551,17 @@ public function refresh(array $query = ['pretty' => 1]) return $this->syncWith($this->get($query)->toArray()); } + /** + * Make a call to teh cluster to get fresh original values. + * + * @param array $query + * @return $this + */ + public function refreshOriginal(array $query = ['pretty' => 1]) + { + return $this->syncOriginalWith($this->get($query)->toArray()); + } + /** * Watch the resources list until the closure returns true or false. * From ea02a8b3c4c085e38216e2899d43b9487de0b606 Mon Sep 17 00:00:00 2001 From: Alex Renoki Date: Sat, 31 Oct 2020 12:44:03 +0200 Subject: [PATCH 22/22] Reverted continue on errors --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ced9c9b..6616378a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,6 @@ on: jobs: build: if: "!contains(github.event.head_commit.message, 'skip ci')" - continue-on-error: true runs-on: ubuntu-latest