Skip to content

Commit

Permalink
Removed static KubernetesCluster::create
Browse files Browse the repository at this point in the history
Added fromKubeConfigVariable
Updated docblocks
Renamed functions to better represent their job
  • Loading branch information
rennokki committed Sep 3, 2021
1 parent 96a6425 commit af14f58
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 76 deletions.
10 changes: 0 additions & 10 deletions src/Exceptions/KubeConfigFileNotFound.php

This file was deleted.

79 changes: 35 additions & 44 deletions src/Traits/Cluster/LoadsFromKubeConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
use Illuminate\Support\Arr;
use RenokiCo\PhpK8s\Exceptions\KubeConfigClusterNotFound;
use RenokiCo\PhpK8s\Exceptions\KubeConfigContextNotFound;
use RenokiCo\PhpK8s\Exceptions\KubeConfigFileNotFound;
use RenokiCo\PhpK8s\Exceptions\KubeConfigUserNotFound;
use RenokiCo\PhpK8s\Kinds\K8sResource;
use RenokiCo\PhpK8s\KubernetesCluster;

trait LoadsFromKubeConfig
{
Expand All @@ -34,56 +32,41 @@ public static function setTempFolder(string $tempFolder)
}

/**
* Creates a KubernetesCluster instance according to the current environment.
* Loads the configuration fro the KubernetesCluster instance
* according to the current KUBECONFIG environment variable.
*
* This method implements the same connection algorithm as kubectl.
* First, it will read the KUBECONFIG environment variable and merge the referenced YAML files.
* If KUBECONFIG isn't set, the method will try to load $HOME/.kube/config.
*
* The current context will be used unless a context name is explicitly passed as parameter of this method.
*
* @see https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/
* @see https://github.com/kubernetes/client-go/blob/f6ce18ae578c8cca64d14ab9687824d9e1305a67/tools/clientcmd/loader.go#L139
*
* @return LoadsFromKubeConfig
* @throws KubeConfigClusterNotFound
* @throws KubeConfigContextNotFound
* @throws KubeConfigFileNotFound
* @throws KubeConfigUserNotFound
* @param string|null $context
* @return $this
* @throws \RenokiCo\PhpK8s\Exceptions\KubeConfigClusterNotFound
* @throws \RenokiCo\PhpK8s\Exceptions\KubeConfigContextNotFound
* @throws \RenokiCo\PhpK8s\Exceptions\KubeConfigUserNotFound
*/
public static function create(?string $currentContext = null): KubernetesCluster
public function fromKubeConfigVariable(string $context = null)
{
if (isset($_SERVER['KUBECONFIG'])) {
$paths = array_unique(explode(':', $_SERVER['KUBECONFIG']));
} else {
$paths = [($_SERVER['HOME'] ?? '').'/.kube/config'];
if (! isset($_SERVER['KUBECONFIG'])) {
return $this;
}

$paths = array_unique(explode(':', $_SERVER['KUBECONFIG']));
$kubeconfig = [];

foreach ($paths as $path) {
if ('' === $path || ! @is_readable($path) || false === $yaml = yaml_parse_file($path)) {
if (! @is_readable($path) || ($yaml = yaml_parse_file($path)) === false) {
continue;
}

$kubeconfig = self::mergeKubeconfig($kubeconfig, $yaml);
$kubeconfig = static::mergeKubeconfigContents($kubeconfig, $yaml);
}

if ([] === $kubeconfig) {
throw new KubeConfigFileNotFound(sprintf('Kubernetes configuration not found (paths: "%s")', implode('", "', $paths)));
if ($kubeconfig === []) {
return $this;
}

if (null === $currentContext && isset($kubeconfig['current-context'])) {
$currentContext = $kubeconfig['current-context'];
if (! $context && isset($kubeconfig['current-context'])) {
$context = $kubeconfig['current-context'];
}

if (null === $currentContext) {
throw new KubeConfigContextNotFound('Kubernetes context not set.');
}

$cluster = new KubernetesCluster('');
$cluster->loadKubeConfigFromArray($kubeconfig, $currentContext);

return $cluster;
$this->loadKubeConfigFromArray($kubeconfig, $context);
}

/**
Expand Down Expand Up @@ -211,21 +194,29 @@ protected function writeTempFileForContext(string $context, string $fileName, st
return $tempFilePath;
}

private static function mergeKubeconfig(array $a1, array $a2): array
/**
* Merge the two kubeconfig contents.
*
* @param array $kubeconfig1
* @param array $kubeconfig2
* @return array
*/
protected static function mergeKubeconfigContents(array $kubeconfig1, array $kubeconfig2): array
{
$a1 += $a2;
foreach ($a1 as $key => $value) {
$kubeconfig1 += $kubeconfig2;

foreach ($kubeconfig1 as $key => $value) {
if (
is_array($value) &&
isset($a2[$key]) &&
is_array($a2[$key]) &&
isset($kubeconfig2[$key]) &&
is_array($kubeconfig2[$key]) &&
! Arr::isAssoc($value) &&
! Arr::isAssoc($a2[$key])
! Arr::isAssoc($kubeconfig2[$key])
) {
$a1[$key] = array_merge($a1[$key], $a2[$key]);
$kubeconfig1[$key] = array_merge($kubeconfig1[$key], $kubeconfig2[$key]);
}
}

return $a1;
return $kubeconfig1;
}
}
30 changes: 8 additions & 22 deletions tests/KubeConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use RenokiCo\PhpK8s\Exceptions\KubeConfigClusterNotFound;
use RenokiCo\PhpK8s\Exceptions\KubeConfigContextNotFound;
use RenokiCo\PhpK8s\Exceptions\KubeConfigFileNotFound;
use RenokiCo\PhpK8s\Exceptions\KubeConfigUserNotFound;
use RenokiCo\PhpK8s\Kinds\K8sResource;
use RenokiCo\PhpK8s\KubernetesCluster;
Expand Down Expand Up @@ -200,36 +199,23 @@ public function test_in_cluster_config()
}

/**
* @dataProvider contextProvider
* @dataProvider environmentVariableContextProvider
*/
public function test_from_environment_variable(?string $context, string $domain)
public function test_from_environment_variable(string $context = null, string $expectedDomain)
{
$_SERVER['KUBECONFIG'] = __DIR__.'/cluster/kubeconfig.yaml::'.__DIR__.'/cluster/kubeconfig-2.yaml';

$cluster = KubernetesCluster::create($context);
$this->assertSame("https://$domain:8443/?", $cluster->getCallableUrl('/', []));
$cluster = new KubernetesCluster("https://{$expectedDomain}:8443");

$cluster->fromKubeConfigVariable($context);

$this->assertSame("https://{$expectedDomain}:8443/?", $cluster->getCallableUrl('/', []));
}

public function contextProvider(): iterable
public function environmentVariableContextProvider(): iterable
{
yield [null, 'minikube'];
yield ['minikube-2', 'minikube-2'];
yield ['minikube-3', 'minikube-3'];
}

public function test_from_environment_variable_file_not_found()
{
$this->expectException(KubeConfigFileNotFound::class);

$_SERVER['KUBECONFIG'] = '/notfound';
KubernetesCluster::create();
}

public function test_from_environment_variable_context_not_set()
{
$this->expectException(KubeConfigContextNotFound::class);

$_SERVER['KUBECONFIG'] = __DIR__.'/cluster/kubeconfig-2.yaml';
KubernetesCluster::create();
}
}

0 comments on commit af14f58

Please sign in to comment.