Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.x] Pod Attach API #79

Merged
merged 3 commits into from
Mar 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions docs/kinds/Pod.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Container Retrieval](#container-retrieval)
- [Pod Logs](#pod-logs)
- [Pod Exec](#pod-exec)
- [Pod Attach](#pod-attach)
- [Pod Status](#pod-status)
- [Containers' Statuses](#containers-statuses)

Expand Down Expand Up @@ -149,6 +150,38 @@ Pass an additional container parameter in case there is more than just 1 contain
$messages = $pod->exec(['/bin/sh', '-c', 'ls -al'], 'mysql');
```

## Pod Attach

You can attach to a container of a pod using the `attach` method. It accepts a callback that passes a WebSocket connection where you can listen to the pod's container output:

```php
use Ratchet\Client\WebSocket;

$stdChannels = [
'stdin',
'stdout',
'stderr',
'error',
'resize',
];

$pod->attach(function (WebSocket $connection) use ($stdChannels) {
$connection->on('message', function ($message) use ($connection, $stdChannels) {
// Decode the channel (stdin, stdout, etc.) and the message.
$channel = $stdChannels[substr($data, 0, 1)];
$message = base64_decode(substr($data, 1));

// Do something with the message.
echo $message.PHP_EOL;

// Call ->close() to end the loop and close the connection.
$connection->close();
});
});
```

The connection is provided using [ratchet/pawl](https://github.com/ratchetphp/Pawl#example) and it will block the main thread of the app by running it in a React event loop.

## Pod Status

The Status API is available to be accessed for fresh instances:
Expand Down
13 changes: 13 additions & 0 deletions src/Contracts/Attachable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace RenokiCo\PhpK8s\Contracts;

interface Attachable
{
/**
* Get the path, prefixed by '/', that points to the specific resource to attach.
*
* @return string
*/
public function resourceAttachPath(): string;
}
8 changes: 8 additions & 0 deletions src/Exceptions/KubernetesAttachException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace RenokiCo\PhpK8s\Exceptions;

class KubernetesAttachException extends PhpK8sException
{
//
}
9 changes: 8 additions & 1 deletion src/Kinds/K8sPod.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace RenokiCo\PhpK8s\Kinds;

use RenokiCo\PhpK8s\Contracts\Attachable;
use RenokiCo\PhpK8s\Contracts\Dnsable;
use RenokiCo\PhpK8s\Contracts\Executable;
use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster;
Expand All @@ -18,7 +19,13 @@
use RenokiCo\PhpK8s\Traits\HasStatusConditions;
use RenokiCo\PhpK8s\Traits\HasStatusPhase;

class K8sPod extends K8sResource implements Dnsable, Executable, InteractsWithK8sCluster, Watchable, Loggable
class K8sPod extends K8sResource implements
Attachable,
Dnsable,
Executable,
InteractsWithK8sCluster,
Watchable,
Loggable
{
use HasAnnotations;
use HasLabels;
Expand Down
50 changes: 48 additions & 2 deletions src/Kinds/K8sResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Support\Str;
use RenokiCo\PhpK8s\Contracts\Attachable;
use RenokiCo\PhpK8s\Contracts\Executable;
use RenokiCo\PhpK8s\Contracts\Loggable;
use RenokiCo\PhpK8s\Contracts\Scalable;
use RenokiCo\PhpK8s\Contracts\Watchable;
use RenokiCo\PhpK8s\Exceptions\KubernetesAPIException;
use RenokiCo\PhpK8s\Exceptions\KubernetesAttachException;
use RenokiCo\PhpK8s\Exceptions\KubernetesExecException;
use RenokiCo\PhpK8s\Exceptions\KubernetesLogsException;
use RenokiCo\PhpK8s\Exceptions\KubernetesScalingException;
Expand Down Expand Up @@ -843,8 +845,11 @@ public function scaler(): K8sScale
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesExecException
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesAPIException
*/
public function exec($command, string $container = null, array $query = ['pretty' => 1, 'stdin' => 1, 'stdout' => 1, 'stderr' => 1, 'tty' => 1])
{
public function exec(
$command,
string $container = null,
array $query = ['pretty' => 1, 'stdin' => 1, 'stdout' => 1, 'stderr' => 1, 'tty' => 1]
) {
if (! $this instanceof Executable) {
throw new KubernetesExecException(
'The resource '.get_class($this).' does not support exec commands.'
Expand All @@ -861,6 +866,37 @@ public function exec($command, string $container = null, array $query = ['pretty
);
}

/**
* Attach to the current resource.
*
* @param
* @param string|null $container
* @param array $query
* @return string
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesAttachException
* @throws \RenokiCo\PhpK8s\Exceptions\KubernetesAPIException
*/
public function attach(
Closure $callback = null,
string $container = null,
array $query = ['pretty' => 1, 'stdin' => 1, 'stdout' => 1, 'stderr' => 1, 'tty' => 1]
) {
if (! $this instanceof Attachable) {
throw new KubernetesAttachException(
'The resource '.get_class($this).' does not support attach commands.'
);
}

return $this->cluster
->setResourceClass(get_class($this))
->runOperation(
KubernetesCluster::ATTACH_OP,
$this->resourceAttachPath(),
$callback,
['container' => $container] + $query
);
}

/**
* Get the path, prefixed by '/', that points to the resources list.
*
Expand Down Expand Up @@ -931,6 +967,16 @@ public function resourceExecPath(): string
return "{$this->getApiPathPrefix()}/".static::getPlural()."/{$this->getIdentifier()}/exec";
}

/**
* Get the path, prefixed by '/', that points to the specific resource to attach.
*
* @return string
*/
public function resourceAttachPath(): string
{
return "{$this->getApiPathPrefix()}/".static::getPlural()."/{$this->getIdentifier()}/attach";
}

/**
* Get the prefix path for the resource.
*
Expand Down
Loading