Initial commit

This commit is contained in:
2022-03-07 22:45:54 +01:00
commit 6cdb155dc5
10 changed files with 487 additions and 0 deletions

View File

@ -0,0 +1,33 @@
<?php
namespace NoccyLabs\FreshDocker\Configuration;
use Symfony\Component\Yaml\Yaml;
class DockerComposeConfiguration
{
private array $checks = [];
public function __construct(string $configfile)
{
$this->loadComposeFile($configfile);
}
private function loadComposeFile($configfile)
{
$config = Yaml::parseFile($configfile);
$services = $config['services']??[];
foreach ($services as $name=>$service) {
$image = $service['image']??null;
if ($image && !in_array($image,$this->checks)) {
$this->checks[] = $image;
}
}
}
public function getChecks(): array
{
return $this->checks;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace NoccyLabs\FreshDocker\Configuration;
use Symfony\Component\Yaml\Yaml;
class LocalConfiguration
{
private array $config = [];
public function __construct(string $configfile)
{
$this->config = Yaml::parseFile($configfile);
}
public function getChecks(): array
{
return $this->config['check']??[];
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace NoccyLabs\FreshDocker\Credentials;
class BasicCredentialsLoader
{
private array $auth = [];
public function __construct()
{
$this->load();
}
private function load()
{
$config = getenv("HOME")."/.docker/config.json";
if (!file_exists($config)) return;
$conf = json_decode(file_get_contents($config));
$this->auth = isset($conf->auths) ? (array)$conf->auths : [];
}
public function getCredentials(string $repo): ?array
{
if (!array_key_exists($repo, $this->auth))
return null;
$auth = $this->auth[$repo]->auth;
return explode(":", base64_decode($auth), 2);
}
}

56
src/Hooks/SlackHook.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace NoccyLabs\FreshDocker\Hooks;
use GuzzleHttp\Client;
use RuntimeException;
class SlackHook
{
private array $options = [];
public function __construct(array $options = [])
{
$this->options = $options;
}
public function sendMessage(string $text, array $options)
{
$mergedOptions = array_merge($this->options, $options);
$url = $mergedOptions['url'] ?? throw new RuntimeException("Empty hook url");
$body = $this->makeBody($text, $mergedOptions);
$client = new Client();
$client->post($url, [
'json' => $body
]);
}
private function makeBody(string $text, array $options)
{
/*
{
"channel": "town-square",
"username": "test-automation",
"icon_url": "https://mattermost.org/wp-content/uploads/2016/04/icon.png",
"text": "#### Test results for July 27th, 2017\n<!channel> please review failed tests.\n
| Component | Tests Run | Tests Failed |
|:-----------|:-----------:|:-----------------------------------------------|
| Server | 948 | :white_check_mark: 0 |
| Web Client | 123 | :warning: 2 [(see details)](http://linktologs) |
| iOS Client | 78 | :warning: 3 [(see details)](http://linktologs) |
"
}
*/
$body = [];
if (array_key_exists('channel', $options)) $body['channel'] = $options['channel'];
if (array_key_exists('username', $options)) $body['username'] = $options['username'];
if (array_key_exists('icon_url', $options)) $body['icon_url'] = $options['icon_url'];
$body['text'] = $text;
return $body;
}
}

56
src/ImageReference.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace NoccyLabs\FreshDocker;
class ImageReference
{
private $image;
private $tag;
private $registry;
private $scheme;
public function __construct(string $image)
{
// if (!preg_match('/^http[s]:\/\//i', $image)) {
$parts = explode("/", $image);
if (count($parts) < 3) {
$image = "https://registry.hub.docker.com/{$image}";
} else {
$image = "https://{$image}";
}
$parts = parse_url($image);
$image = ltrim($parts['path'],'/');
if (str_contains($image,':')) {
[$image, $tag] = explode(":", $image, 2);
} else {
$tag = 'latest';
}
if (!str_contains($image,'/')) {
$image = "library/{$image}";
}
$this->image = $image;
$this->tag = $tag;
$this->registry = $parts['host'];
$this->scheme = $parts['scheme'];
}
public function getRegistry(): string
{
return $this->registry;
}
public function getImage(): string
{
return $this->image;
}
public function getTag(): string
{
return $this->tag;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace NoccyLabs\FreshDocker\Registry;
use GuzzleHttp\Client;
class RegistryV2Client
{
private Client $client;
public function __construct(string $registry, ?array $auth)
{
$this->createClient($registry, $auth);
}
private function createClient(string $registry, ?array $auth)
{
$this->client = new Client([
'base_uri' => 'https://' . $registry . '/v2/',
'auth' => $auth,
]);
}
public function getManifest(string $image, string $tag)
{
$response = $this->client->get("{$image}/manifests/{$tag}");
$body = $response->getBody();
return json_decode($body);
}
public function getImageStatus(string $image, string $tag)
{
$manifest = $this->getManifest($image, $tag);
$fslayers = (array)$manifest->fsLayers;
$fshashes = array_map(fn($layer) => $layer->blobSum, $fslayers);
$metahash = hash("sha256", join("|", $fshashes));
$history = $manifest->history[0];
$info = json_decode($history->v1Compatibility);
return [
'image' => $image,
'tag' => $tag,
'hash' => $metahash,
'created' => $info->created??null,
];
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace NoccyLabs\FreshDocker\State;
use Symfony\Component\Yaml\Yaml;
class PersistentState
{
private string $filename;
private array $state = [];
private bool $dirty = false;
public function __construct(string $filename)
{
$this->filename = $filename;
register_shutdown_function([$this,"flush"]);
if (file_exists($filename)) {
$this->state = Yaml::parseFile($filename);
}
}
public function flush()
{
if (!$this->dirty) return;
$yaml = Yaml::dump($this->state);
file_put_contents($this->filename."~", $yaml);
rename($this->filename."~", $this->filename);
}
public function set(string $key, $value)
{
$this->state[$key] = $value;
$this->dirty = true;
}
public function get(string $key, $default=null): mixed
{
return $this->state[$key] ?? $default;
}
public function unset(string $key)
{
unset($this->state[$key]);
}
}