Custom resources & macros
Define a resource class for any kind — including your own CRDs — and register it in config/kubernetes.php or at runtime:
use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;
use RoundlyConsulting\KubernetesApi\Resources\Resource;
class Application extends Resource
{
protected string $version = 'example.com/v2';
protected string $kind = 'Application';
protected bool $usesNamespaces = true;
}
Kubernetes::registerResource('apps', Application::class);
Kubernetes::cluster('production')->apps()->get(); // all Application resources
Kubernetes::apps()->get(); // on the default cluster- $version — the apiVersion. v1 (the default) maps to /api/v1; anything else to /apis/<version>.
- $kind — the kind written into every payload.
- $usesNamespaces — true for namespaced kinds; the default false makes the resource cluster-scoped.
- $plural — the REST plural. Left null it is the lower-cased kind, pluralised; set it when the CRD’s spec.names.plural differs.
- Add the traits you need — HasSpec, HasStatus, HasStatusPhase, HasReplicas… from RoundlyConsulting\KubernetesApi\Traits\Resource.
namespace App\Kubernetes;
use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;
use RoundlyConsulting\KubernetesApi\Resources\Resource;
use RoundlyConsulting\KubernetesApi\Traits\Resource\HasSpec;
use RoundlyConsulting\KubernetesApi\Traits\Resource\HasStatus;
class DatabaseMigration extends Resource
{
use HasSpec;
use HasStatus;
protected string $version = 'ops.example.com/v1';
protected string $kind = 'DatabaseMigration';
protected ?string $plural = 'dbmigrations'; // the CRD's spec.names.plural
protected bool $usesNamespaces = true;
}
// Registered or not, any class resolves through resource():
Kubernetes::cluster('production')->resource(DatabaseMigration::class)
->setNamespace('shop')
->setName('add-orders-index')
->setSpec('database', 'orders')
->create();Registering and swapping in config
The resources map is read at call time, and Kubernetes::registerResource() writes into the same map. Pointing a built-in name at your own subclass swaps it on every cluster, the facade included — resource classes are deliberately not final. A name a Cluster method already answers (url, namespace, …) is refused with InvalidResourceException:
// config/kubernetes.php
'resources' => [
// …keep the built-in entries from the published file…
'dbMigrations' => App\Kubernetes\DatabaseMigration::class,
// Swap a built-in: every $cluster->pods() now returns your subclass
'pods' => App\Kubernetes\Pod::class,
],namespace App\Kubernetes;
use RoundlyConsulting\KubernetesApi\Resources\Pod as BasePod;
class Pod extends BasePod
{
public function isServing(): bool
{
return $this->isRunning() && $this->containersReady();
}
}Macros and conditionals
Both Cluster and every resource use Laravel’s Macroable and Conditionable traits, so you can extend and branch fluently. A Cluster macro is also callable on the facade, for the default cluster:
use RoundlyConsulting\KubernetesApi\Cluster;
use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;
use RoundlyConsulting\KubernetesApi\Resources\Deployment;
// A resource macro — $this is the resource
Deployment::macro('isFullyAvailable', function (): bool {
/** @var Deployment $this */
return $this->getAvailableReplicasCount() >= $this->getReplicas();
});
// A client macro — $this is the cluster client
Cluster::macro('tenantNamespace', function (string $tenant) {
/** @var Cluster $this */
return $this->namespaces()->setName("tenant-{$tenant}");
});
$cluster = Kubernetes::cluster('production');
$cluster->deployments()->setNamespace('shop')->withName('checkout')->find()->isFullyAvailable();
$cluster->tenantNamespace('acme')->create();
Kubernetes::tenantNamespace('acme'); // a Cluster macro also works on the facade (default cluster)
// Conditionable — branch without breaking the chain
$cluster->deployments()->setNamespace('shop')->withName('checkout')->find()
->when($peakTraffic, fn (Deployment $deployment) => $deployment->setReplicas(12))
->unless($peakTraffic, fn (Deployment $deployment) => $deployment->setReplicas(3))
->update();Resource macros whose names start with set, get, with, addTo or remove are intercepted by the magic attribute accessors — pick another prefix, such as is…, has… or find….
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.