From f67e866e7eca4a872af38b9127b9928104ed1758 Mon Sep 17 00:00:00 2001 From: xAt0mZ Date: Mon, 14 Oct 2019 15:46:33 +0200 Subject: [PATCH] feat(registry): inspect repository images (#3121) * feat(registry): inspect repository images * fix(registry): tag inspect column sorting --- app/extensions/registry-management/_module.js | 12 ++ .../registriesRepositoryTagsDatatable.html | 3 +- .../models/registryImageDetails.js | 14 ++ .../models/registryImageLayer.js | 8 + .../tag/registryRepositoryTag.html | 175 ++++++++++++++++++ .../tag/registryRepositoryTagController.js | 57 ++++++ 6 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 app/extensions/registry-management/models/registryImageDetails.js create mode 100644 app/extensions/registry-management/models/registryImageLayer.js create mode 100644 app/extensions/registry-management/views/repositories/tag/registryRepositoryTag.html create mode 100644 app/extensions/registry-management/views/repositories/tag/registryRepositoryTagController.js diff --git a/app/extensions/registry-management/_module.js b/app/extensions/registry-management/_module.js index 9fdde0c5d..777ebcc55 100644 --- a/app/extensions/registry-management/_module.js +++ b/app/extensions/registry-management/_module.js @@ -34,8 +34,20 @@ angular.module('portainer.extensions.registrymanagement', []) } } }; + var registryRepositoryTag = { + name: 'portainer.registries.registry.repository.tag', + url: '/:tag', + views: { + 'content@': { + templateUrl: './views/repositories/tag/registryRepositoryTag.html', + controller: 'RegistryRepositoryTagController', + controllerAs: 'ctrl' + } + } + }; $stateRegistryProvider.register(registryConfiguration); $stateRegistryProvider.register(registryRepositories); $stateRegistryProvider.register(registryRepositoryTags); + $stateRegistryProvider.register(registryRepositoryTag); }]); diff --git a/app/extensions/registry-management/components/registries-repository-tags-datatable/registriesRepositoryTagsDatatable.html b/app/extensions/registry-management/components/registries-repository-tags-datatable/registriesRepositoryTagsDatatable.html index 6e524d77e..15448a9e4 100644 --- a/app/extensions/registry-management/components/registries-repository-tags-datatable/registriesRepositoryTagsDatatable.html +++ b/app/extensions/registry-management/components/registries-repository-tags-datatable/registriesRepositoryTagsDatatable.html @@ -44,7 +44,8 @@ - {{ item.Name }} + {{ item.Name }} {{ item.Os }}/{{ item.Architecture }} {{ item.ImageId | trimshasum }} diff --git a/app/extensions/registry-management/models/registryImageDetails.js b/app/extensions/registry-management/models/registryImageDetails.js new file mode 100644 index 000000000..9a80adedc --- /dev/null +++ b/app/extensions/registry-management/models/registryImageDetails.js @@ -0,0 +1,14 @@ +export function RegistryImageDetailsViewModel(data) { + this.Id = data.id; + this.Parent = data.parent; + this.Created = data.created; + this.DockerVersion = data.docker_version; + this.Os = data.os; + this.Architecture = data.architecture; + this.Author = data.author; + this.Command = data.config.Cmd; + this.Entrypoint = data.container_config.Entrypoint ? data.container_config.Entrypoint : ''; + this.ExposedPorts = data.container_config.ExposedPorts ? Object.keys(data.container_config.ExposedPorts) : []; + this.Volumes = data.container_config.Volumes ? Object.keys(data.container_config.Volumes) : []; + this.Env = data.container_config.Env ? data.container_config.Env : []; +} diff --git a/app/extensions/registry-management/models/registryImageLayer.js b/app/extensions/registry-management/models/registryImageLayer.js new file mode 100644 index 000000000..f8990a514 --- /dev/null +++ b/app/extensions/registry-management/models/registryImageLayer.js @@ -0,0 +1,8 @@ +import _ from 'lodash-es'; + +export function RegistryImageLayerViewModel(order, data) { + this.Order = order; + this.Id = data.id; + this.Created = data.created; + this.CreatedBy = _.join(data.container_config.Cmd, ' '); +} \ No newline at end of file diff --git a/app/extensions/registry-management/views/repositories/tag/registryRepositoryTag.html b/app/extensions/registry-management/views/repositories/tag/registryRepositoryTag.html new file mode 100644 index 000000000..69316f24e --- /dev/null +++ b/app/extensions/registry-management/views/repositories/tag/registryRepositoryTag.html @@ -0,0 +1,175 @@ + + + + + + + + Registries > + {{ ctrl.registry.Name }} > + {{ ctrl.context.repository }} > + {{ ctrl.context.tag }} + + + +
+
+ + + +
+
+
+
+
+ {{ tag }} +
+
+
+
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ID + {{ ctrl.details.Id }} +
Parent{{ ctrl.details.Parent }}
Created{{ ctrl.details.Created|getisodate }}
BuildDocker {{ ctrl.details.DockerVersion }} on {{ ctrl.details.Os}}, {{ ctrl.details.Architecture }}
Author{{ ctrl.details.Author }}
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
CMD{{ ctrl.details.Command|command }}
ENTRYPOINT{{ ctrl.details.Entrypoint|command }}
EXPOSE + + {{ port }} + +
VOLUME + + {{ volume }} + +
ENV + + + + + +
{{ var|key: '=' }}{{ var|value: '=' }}
+
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + +
+ + Order + + + + + + Layer + + + +
+ {{ layer.Order }} + +
+ + + {{ layer.CreatedBy | truncate:130 }} + + + + + + +
+
+ + {{ layer.CreatedBy }} + +
+
+
+
+
+
\ No newline at end of file diff --git a/app/extensions/registry-management/views/repositories/tag/registryRepositoryTagController.js b/app/extensions/registry-management/views/repositories/tag/registryRepositoryTagController.js new file mode 100644 index 000000000..4f34b89f1 --- /dev/null +++ b/app/extensions/registry-management/views/repositories/tag/registryRepositoryTagController.js @@ -0,0 +1,57 @@ +import _ from 'lodash-es'; +import angular from 'angular'; +import { RegistryImageLayerViewModel } from 'Extensions/registry-management/models/registryImageLayer'; +import { RegistryImageDetailsViewModel } from 'Extensions/registry-management/models/registryImageDetails'; + +class RegistryRepositoryTagController { + + /* @ngInject */ + constructor($transition$, $async, Notifications, RegistryService, RegistryV2Service, imagelayercommandFilter) { + this.$transition$ = $transition$; + this.$async = $async; + this.Notifications = Notifications; + this.RegistryService = RegistryService; + this.RegistryV2Service = RegistryV2Service; + this.imagelayercommandFilter = imagelayercommandFilter; + + this.context = {}; + this.onInit = this.onInit.bind(this); + } + + toggleLayerCommand(layerId) { + $('#layer-command-expander'+layerId+' span').toggleClass('glyphicon-plus-sign glyphicon-minus-sign'); + $('#layer-command-'+layerId+'-short').toggle(); + $('#layer-command-'+layerId+'-full').toggle(); + } + + order(sortType) { + this.Sort.Reverse = (this.Sort.Type === sortType) ? !this.Sort.Reverse : false; + this.Sort.Type = sortType; + } + + async onInit() { + this.context.registryId = this.$transition$.params().id; + this.context.repository = this.$transition$.params().repository; + this.context.tag = this.$transition$.params().tag; + this.Sort = { + Type: 'Order', + Reverse: false + } + try { + this.registry = await this.RegistryService.registry(this.context.registryId); + this.tag = await this.RegistryV2Service.tag(this.context.registryId, this.context.repository, this.context.tag); + const length = this.tag.History.length; + this.history = _.map(this.tag.History, (layer, idx) => new RegistryImageLayerViewModel(length - idx, layer)); + _.forEach(this.history, (item) => item.CreatedBy = this.imagelayercommandFilter(item.CreatedBy)) + this.details = new RegistryImageDetailsViewModel(this.tag.History[0]); + } catch (error) { + this.Notifications.error('Failure', error, 'Unable to retrieve tag') + } + } + + $onInit() { + return this.$async(this.onInit); + } +} +export default RegistryRepositoryTagController; +angular.module('portainer.extensions.registrymanagement').controller('RegistryRepositoryTagController', RegistryRepositoryTagController);