Skip to content

Commit

Permalink
Merge pull request #169 from tiagomichaelsousa/feat/mutation-webhook-…
Browse files Browse the repository at this point in the history
…configuration

[feature] Add `MutatingWebhookConfiguration` resource
  • Loading branch information
rennokki committed Dec 4, 2021
2 parents 4b7adfe + f961dac commit 5d66943
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 2 deletions.
35 changes: 35 additions & 0 deletions src/Kinds/K8sMutatingWebhookConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace RenokiCo\PhpK8s\Kinds;

use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster;
use RenokiCo\PhpK8s\Contracts\Watchable;
use RenokiCo\PhpK8s\Traits\Resource\HasWebhooks;

class K8sMutatingWebhookConfiguration extends K8sResource implements
InteractsWithK8sCluster,
Watchable
{
use HasWebhooks;

/**
* The resource Kind parameter.
*
* @var null|string
*/
protected static $kind = 'MutatingWebhookConfiguration';

/**
* The default version for the resource.
*
* @var string
*/
protected static $defaultVersion = 'admissionregistration.k8s.io/v1';

/**
* Wether the resource has a namespace.
*
* @var bool
*/
protected static $namespaceable = false;
}
4 changes: 4 additions & 0 deletions src/KubernetesCluster.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@
* @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)
Expand Down
13 changes: 13 additions & 0 deletions src/Traits/InitializesResources.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use RenokiCo\PhpK8s\Kinds\K8sHorizontalPodAutoscaler;
use RenokiCo\PhpK8s\Kinds\K8sIngress;
use RenokiCo\PhpK8s\Kinds\K8sJob;
use RenokiCo\PhpK8s\Kinds\K8sMutatingWebhookConfiguration;
use RenokiCo\PhpK8s\Kinds\K8sNamespace;
use RenokiCo\PhpK8s\Kinds\K8sNode;
use RenokiCo\PhpK8s\Kinds\K8sPersistentVolume;
Expand Down Expand Up @@ -316,4 +317,16 @@ public static function validatingWebhookConfiguration($cluster = null, array $at
{
return new K8sValidatingWebhookConfiguration($cluster, $attributes);
}

/**
* Create a new MutatingWebhookConfiguration kind.
*
* @param \RenokiCo\PhpK8s\KubernetesCluster|null $cluster
* @param array $attributes
* @return \RenokiCo\PhpK8s\Kinds\K8sMutatingWebhookConfiguration
*/
public static function mutatingWebhookConfiguration($cluster = null, array $attributes = [])
{
return new K8sMutatingWebhookConfiguration($cluster, $attributes);
}
}
203 changes: 203 additions & 0 deletions tests/MutatingWebhookConfigurationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php

namespace RenokiCo\PhpK8s\Test;

use RenokiCo\PhpK8s\Exceptions\KubernetesAPIException;
use RenokiCo\PhpK8s\Instances\Webhook;
use RenokiCo\PhpK8s\K8s;
use RenokiCo\PhpK8s\Kinds\K8sMutatingWebhookConfiguration;
use RenokiCo\PhpK8s\ResourcesList;

