Skip to content

Instantly share code, notes, and snippets.

@ebuildy
Created February 1, 2017 10:43
Show Gist options
  • Save ebuildy/9770009c39932990ff4013dac42ee923 to your computer and use it in GitHub Desktop.
Save ebuildy/9770009c39932990ff4013dac42ee923 to your computer and use it in GitHub Desktop.
Retrieve Gitlab projects with Docker container registry tags.
<?php
namespace AppBundle\Service;
class ContainerImageRepository
{
/**
* URL to container registry.
*
* @var string
*/
private $registryUrl;
/**
* URL to gitlab.
*
* @var string
*/
private $gitlabUrl;
/**
* Hash of gitlab auth.
*
* @var string
*/
private $gitlabAuthHash;
/**
* Private access token to gitlab.
*
* @var string
*/
private $gitlabAccessToken;
/**
* @var null|\Psr\Log\LoggerInterface
*/
private $logger = null;
public function __construct($registryUrl, $gitlabUrl, $gitlabAccessToken, $gitlabAuthHash)
{
$this->registryUrl = $registryUrl;
$this->gitlabUrl = $gitlabUrl;
$this->gitlabAccessToken = $gitlabAccessToken;
$this->gitlabAuthHash = $gitlabAuthHash;
}
/**
* Set optional logger
*
* @param $logger
*/
public function setLogger($logger)
{
$this->logger = $logger;
}
/**
* Retrieve Gitlab project with container registry details.
*
* @return array
*/
public function find()
{
$repositories = [];
$projects = $this->getProjects();
foreach($projects as $project)
{
$repositories []= $project->path_with_namespace;
}
$authorizations = $this->getAuthorizations($repositories);
$repositoriesDetails = $this->getRegistryTags($repositories, $authorizations);
$results = [];
foreach($projects as $project)
{
if ($project->container_registry_enabled === true &&
isset($repositoriesDetails[$project->path_with_namespace]))
{
$results[] = [
'project' => $project,
'container_registry_tags' => $repositoriesDetails[$project->path_with_namespace]
];
}
}
return $results;
}
/**
* Retrieve Gitlab projects.
*
* @return array
*/
private function getProjects()
{
$client = new \GuzzleHttp\Client();
$httpQueries = [];
for($page = 1; $page < 5; $page++)
{
$url = sprintf('%s/api/v3/projects/visible?%s', $this->gitlabUrl, http_build_query([
'page' => $page,
'per_page' => '20'
]));
$httpQueries[$page] = new \GuzzleHttp\Psr7\Request('GET', $url, [
'User-agent' => 'testy/1.0',
'Accept-Encoding' => 'gzip, deflate, sdch',
'Cache-Control' => 'max-age=0',
'PRIVATE-TOKEN' => $this->gitlabAccessToken
]);
}
$responses = \GuzzleHttp\Pool::batch($client, $httpQueries, ['concurrency' => 10]);
$projects = [];
foreach($responses as $repository => $response)
{
if ($response instanceof \GuzzleHttp\Exception\ClientException)
{
$this->log(\Psr\Log\LogLevel::ERROR, $response->getMessage());
}
elseif ($response->getStatusCode() === 200)
{
$buffer = \GuzzleHttp\json_decode((string) $response->getBody());
if (!empty($buffer))
{
foreach($buffer as $project)
{
if ($project->container_registry_enabled === true)
{
$projects[] = $project;
}
}
}
}
}
return $projects;
}
/**
* Retrieve auth. token for each repository.
*
* @param $repositories
* @return array
*/
private function getAuthorizations($repositories)
{
$client = new \GuzzleHttp\Client();
$httpQueries = [];
foreach($repositories as $repository)
{
$url = sprintf('%s/jwt/auth?%s', $this->gitlabUrl, http_build_query([
'client_id' => 'docker',
'service' => 'container_registry',
'offline_token' => 'true',
'scope' => sprintf('repository:%s:pull', $repository)
]));
$httpQueries[$repository] = new \GuzzleHttp\Psr7\Request('GET', $url, [
'User-agent' => 'testy/1.0',
'Accept-Encoding' => 'gzip, deflate, sdch',
'Cache-Control' => 'max-age=0',
'Authorization' => sprintf('Basic %s', $this->gitlabAuthHash)
]);
}
$responses = \GuzzleHttp\Pool::batch($client, $httpQueries, ['concurrency' => 10]);
$auths = [];
foreach($responses as $repository => $response)
{
if ($response instanceof \GuzzleHttp\Exception\ClientException)
{
$this->log(\Psr\Log\LogLevel::ERROR, $response->getMessage());
}
elseif ($response->getStatusCode() === 200)
{
try {
$buffer = \GuzzleHttp\json_decode((string)$response->getBody());
if (!empty($buffer) && isset($buffer->token)) {
$auths[$repository] = $buffer->token;
}
}
catch(\Exception $e) {
continue;
}
}
}
return $auths;
}
/**
* Retrieve container registry tags for each repository.
*
* @param $repositories
* @param $authorizations
* @return array
*/
private function getRegistryTags($repositories, $authorizations)
{
$client = new \GuzzleHttp\Client();
$httpQueries = [];
foreach($repositories as $repository)
{
if (isset($authorizations[$repository]))
{
$url = sprintf('%s/v2/%s/tags/list', $this->registryUrl, $repository);
$httpQueries[$repository] = new \GuzzleHttp\Psr7\Request('GET', $url, [
'User-agent' => 'testy/1.0',
'Accept-Encoding' => 'gzip, deflate, sdch',
'Cache-Control' => 'max-age=0',
'Authorization' => sprintf('Bearer %s', $authorizations[$repository])
]);
}
}
$responses = \GuzzleHttp\Pool::batch($client, $httpQueries, ['concurrency' => 10]);
$results = [];
foreach($responses as $repository => $response)
{
if ($response instanceof \GuzzleHttp\Exception\ClientException)
{
$this->log(\Psr\Log\LogLevel::ERROR, $response->getMessage());
}
elseif ($response->getStatusCode() === 200)
{
$buffer = \GuzzleHttp\json_decode((string) $response->getBody());
if (!empty($buffer) && isset($buffer->tags)) {
$results[$repository] = $buffer->tags;
}
}
}
return $results;
}
/**
* Decorate logger.
*
* @param $level
* @param $message
* @param array $context
*/
private function log($level, $message, $context = [])
{
if (!empty($this->logger))
{
$this->logger->log($level, $message, $context);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment