Compare commits
7 Commits
test/node_
...
fix/EE-170
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e73339eba7 | ||
|
|
1f4a7b32e3 | ||
|
|
a781021072 | ||
|
|
9492e30dc2 | ||
|
|
d2cbdf935a | ||
|
|
05efac44f6 | ||
|
|
555c9f238f |
@@ -38,7 +38,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210909083948-8be0d98451a1
|
||||
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a
|
||||
github.com/portainer/libhelm v0.0.0-20210906035629-b5635edd5d97
|
||||
github.com/portainer/libhelm v0.0.0-20210913052337-365741c1c320
|
||||
github.com/portainer/libhttp v0.0.0-20190806161843-ba068f58be33
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
|
||||
@@ -206,14 +206,12 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210909011155-9ff375eac059 h1:98v0k3x3ZXa09NaHP/HmSA83rcN8cuE/zTKo6xvNmoM=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210909011155-9ff375eac059/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210909083948-8be0d98451a1 h1:0ZGSu3Atz7RHMDsoITHV676igRfsb51mlgELGo37ELU=
|
||||
github.com/portainer/docker-compose-wrapper v0.0.0-20210909083948-8be0d98451a1/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c=
|
||||
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a h1:qY8TbocN75n5PDl16o0uVr5MevtM5IhdwSelXEd4nFM=
|
||||
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a/go.mod h1:n54EEIq+MM0NNtqLeCby8ljL+l275VpolXO0ibHegLE=
|
||||
github.com/portainer/libhelm v0.0.0-20210906035629-b5635edd5d97 h1:ZcRVgWHTac8V7WU9TUBr73H3e5ajVFYTPjPl9TWULDA=
|
||||
github.com/portainer/libhelm v0.0.0-20210906035629-b5635edd5d97/go.mod h1:YvYAk7krKTzB+rFwDr0jQ3sQu2BtiXK1AR0sZH7nhJA=
|
||||
github.com/portainer/libhelm v0.0.0-20210913052337-365741c1c320 h1:wkmxoHYjWc7OB6JfSlt83mAVpnAo4/6TdL60PO4DlXk=
|
||||
github.com/portainer/libhelm v0.0.0-20210913052337-365741c1c320/go.mod h1:YvYAk7krKTzB+rFwDr0jQ3sQu2BtiXK1AR0sZH7nhJA=
|
||||
github.com/portainer/libhttp v0.0.0-20190806161843-ba068f58be33 h1:H8HR2dHdBf8HANSkUyVw4o8+4tegGcd+zyKZ3e599II=
|
||||
github.com/portainer/libhttp v0.0.0-20190806161843-ba068f58be33/go.mod h1:Y2TfgviWI4rT2qaOTHr+hq6MdKIE5YjgQAu7qwptTV0=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/portainer/libhelm"
|
||||
"github.com/portainer/libhelm/options"
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
)
|
||||
@@ -40,7 +39,7 @@ func (handler *Handler) helmRepoSearch(w http.ResponseWriter, r *http.Request) *
|
||||
Repo: repo,
|
||||
}
|
||||
|
||||
result, err := libhelm.SearchRepo(searchOpts)
|
||||
result, err := handler.helmPackageManager.SearchRepo(searchOpts)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
|
||||
@@ -9,13 +9,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/portainer/libhelm/binary/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
helper "github.com/portainer/portainer/api/internal/testhelpers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_helmRepoSearch(t *testing.T) {
|
||||
helper.IntegrationTest(t)
|
||||
is := assert.New(t)
|
||||
|
||||
helmPackageManager := test.NewMockHelmBinaryPackageManager("")
|
||||
|
||||
@@ -104,7 +104,7 @@ angular.module('portainer.docker').controller('ImageController', [
|
||||
try {
|
||||
const registryModel = await RegistryService.retrievePorRegistryModelFromRepository(repository, endpoint.Id);
|
||||
await ImageService.pullImage(registryModel);
|
||||
Notifications.success('Image successfully pushed', repository);
|
||||
Notifications.success('Image successfully pulled', repository);
|
||||
} catch (err) {
|
||||
Notifications.error('Failure', err, 'Unable to push image to repository');
|
||||
} finally {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<span class="small text-muted">
|
||||
<p>
|
||||
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
This is a first version for Helm charts, for more information see this <a href="#">blog post.</a>
|
||||
This is a first version for Helm charts, for more information see this <a href="https://www.portainer.io/blog/portainer-now-with-helm-support" target="_blank">blog post</a>.
|
||||
</p>
|
||||
</span>
|
||||
</information-panel>
|
||||
|
||||
@@ -56,6 +56,7 @@ class KubernetesApplicationConverter {
|
||||
const containers = data.spec.template ? _.without(_.concat(data.spec.template.spec.containers, data.spec.template.spec.initContainers), undefined) : data.spec.containers;
|
||||
res.Id = data.metadata.uid;
|
||||
res.Name = data.metadata.name;
|
||||
res.Metadata = data.metadata;
|
||||
|
||||
if (data.metadata.labels) {
|
||||
const { labels } = data.metadata;
|
||||
|
||||
@@ -449,8 +449,8 @@ class KubernetesApplicationHelper {
|
||||
// filter out all the applications that are managed by helm
|
||||
// to identify the helm managed applications, we need to check if the applications pod labels include
|
||||
// `app.kubernetes.io/instance` and `app.kubernetes.io/managed-by` = `helm`
|
||||
const helmManagedApps = applications.filter((app) =>
|
||||
app.Pods.flatMap((pod) => pod.Labels).some((label) => label && label[PodKubernetesInstanceLabel] && label[PodManagedByLabel] === 'Helm')
|
||||
const helmManagedApps = applications.filter(
|
||||
(app) => app.Metadata.labels && app.Metadata.labels[PodKubernetesInstanceLabel] && app.Metadata.labels[PodManagedByLabel] === 'Helm'
|
||||
);
|
||||
|
||||
// groups the helm managed applications by helm release name
|
||||
@@ -467,15 +467,12 @@ class KubernetesApplicationHelper {
|
||||
const namespacedHelmReleases = {};
|
||||
helmManagedApps.forEach((app) => {
|
||||
const namespace = app.ResourcePool;
|
||||
const labels = app.Pods.filter((p) => p.Labels).map((p) => p.Labels[PodKubernetesInstanceLabel]);
|
||||
const uniqueLabels = [...new Set(labels)];
|
||||
uniqueLabels.forEach((instanceStr) => {
|
||||
if (namespacedHelmReleases[namespace]) {
|
||||
namespacedHelmReleases[namespace][instanceStr] = [...(namespacedHelmReleases[namespace][instanceStr] || []), app];
|
||||
} else {
|
||||
namespacedHelmReleases[namespace] = { [instanceStr]: [app] };
|
||||
}
|
||||
});
|
||||
const instanceLabel = app.Metadata.labels[PodKubernetesInstanceLabel];
|
||||
if (namespacedHelmReleases[namespace]) {
|
||||
namespacedHelmReleases[namespace][instanceLabel] = [...(namespacedHelmReleases[namespace][instanceLabel] || []), app];
|
||||
} else {
|
||||
namespacedHelmReleases[namespace] = { [instanceLabel]: [app] };
|
||||
}
|
||||
});
|
||||
|
||||
// `helmAppsEntriesList` object structure:
|
||||
@@ -511,5 +508,25 @@ class KubernetesApplicationHelper {
|
||||
|
||||
return helmAppsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get nested applications -
|
||||
* @param {KubernetesApplication[]} applications Application list
|
||||
* @returns {Object} { helmApplications: [app1, app2, ...], nonHelmApplications: [app3, app4, ...] }
|
||||
*/
|
||||
static getNestedApplications(applications) {
|
||||
const helmApplications = KubernetesApplicationHelper.getHelmApplications(applications);
|
||||
|
||||
// filter out helm managed applications
|
||||
const helmAppNames = [...new Set(helmApplications.map((hma) => hma.Name))]; // distinct helm app names
|
||||
const nonHelmApplications = applications.filter((app) => {
|
||||
if (app.Metadata.labels) {
|
||||
return !helmAppNames.includes(app.Metadata.labels[PodKubernetesInstanceLabel]);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return { helmApplications, nonHelmApplications };
|
||||
}
|
||||
}
|
||||
export default KubernetesApplicationHelper;
|
||||
|
||||
@@ -16,6 +16,7 @@ const _KubernetesApplication = Object.freeze({
|
||||
CreationDate: 0,
|
||||
Pods: [],
|
||||
Containers: [],
|
||||
Metadata: {},
|
||||
Limits: {},
|
||||
ServiceType: '',
|
||||
ServiceId: '',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash-es';
|
||||
import KubernetesStackHelper from 'Kubernetes/helpers/stackHelper';
|
||||
import KubernetesApplicationHelper, { PodKubernetesInstanceLabel } from 'Kubernetes/helpers/application';
|
||||
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
|
||||
import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper';
|
||||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
|
||||
@@ -109,18 +109,9 @@ class KubernetesApplicationsController {
|
||||
try {
|
||||
const [applications, configurations] = await Promise.all([this.KubernetesApplicationService.get(), this.KubernetesConfigurationService.get()]);
|
||||
const configuredApplications = KubernetesConfigurationHelper.getApplicationConfigurations(applications, configurations);
|
||||
const helmApplications = KubernetesApplicationHelper.getHelmApplications(configuredApplications);
|
||||
const { helmApplications, nonHelmApplications } = KubernetesApplicationHelper.getNestedApplications(configuredApplications);
|
||||
|
||||
// filter out multi-chart helm managed applications
|
||||
const helmAppNames = [...new Set(helmApplications.map((hma) => hma.Name))]; // distinct helm app names
|
||||
const nonHelmApps = configuredApplications.filter(
|
||||
(app) =>
|
||||
!app.Pods.flatMap((pod) => pod.Labels) // flatten pod labels
|
||||
.filter((label) => label) // filter out empty labels
|
||||
.some((label) => helmAppNames.includes(label[PodKubernetesInstanceLabel])) // check if label key is in helmAppNames
|
||||
);
|
||||
|
||||
this.state.applications = [...nonHelmApps, ...helmApplications];
|
||||
this.state.applications = [...helmApplications, ...nonHelmApplications];
|
||||
this.state.stacks = KubernetesStackHelper.stacksFromApplications(applications);
|
||||
this.state.ports = KubernetesApplicationHelper.portMappingsFromApplications(applications);
|
||||
} catch (err) {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
>
|
||||
<template-item-actions>
|
||||
<div ng-if="$ctrl.isEditAllowed(template)" style="display: flex;">
|
||||
<a ui-state="$ctrl.editPath" ui-state-params="({id: template.Id})" ng-click="$event.stopPropagation();" class="btn btn-primary btn-xs" style="margin-right: 10px;">
|
||||
<a ui-state="$ctrl.editPath" ui-state-params="{id: template.Id}" ng-click="$event.stopPropagation();" class="btn btn-primary btn-xs" style="margin-right: 10px;">
|
||||
Edit
|
||||
</a>
|
||||
<button class="btn btn-danger btn-xs" ng-click="$ctrl.onDeleteClick(template.Id); $event.stopPropagation();">Delete</button>
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
templates="$ctrl.templates"
|
||||
table-key="customTemplates"
|
||||
create-path="docker.templates.custom.new"
|
||||
edit-path="docker.templates.custom.edit"
|
||||
is-edit-allowed="$ctrl.isEditAllowed"
|
||||
on-select-click="($ctrl.selectTemplate)"
|
||||
on-delete-click="($ctrl.confirmDelete)"
|
||||
|
||||
@@ -34,7 +34,7 @@ angular
|
||||
StackFile: null,
|
||||
RepositoryURL: '',
|
||||
RepositoryReferenceName: '',
|
||||
RepositoryAuthentication: true,
|
||||
RepositoryAuthentication: false,
|
||||
RepositoryUsername: '',
|
||||
RepositoryPassword: '',
|
||||
Env: [],
|
||||
|
||||
@@ -70,7 +70,7 @@ module.exports = {
|
||||
compress: true,
|
||||
port: 8999,
|
||||
proxy: {
|
||||
'/api': 'https://localhost:9443',
|
||||
'/api': 'http://localhost:9000',
|
||||
},
|
||||
open: true,
|
||||
writeToDisk: true,
|
||||
|
||||
Reference in New Issue
Block a user