1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-04 05:15:25 +02:00

feat(registry): gitlab support (#3107)

* feat(api): gitlab registry type

* feat(registries): early support for gitlab registries

* feat(app): registry service selector

* feat(registry): gitlab support : list repositories and tags - remove features missing

* feat(registry): gitlab registry remove features

* feat(registry): gitlab switch to registry V2 API for repositories and tags

* feat(api): use development extension binary

* fix(registry): avoid 401 on gitlab retrieve to disconnect the user

* feat(registry): gitlab browse projects without extension

* style(app): code cleaning

* refactor(app): PR review changes + refactor on types

* fix(gitlab): remove gitlab info from registrymanagementconfig and force gitlab type

* style(api): go fmt

* feat(api): update APIVersion and ExtensionDefinitionsURL

* fix(api): fix invalid RM extension URL

* feat(registry): PAT scope help

* feat(registry): defaults on registry creation

* style(registry-creation): update layout and text for Gitlab registry

* feat(registry-creation): update gitlab notice
This commit is contained in:
xAt0mZ 2019-11-12 04:28:31 +01:00 committed by Anthony Lapenna
parent 03d9d6afbb
commit 198e92c734
38 changed files with 1022 additions and 160 deletions

View file

@ -1,6 +1,7 @@
import _ from 'lodash-es';
import { RepositoryShortTag } from '../models/repositoryTag';
import RegistryRepositoryViewModel from '../models/registryRepository';
import { RepositoryAddTagPayload } from '../models/repositoryTag'
import { RegistryRepositoryViewModel } from '../models/registryRepository';
import genericAsyncGenerator from './genericAsyncGenerator';
angular.module('portainer.extensions.registrymanagement')
@ -9,12 +10,24 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
'use strict';
var service = {};
service.ping = function(id, forceNewConfig) {
/**
* PING
*/
function ping(registry, forceNewConfig) {
const id = registry.Id;
if (forceNewConfig) {
return RegistryCatalog.pingWithForceNew({ id: id }).$promise;
}
return RegistryCatalog.ping({ id: id }).$promise;
};
}
/**
* END PING
*/
/**
* REPOSITORIES
*/
function _getCatalogPage(params, deferred, repositories) {
RegistryCatalog.get(params).$promise.then(function(data) {
@ -27,7 +40,7 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
});
}
function getCatalog(id) {
function _getCatalog(id) {
var deferred = $q.defer();
var repositories = [];
@ -35,13 +48,12 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
return deferred.promise;
}
service.catalog = function (id) {
var deferred = $q.defer();
function repositories(registry) {
const deferred = $q.defer();
const id = registry.Id;
getCatalog(id).then(function success(data) {
var repositories = data.map(function (repositoryName) {
return new RegistryRepositoryViewModel(repositoryName);
});
_getCatalog(id).then(function success(data) {
const repositories = _.map(data, (repositoryName) => new RegistryRepositoryViewModel(repositoryName));
deferred.resolve(repositories);
})
.catch(function error(err) {
@ -52,14 +64,37 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
});
return deferred.promise;
};
}
service.tags = function (id, repository) {
var deferred = $q.defer();
function getRepositoriesDetails(registry, repositories) {
const deferred = $q.defer();
const promises = _.map(repositories, (repository) => tags(registry, repository.Name));
$q.all(promises)
.then(function success(data) {
var repositories = data.map(function (item) {
return new RegistryRepositoryViewModel(item);
});
repositories = _.without(repositories, undefined);
deferred.resolve(repositories);
})
.catch(function error(err) {
deferred.reject({
msg: 'Unable to retrieve repositories',
err: err
});
});
_getTagsPage({id: id, repository: repository}, deferred, {tags:[]});
return deferred.promise;
};
}
/**
* END REPOSITORIES
*/
/**
* TAGS
*/
function _getTagsPage(params, deferred, previousTags) {
RegistryTags.get(params).$promise.then(function(data) {
@ -78,45 +113,23 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
});
}
service.getRepositoriesDetails = function (id, repositories) {
var deferred = $q.defer();
var promises = [];
for (var i = 0; i < repositories.length; i++) {
var repository = repositories[i].Name;
promises.push(service.tags(id, repository));
}
$q.all(promises)
.then(function success(data) {
var repositories = data.map(function (item) {
return new RegistryRepositoryViewModel(item);
});
repositories = _.without(repositories, undefined);
deferred.resolve(repositories);
})
.catch(function error(err) {
deferred.reject({
msg: 'Unable to retrieve repositories',
err: err
});
});
function tags(registry, repository) {
const deferred = $q.defer();
const id = registry.Id;
_getTagsPage({id: id, repository: repository}, deferred, {tags:[]});
return deferred.promise;
};
}
service.getTagsDetails = function (id, repository, tags) {
var promises = [];
for (var i = 0; i < tags.length; i++) {
var tag = tags[i].Name;
promises.push(service.tag(id, repository, tag));
}
function getTagsDetails(registry, repository, tags) {
const promises = _.map(tags, (t) => tag(registry, repository, t.Name));
return $q.all(promises);
};
}
service.tag = function (id, repository, tag) {
var deferred = $q.defer();
function tag(registry, repository, tag) {
const deferred = $q.defer();
const id = registry.Id;
var promises = {
v1: RegistryManifestsJquery.get({
@ -142,35 +155,33 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
});
return deferred.promise;
};
}
service.addTag = function (id, repository, {tag, manifest}) {
/**
* END TAGS
*/
/**
* ADD TAG
*/
// tag: RepositoryAddTagPayload
function _addTagFromGenerator(registry, repository, tag) {
return addTag(registry, repository, tag.Tag, tag.Manifest);
}
function addTag(registry, repository, tag, manifest) {
const id = registry.Id;
delete manifest.digest;
return RegistryManifestsJquery.put({
id: id,
repository: repository,
tag: tag
}, manifest);
};
}
service.deleteManifest = function (id, repository, imageDigest) {
return RegistryManifestsJquery.delete({
id: id,
repository: repository,
tag: imageDigest
});
};
service.shortTag = function(id, repository, tag) {
return new Promise ((resolve, reject) => {
RegistryManifestsJquery.getV2({id:id, repository: repository, tag: tag})
.then((data) => resolve(new RepositoryShortTag(tag, data.config.digest, data.digest, data)))
.catch((err) => reject(err))
});
};
async function* addTagsWithProgress(id, repository, tagsList, progression = 0) {
for await (const partialResult of genericAsyncGenerator($q, tagsList, service.addTag, [id, repository])) {
async function* _addTagsWithProgress(registry, repository, tagsList, progression = 0) {
for await (const partialResult of genericAsyncGenerator($q, tagsList, _addTagFromGenerator, [registry, repository])) {
if (typeof partialResult === 'number') {
yield progression + partialResult;
} else {
@ -179,36 +190,110 @@ function RegistryV2ServiceFactory($q, $async, RegistryCatalog, RegistryTags, Reg
}
}
service.shortTagsWithProgress = async function* (id, repository, tagsList) {
yield* genericAsyncGenerator($q, tagsList, service.shortTag, [id, repository]);
/**
* END ADD TAG
*/
/**
* DELETE MANIFEST
*/
function deleteManifest(registry, repository, imageDigest) {
const id = registry.Id;
return RegistryManifestsJquery.delete({
id: id,
repository: repository,
tag: imageDigest
});
}
async function* deleteManifestsWithProgress(id, repository, manifests) {
for await (const partialResult of genericAsyncGenerator($q, manifests, service.deleteManifest, [id, repository])) {
async function* _deleteManifestsWithProgress(registry, repository, manifests) {
for await (const partialResult of genericAsyncGenerator($q, manifests, deleteManifest, [registry, repository])) {
yield partialResult;
}
}
service.retagWithProgress = async function* (id, repository, modifiedTags, modifiedDigests, impactedTags){
yield* deleteManifestsWithProgress(id, repository, modifiedDigests);
/**
* END DELETE MANIFEST
*/
/**
* SHORT TAG
*/
function _shortTagFromGenerator(id, repository, tag) {
return new Promise ((resolve, reject) => {
RegistryManifestsJquery.getV2({id:id, repository: repository, tag: tag})
.then((data) => resolve(new RepositoryShortTag(tag, data.config.digest, data.digest, data)))
.catch((err) => reject(err))
});
}
async function* shortTagsWithProgress(registry, repository, tagsList) {
const id = registry.Id;
yield* genericAsyncGenerator($q, tagsList, _shortTagFromGenerator, [id, repository]);
}
/**
* END SHORT TAG
*/
/**
* RETAG
*/
async function* retagWithProgress(registry, repository, modifiedTags, modifiedDigests, impactedTags){
yield* _deleteManifestsWithProgress(registry, repository, modifiedDigests);
const newTags = _.map(impactedTags, (item) => {
const tagFromTable = _.find(modifiedTags, { 'Name': item.Name });
const name = tagFromTable && tagFromTable.Name !== tagFromTable.NewName ? tagFromTable.NewName : item.Name;
return { tag: name, manifest: item.ManifestV2 };
return new RepositoryAddTagPayload(name, item.ManifestV2);
});
yield* addTagsWithProgress(id, repository, newTags, modifiedDigests.length);
yield* _addTagsWithProgress(registry, repository, newTags, modifiedDigests.length);
}
service.deleteTagsWithProgress = async function* (id, repository, modifiedDigests, impactedTags) {
yield* deleteManifestsWithProgress(id, repository, modifiedDigests);
/**
* END RETAG
*/
const newTags = _.map(impactedTags, (item) => {return {tag: item.Name, manifest: item.ManifestV2}})
/**
* DELETE TAGS
*/
yield* addTagsWithProgress(id, repository, newTags, modifiedDigests.length);
async function* deleteTagsWithProgress(registry, repository, modifiedDigests, impactedTags) {
yield* _deleteManifestsWithProgress(registry, repository, modifiedDigests);
const newTags = _.map(impactedTags, (item) => new RepositoryAddTagPayload(item.Name, item.ManifestV2));
yield* _addTagsWithProgress(registry, repository, newTags, modifiedDigests.length);
}
/**
* END DELETE TAGS
*/
/**
* SERVICE FUNCTIONS DECLARATION
*/
service.ping = ping;
service.repositories = repositories;
service.getRepositoriesDetails = getRepositoriesDetails;
service.tags = tags;
service.tag = tag;
service.getTagsDetails = getTagsDetails;
service.shortTagsWithProgress = shortTagsWithProgress;
service.addTag = addTag;
service.deleteManifest = deleteManifest;
service.deleteTagsWithProgress = deleteTagsWithProgress;
service.retagWithProgress = retagWithProgress;
return service;
}
]);