class MutatingWebhookConfigurationTest extends TestCase
{
public function test_mutation_webhook_build()
{
$webhook = K8s::webhook()
->setName('v1.webhook.com')
->addRule([
'apiGroups' => [''],
'apiVersions' => ['v1'],
'operations' => ['CREATE'],
'resources' => ['pods'],
'scope' => 'Namespaced',
])
->setClientConfig(['url' => 'https://my-webhook.example.com:9443/my-webhook-path'])
->setAdmissionReviewVersions(['v1', 'v1beta'])
->setSideEffects('None')
->setTimeoutSeconds(5);

$mutatingWebhookConfiguration = $this->cluster->mutatingWebhookConfiguration()
->setName('ingress-mutation-webhook')
->setLabels(['tier' => 'webhook'])
->setAnnotations(['webhook/annotation' => 'yes'])
->setWebhooks([$webhook]);

$this->assertEquals('admissionregistration.k8s.io/v1', $mutatingWebhookConfiguration->getApiVersion());
$this->assertEquals('ingress-mutation-webhook', $mutatingWebhookConfiguration->getName());
$this->assertEquals(['tier' => 'webhook'], $mutatingWebhookConfiguration->getLabels());
$this->assertEquals(['webhook/annotation' => 'yes'], $mutatingWebhookConfiguration->getAnnotations());
$this->assertInstanceOf(K8sMutatingWebhookConfiguration::class, $mutatingWebhookConfiguration);
}

public function test_mutation_webhook_from_yaml()
{
$mutatingWebhookConfiguration = $this->cluster->fromYamlFile(__DIR__.'/yaml/mutatingwebhookconfiguration.yaml');

$this->assertEquals('admissionregistration.k8s.io/v1', $mutatingWebhookConfiguration->getApiVersion());
$this->assertEquals('ingress-mutation-webhook', $mutatingWebhookConfiguration->getName());
$this->assertEquals(['tier' => 'webhook'], $mutatingWebhookConfiguration->getLabels());
$this->assertEquals(['webhook/annotation' => 'yes'], $mutatingWebhookConfiguration->getAnnotations());
}

public function test_mutation_webhook_api_interaction()
{
$this->runCreationTests();
$this->runGetAllTests();
$this->runGetTests();
$this->runUpdateTests();
$this->runWatchAllTests();
$this->runWatchTests();
$this->runDeletionTests();
}

public function runCreationTests()
{
$webhook = K8s::webhook()
->setName('v1.webhook.com')
->addRules([
[
'apiGroups' => [''],
'apiVersions' => ['v1'],
'operations' => ['CREATE'],
'resources' => ['pods'],
'scope' => 'Namespaced',
],
])
->setClientConfig(['url' => 'https://my-webhook.example.com:9443/my-webhook-path'])
->setAdmissionReviewVersions(['v1', 'v1beta'])
->setSideEffects('None')
->setTimeoutSeconds(5);

$mutatingWebhookConfiguration = $this->cluster->mutatingWebhookConfiguration()
->setName('ingress-mutation-webhook')
->setLabels(['tier' => 'webhook'])
->setAnnotations(['webhook/annotation' => 'yes'])
->setWebhooks([$webhook]);

$this->assertFalse($mutatingWebhookConfiguration->isSynced());
$this->assertFalse($mutatingWebhookConfiguration->exists());

$mutatingWebhookConfiguration = $mutatingWebhookConfiguration->createOrUpdate();

$this->assertTrue($mutatingWebhookConfiguration->isSynced());
$this->assertTrue($mutatingWebhookConfiguration->exists());

$this->assertInstanceOf(K8sMutatingWebhookConfiguration::class, $mutatingWebhookConfiguration);

$this->assertEquals('admissionregistration.k8s.io/v1', $mutatingWebhookConfiguration->getApiVersion());
$this->assertEquals('ingress-mutation-webhook', $mutatingWebhookConfiguration->getName());
$this->assertEquals(['tier' => 'webhook'], $mutatingWebhookConfiguration->getLabels());
$this->assertArrayHasKey('webhook/annotation', $mutatingWebhookConfiguration->getAnnotations());
$this->assertEquals(1, count($mutatingWebhookConfiguration->getWebhooks()));

foreach ($mutatingWebhookConfiguration->getWebhooks() as $mw) {
$this->assertEquals($webhook->getName(), $mw->getName());
$this->assertEquals($webhook->getSideEffects(), $mw->getSideEffects());
$this->assertEquals($webhook->getTimeoutSeconds(), $mw->getTimeoutSeconds());
$this->assertEquals($webhook->getAdmissionReviewVersions(), $mw->getAdmissionReviewVersions());
$this->assertEquals($webhook->getClientConfig(), $mw->getClientConfig());
$this->assertEquals($webhook->getRules(), $mw->getRules());

$this->assertInstanceOf(Webhook::class, $mw);
}
}

public function runGetAllTests()
{
$mutatingWebhookConfigurations = $this->cluster->getAllMutatingWebhookConfiguration();
$this->assertInstanceOf(ResourcesList::class, $mutatingWebhookConfigurations);

foreach ($mutatingWebhookConfigurations as $mutatingWebhookConfiguration) {
$this->assertInstanceOf(K8sMutatingWebhookConfiguration::class, $mutatingWebhookConfiguration);

$this->assertNotNull($mutatingWebhookConfiguration->getName());
}
}

public function runGetTests()
{
$mutatingWebhookConfiguration = $this->cluster->getMutatingWebhookConfigurationByName('ingress-mutation-webhook');

$this->assertInstanceOf(K8sMutatingWebhookConfiguration::class, $mutatingWebhookConfiguration);

$this->assertTrue($mutatingWebhookConfiguration->isSynced());

$this->assertEquals('admissionregistration.k8s.io/v1', $mutatingWebhookConfiguration->getApiVersion());
$this->assertEquals('ingress-mutation-webhook', $mutatingWebhookConfiguration->getName());
$this->assertEquals(['tier' => 'webhook'], $mutatingWebhookConfiguration->getLabels());
$this->assertArrayHasKey('webhook/annotation', $mutatingWebhookConfiguration->getAnnotations());
$this->assertEquals(1, count($mutatingWebhookConfiguration->getWebhooks()));

foreach ($mutatingWebhookConfiguration->getWebhooks() as $mw) {
$this->assertInstanceOf(Webhook::class, $mw);
}
}

public function runUpdateTests()
{
$mutatingWebhookConfiguration = $this->cluster->getMutatingWebhookConfigurationByName('ingress-mutation-webhook');

$this->assertTrue($mutatingWebhookConfiguration->isSynced());

$mutatingWebhookConfiguration->setAnnotations([]);

$mutatingWebhookConfiguration->createOrUpdate();

$this->assertTrue($mutatingWebhookConfiguration->isSynced());

$this->assertEquals('admissionregistration.k8s.io/v1', $mutatingWebhookConfiguration->getApiVersion());
$this->assertEquals('ingress-mutation-webhook', $mutatingWebhookConfiguration->getName());
$this->assertEquals(['tier' => 'webhook'], $mutatingWebhookConfiguration->getLabels());
$this->assertEquals([], $mutatingWebhookConfiguration->getAnnotations());

foreach ($mutatingWebhookConfiguration->getWebhooks() as $mw) {
$this->assertInstanceOf(Webhook::class, $mw);
}
}

public function runDeletionTests()
{
$mutatingWebhookConfiguration = $this->cluster->getMutatingWebhookConfigurationByName('ingress-mutation-webhook');

$this->assertTrue($mutatingWebhookConfiguration->delete());

while ($mutatingWebhookConfiguration->exists()) {
dump("Awaiting for mutation webhook configuration {$mutatingWebhookConfiguration->getName()} to be deleted...");
sleep(1);
}

$this->expectException(KubernetesAPIException::class);

$this->cluster->getMutatingWebhookConfigurationByName('ingress-mutation-webhook');
}

public function runWatchAllTests()
{
$watch = $this->cluster->mutatingWebhookConfiguration()->watchAll(function ($type, $mutatingWebhookConfiguration) {
if ($mutatingWebhookConfiguration->getName() === 'ingress-mutation-webhook') {
return true;
}
}, ['timeoutSeconds' => 10]);

$this->assertTrue($watch);
}

public function runWatchTests()
{
$watch = $this->cluster->mutatingWebhookConfiguration()->watchByName('ingress-mutation-webhook', function ($type, $mutatingWebhookConfiguration) {
return $mutatingWebhookConfiguration->getName() === 'ingress-mutation-webhook';
}, ['timeoutSeconds' => 10]);

$this->assertTrue($watch);
}
}
4 changes: 2 additions & 2 deletions tests/ValidatingWebhookConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public function runCreationTests()
foreach ($validatingWebhookConfiguration->getWebhooks() as $vw) {
$this->assertEquals($webhook->getName(), $vw->getName());
$this->assertEquals($webhook->getSideEffects(), $vw->getSideEffects());
//$this->assertEquals($webhook->getTimeoutSeconds(), $vw->getTimeoutSeconds());
$this->assertEquals($webhook->getTimeoutSeconds(), $vw->getTimeoutSeconds());
$this->assertEquals($webhook->getAdmissionReviewVersions(), $vw->getAdmissionReviewVersions());
$this->assertEquals($webhook->getClientConfig(), $vw->getClientConfig());
$this->assertEquals($webhook->getRules(), $vw->getRules());
Expand Down Expand Up @@ -178,7 +178,7 @@ public function runDeletionTests()

$this->expectException(KubernetesAPIException::class);

$this->cluster->getDeploymentByName('ingress-validation-webhook');
$this->cluster->getValidatingWebhookConfigurationByName('ingress-validation-webhook');
}

public function runWatchAllTests()
Expand Down
21 changes: 21 additions & 0 deletions tests/yaml/mutatingwebhookconfiguration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: "ingress-mutation-webhook"
labels:
tier: webhook
annotations:
webhook/annotation: "yes"
webhooks:
- name: "v1.webhook.com"
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
scope: "Namespaced"
clientConfig:
url: "https://my-webhook.example.com:9443/my-webhook-path"
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5

0 comments on commit 5d66943

Please sign in to comment.