mirror of
https://github.com/portainer/portainer.git
synced 2025-08-09 07:45:22 +02:00
fix(registry) EE-1861 improve registry selection (#5925)
* fix(registry) EE-1861 improve registry selection (#5899) * fix(registry) EE-1861 hide anonymous dockerhub registry if user has an authenticated one * fix(registry) EE-1861 pick up a best match dockerhub registry * fix(registry) EE-1861 set the anonymous registry as default if it is shown * fix(registry) EE-1861 refactor how to match registry Co-authored-by: Simon Meng <simon.meng@portainer.io> * fix(registry) EE-1861 fail to select registry with same name * fix(registry) EE-1861 show registry modal when pull and push image * fix(registry) EE-1861 cleanup code Co-authored-by: Simon Meng <simon.meng@portainer.io>
This commit is contained in:
parent
623079442f
commit
d18c8d0e88
6 changed files with 141 additions and 23 deletions
|
@ -22,6 +22,8 @@ angular.module('portainer.app').factory('RegistryService', [
|
|||
createRegistry,
|
||||
createGitlabRegistries,
|
||||
retrievePorRegistryModelFromRepository,
|
||||
retrievePorRegistryModelFromRepositoryWithRegistries,
|
||||
loadRegistriesForDropdown,
|
||||
};
|
||||
|
||||
function registries() {
|
||||
|
@ -107,17 +109,45 @@ angular.module('portainer.app').factory('RegistryService', [
|
|||
return url;
|
||||
}
|
||||
|
||||
// findBestMatchRegistry finds out the best match registry for repository
|
||||
// matching precedence:
|
||||
// 1. registryId matched
|
||||
// 2. both domain name and username matched (for dockerhub only)
|
||||
// 3. only URL matched
|
||||
// 4. pick up the first dockerhub registry
|
||||
function findBestMatchRegistry(repository, registries, registryId) {
|
||||
let match2, match3, match4;
|
||||
|
||||
for (const registry of registries) {
|
||||
if (registry.Id == registryId) {
|
||||
return registry;
|
||||
}
|
||||
|
||||
if (registry.Type === RegistryTypes.DOCKERHUB) {
|
||||
// try to match repository examples:
|
||||
// <USERNAME>/nginx:latest
|
||||
// docker.io/<USERNAME>/nginx:latest
|
||||
if (repository.startsWith(registry.Username + '/') || repository.startsWith(getURL(registry) + '/' + registry.Username + '/')) {
|
||||
match2 = registry;
|
||||
}
|
||||
|
||||
// try to match repository examples:
|
||||
// portainer/portainer-ee:latest
|
||||
// <NON-USERNAME>/portainer-ee:latest
|
||||
match4 = match4 || registry;
|
||||
}
|
||||
|
||||
if (_.includes(repository, getURL(registry))) {
|
||||
match3 = registry;
|
||||
}
|
||||
}
|
||||
|
||||
return match2 || match3 || match4;
|
||||
}
|
||||
|
||||
function retrievePorRegistryModelFromRepositoryWithRegistries(repository, registries, registryId) {
|
||||
const model = new PorImageRegistryModel();
|
||||
const registry = registries.find((reg) => {
|
||||
if (registryId) {
|
||||
return reg.Id === registryId;
|
||||
}
|
||||
if (reg.Type === RegistryTypes.DOCKERHUB) {
|
||||
return _.includes(repository, reg.Username);
|
||||
}
|
||||
return _.includes(repository, getURL(reg));
|
||||
});
|
||||
const registry = findBestMatchRegistry(repository, registries, registryId);
|
||||
if (registry) {
|
||||
const url = getURL(registry);
|
||||
let lastIndex = repository.lastIndexOf(url);
|
||||
|
@ -148,5 +178,22 @@ angular.module('portainer.app').factory('RegistryService', [
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadRegistriesForDropdown(endpointId, namespace) {
|
||||
return $async(async () => {
|
||||
try {
|
||||
const registries = await EndpointService.registries(endpointId, namespace);
|
||||
|
||||
// hide default(anonymous) dockerhub registry if user has an authenticated one
|
||||
if (!registries.some((registry) => registry.Type === RegistryTypes.DOCKERHUB)) {
|
||||
registries.push(new DockerHubViewModel());
|
||||
}
|
||||
|
||||
return registries;
|
||||
} catch (err) {
|
||||
throw { msg: 'Unable to retrieve the registries', err: err };
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -308,6 +308,17 @@ angular.module('portainer.app').factory('ModalService', [
|
|||
);
|
||||
};
|
||||
|
||||
service.selectRegistry = function (options) {
|
||||
var box = bootbox.prompt({
|
||||
title: 'Which registry do you want to use?',
|
||||
inputType: 'select',
|
||||
value: options.defaultValue,
|
||||
inputOptions: options.options,
|
||||
callback: options.callback,
|
||||
});
|
||||
applyBoxCSS(box);
|
||||
};
|
||||
|
||||
return service;
|
||||
},
|
||||
]);
|
||||
|
|
39
app/portainer/services/registryModalService.js
Normal file
39
app/portainer/services/registryModalService.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
angular.module('portainer.app').factory('RegistryModalService', ModalServiceFactory);
|
||||
|
||||
function ModalServiceFactory($q, ModalService, RegistryService) {
|
||||
const service = {};
|
||||
|
||||
function registries2Options(registries) {
|
||||
return registries.map((r) => ({
|
||||
text: r.Name,
|
||||
value: String(r.Id),
|
||||
}));
|
||||
}
|
||||
|
||||
service.registryModal = async function (repository, registries) {
|
||||
const deferred = $q.defer();
|
||||
|
||||
const options = registries2Options(registries);
|
||||
const registryModel = RegistryService.retrievePorRegistryModelFromRepositoryWithRegistries(repository, registries);
|
||||
const defaultValue = String(_.get(registryModel, 'Registry.Id', '0'));
|
||||
|
||||
ModalService.selectRegistry({
|
||||
options,
|
||||
defaultValue,
|
||||
callback: (registryId) => {
|
||||
if (registryId) {
|
||||
const registryModel = RegistryService.retrievePorRegistryModelFromRepositoryWithRegistries(repository, registries, registryId);
|
||||
deferred.resolve(registryModel);
|
||||
} else {
|
||||
deferred.resolve(null);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue