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

feat(k8s/application): Support multi-container pods applications (#4208)

* feat(application): Support multi-container pods applications

* feat(application): Support multi-container pods applications

* fix(application): use only one pod in app details and fix logs and console links

* fix(application): show all containers in containers datatable

* fix(application): fix order by pod name

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* fix(application): fix persisted folders in application details

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
This commit is contained in:
Maxime Bajeux 2020-08-14 01:27:10 +02:00 committed by GitHub
parent fe4a80c7bd
commit 00389a7da9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 358 additions and 141 deletions

View file

@ -3,7 +3,7 @@
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: ctrl.application.ResourcePool })">{{ ctrl.application.ResourcePool }}</a> &gt;
<a ui-sref="kubernetes.applications">Applications</a> &gt;
<a ui-sref="kubernetes.applications.application({ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool })">{{ ctrl.application.Name }}</a> &gt; Pods &gt;
{{ ctrl.podName }} &gt; Console
{{ ctrl.podName }} &gt; Containers &gt; {{ ctrl.containerName }} &gt; Console
</kubernetes-view-header>
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>

View file

@ -54,7 +54,7 @@ class KubernetesApplicationConsoleController {
endpointId: this.EndpointProvider.endpointID(),
namespace: this.application.ResourcePool,
podName: this.podName,
containerName: this.application.Pods[0].Containers[0].name,
containerName: this.containerName,
command: this.state.command,
};
@ -92,8 +92,10 @@ class KubernetesApplicationConsoleController {
const podName = this.$transition$.params().pod;
const applicationName = this.$transition$.params().name;
const namespace = this.$transition$.params().namespace;
const containerName = this.$transition$.params().container;
this.podName = podName;
this.containerName = containerName;
try {
this.application = await this.KubernetesApplicationService.get(namespace, applicationName);

View file

@ -54,7 +54,15 @@
<div class="form-group">
<label for="container_image" class="col-sm-1 control-label text-left">Image</label>
<div class="col-sm-11">
<input type="text" class="form-control" name="container_image" ng-model="ctrl.formValues.Image" placeholder="nginx:latest" required />
<input
type="text"
class="form-control"
name="container_image"
ng-model="ctrl.formValues.Image"
placeholder="nginx:latest"
required
ng-disabled="ctrl.formValues.Containers.length > 1"
/>
</div>
</div>
<div class="form-group" ng-show="kubernetesApplicationCreationForm.container_image.$invalid">
@ -128,7 +136,7 @@
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Environment variables</label>
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="ctrl.addEnvironmentVariable()">
<span ng-if="ctrl.formValues.Containers.length <= 1" class="label label-default interactive" style="margin-left: 10px;" ng-click="ctrl.addEnvironmentVariable()">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add environment variable
</span>
</div>
@ -146,6 +154,7 @@
ng-change="ctrl.onChangeEnvironmentName()"
ng-pattern="/^[a-zA-Z]([-_a-zA-Z0-9]*[a-zA-Z0-9])?$/"
placeholder="foo"
ng-disabled="ctrl.formValues.Containers.length > 1"
required
/>
</div>
@ -171,10 +180,17 @@
<div class="input-group col-sm-4 input-group-sm" ng-class="{ striked: envVar.NeedsDeletion }">
<span class="input-group-addon">value</span>
<input type="text" name="environment_variable_value_{{ $index }}" class="form-control" ng-model="envVar.Value" placeholder="bar" />
<input
type="text"
name="environment_variable_value_{{ $index }}"
class="form-control"
ng-model="envVar.Value"
placeholder="bar"
ng-disabled="ctrl.formValues.Containers.length > 1"
/>
</div>
<div class="input-group col-sm-2 input-group-sm">
<div class="input-group col-sm-2 input-group-sm" ng-if="ctrl.formValues.Containers.length <= 1">
<button ng-if="!envVar.NeedsDeletion" class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removeEnvironmentVariable($index)">
<i class="fa fa-trash-alt" aria-hidden="true"></i>
</button>
@ -194,7 +210,7 @@
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Configurations</label>
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="ctrl.addConfiguration()">
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="ctrl.addConfiguration()" ng-if="ctrl.formValues.Containers.length <= 1">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add configuration
</span>
</div>
@ -214,6 +230,7 @@
ng-model="config.SelectedConfiguration"
ng-options="c as c.Name for c in ctrl.configurations"
ng-change="ctrl.resetConfiguration(index)"
ng-disabled="ctrl.formValues.Containers.length > 1"
></select>
</div>
<div class="col-sm-6" style="margin-top: 2px;">
@ -222,14 +239,20 @@
type="button"
ng-if="!config.Overriden"
ng-click="ctrl.overrideConfiguration(index)"
ng-disabled="!config.SelectedConfiguration"
ng-disabled="!config.SelectedConfiguration || ctrl.formValues.Containers.length > 1"
>
<i class="fa fa-list" aria-hidden="true"></i> Override
</button>
<button class="btn btn-sm btn-primary" type="button" ng-if="config.Overriden" ng-click="ctrl.resetConfiguration(index)">
<button
class="btn btn-sm btn-primary"
type="button"
ng-if="config.Overriden"
ng-click="ctrl.resetConfiguration(index)"
ng-disabled="ctrl.formValues.Containers.length > 1"
>
<i class="fa fa-undo" aria-hidden="true"></i> Auto
</button>
<button class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removeConfiguration(index)"> <i class="fa fa-trash-alt" aria-hidden="true"></i> Remove </button>
<button class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removeConfiguration(index)" ng-if="ctrl.formValues.Containers.length <= 1"> <i class="fa fa-trash-alt" aria-hidden="true"></i> Remove </button>
</div>
<!-- no-override -->
<div class="col-sm-12" style="margin-top: 10px;" ng-if="config.SelectedConfiguration && !config.Overriden">
@ -266,6 +289,7 @@
ng-model="overridenKey.Path"
placeholder="/etc/myapp/conf.d"
name="overriden_key_path_{{ index }}_{{ keyIndex }}"
ng-disabled="ctrl.formValues.Containers.length > 1"
required
ng-change="ctrl.onChangeConfigurationPath()"
/>
@ -316,7 +340,12 @@
<div class="form-group" ng-if="ctrl.storageClassAvailable()">
<div class="col-sm-12" style="margin-top: 5px;">
<label class="control-label text-left">Persisted folders</label>
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="ctrl.addPersistedFolder()" ng-if="!ctrl.isEditAndStatefulSet()">
<span
class="label label-default interactive"
style="margin-left: 10px;"
ng-click="ctrl.addPersistedFolder()"
ng-if="!ctrl.isEditAndStatefulSet() && ctrl.formValues.Containers.length <= 1"
>
<i class="fa fa-plus-circle" aria-hidden="true"></i> add persisted folder
</span>
</div>
@ -331,7 +360,7 @@
name="persisted_folder_path_{{ $index }}"
ng-model="persistedFolder.ContainerPath"
ng-change="ctrl.onChangePersistedFolderPath()"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index)"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
placeholder="/data"
required
/>
@ -341,7 +370,11 @@
<span
class="btn-group btn-group-sm"
ng-class="{ striked: persistedFolder.NeedsDeletion }"
ng-if="!ctrl.isEditAndExistingPersistedFolder($index) && ctrl.application.ApplicationType !== ctrl.ApplicationTypes.STATEFULSET"
ng-if="
!ctrl.isEditAndExistingPersistedFolder($index) &&
ctrl.application.ApplicationType !== ctrl.ApplicationTypes.STATEFULSET &&
ctrl.formValues.Containers.length <= 1
"
>
<label
class="btn btn-primary"
@ -372,14 +405,14 @@
placeholder="20"
ng-min="0"
required
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index)"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
/>
<span class="input-group-addon" style="padding: 0;">
<select
ng-model="persistedFolder.SizeUnit"
ng-style="{ width: '100%', height: '100%', cursor: ctrl.isEditAndExistingPersistedFolder($index) ? 'not-allowed' : 'auto' }"
ng-options="unit for unit in ctrl.state.availableSizeUnits"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index)"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
></select>
</span>
</div>
@ -396,7 +429,7 @@
class="form-control"
ng-model="persistedFolder.StorageClass"
ng-options="storageClass as storageClass.Name for storageClass in ctrl.storageClasses"
ng-disabled="ctrl.state.isEdit"
ng-disabled="ctrl.state.isEdit || ctrl.formValues.Containers.length > 1"
></select>
<input ng-if="!ctrl.hasMultipleStorageClassesAvailable()" type="text" class="form-control" disabled ng-model="persistedFolder.StorageClass.Name" />
</div>
@ -409,7 +442,7 @@
ng-model="ctrl.formValues.PersistedFolders[$index].ExistingVolume"
ng-options="vol as vol.PersistentVolumeClaim.Name for vol in ctrl.availableVolumes"
ng-change="ctrl.onChangeExistingVolumeSelection()"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index)"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
required
>
<option selected disabled hidden value="">Select a volume</option>
@ -417,7 +450,7 @@
</div>
<div class="input-group col-sm-1 input-group-sm">
<div style="vertical-align: top;" ng-if="!ctrl.isEditAndStatefulSet()" ng-if="!ctrl.state.useExistingVolume[$index]">
<div style="vertical-align: top;" ng-if="!ctrl.isEditAndStatefulSet() && !ctrl.state.useExistingVolume[$index] && ctrl.formValues.Containers.length <= 1">
<button ng-if="!persistedFolder.NeedsDeletion" class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removePersistedFolder($index)">
<i class="fa fa-trash-alt" aria-hidden="true"></i>
</button>
@ -607,7 +640,10 @@
</div>
<!-- memory-limit-input -->
<div class="form-group" ng-if="!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded())">
<div
class="form-group"
ng-if="(!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded())) && ctrl.formValues.Containers.length <= 1"
>
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px;">
Memory
<portainer-tooltip
@ -648,7 +684,10 @@
</div>
<!-- !memory-limit-input -->
<!-- cpu-limit-input -->
<div class="form-group" ng-if="!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded())">
<div
class="form-group"
ng-if="(!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded())) && ctrl.formValues.Containers.length <= 1"
>
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px;">
CPU
<portainer-tooltip

View file

@ -366,77 +366,92 @@
<!-- CONFIGURATIONS -->
<div class="text-muted" style="margin-bottom: 15px; margin-top: 25px;"> <i class="fa fa-file-code" aria-hidden="true" style="margin-right: 2px;"></i> Configuration </div>
<div class="small text-muted" ng-if="!ctrl.application.Env && !ctrl.hasVolumeConfiguration()" style="margin-bottom: 15px;">
<div class="small text-muted" ng-if="!ctrl.application.Env.length > 0 && !ctrl.hasVolumeConfiguration()" style="margin-bottom: 15px;">
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
This application is not using any environment variable or configuration.
</div>
<div ng-if="ctrl.application.Env.length > 0">
<div>
<table class="table">
<tbody>
<tr class="text-muted">
<td style="width: 33%;">Environment variable</td>
<td style="width: 33%;">Value</td>
<td style="width: 33%;">Configuration</td>
</tr>
<tr ng-repeat="envvar in ctrl.application.Env track by $index">
<td>{{ envvar.name }}</td>
<td>
<span ng-if="envvar.value">{{ envvar.value }}</span>
<span ng-if="envvar.valueFrom.configMapKeyRef"><i class="fa fa-key" aria-hidden="true"></i> {{ envvar.valueFrom.configMapKeyRef.key }}</span>
<span ng-if="envvar.valueFrom.secretKeyRef"><i class="fa fa-key" aria-hidden="true"></i> {{ envvar.valueFrom.secretKeyRef.key }}</span>
<span ng-if="envvar.valueFrom.fieldRef"
><i class="fa fa-asterisk" aria-hidden="true"></i> {{ envvar.valueFrom.fieldRef.fieldPath }} (<a
href="https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#capabilities-of-the-downward-api"
target="_blank"
>downward API</a
>)</span
>
<span ng-if="!envvar.value && !envvar.valueFrom.secretKeyRef && !envvar.valueFrom.configMapKeyRef && !envvar.valueFrom.fieldRef">-</span>
</td>
<td>
<span ng-if="envvar.value || envvar.valueFrom.fieldRef || (!envvar.valueFrom.secretKeyRef && !envvar.valueFrom.configMapKeyRef)">-</span>
<span ng-if="envvar.valueFrom.configMapKeyRef"
><a ui-sref="kubernetes.configurations.configuration({ name: envvar.valueFrom.configMapKeyRef.name, namespace: ctrl.application.ResourcePool })"
><i class="fa fa-file-code" aria-hidden="true"></i> {{ envvar.valueFrom.configMapKeyRef.name }}</a
></span
>
<span ng-if="envvar.valueFrom.secretKeyRef"
><a ui-sref="kubernetes.configurations.configuration({ name: envvar.valueFrom.secretKeyRef.name, namespace: ctrl.application.ResourcePool })"
><i class="fa fa-file-code" aria-hidden="true"></i> {{ envvar.valueFrom.secretKeyRef.name }}</a
></span
>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<table class="table" ng-if="ctrl.application.Env.length > 0">
<tr class="text-muted">
<td style="width: 25%;">Container</td>
<td style="width: 25%;">Environment variable</td>
<td style="width: 25%;">Value</td>
<td style="width: 25%;">Configuration</td>
</tr>
<tbody ng-repeat="container in ctrl.application.Containers" style="border-top: 0;">
<tr ng-repeat="envvar in container.Env track by $index">
<td>
{{ container.Name }}
<span ng-if="container.Type === ctrl.KubernetesPodContainerTypes.INIT"
><i class="fa fa-asterisk" aria-hidden="true"></i> {{ envvar.valueFrom.fieldRef.fieldPath }} (<a
href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/"
target="_blank"
>init container</a
>)</span
>
</td>
<td>{{ envvar.name }}</td>
<td>
<span ng-if="envvar.value">{{ envvar.value }}</span>
<span ng-if="envvar.valueFrom.configMapKeyRef"><i class="fa fa-key" aria-hidden="true"></i> {{ envvar.valueFrom.configMapKeyRef.key }}</span>
<span ng-if="envvar.valueFrom.secretKeyRef"><i class="fa fa-key" aria-hidden="true"></i> {{ envvar.valueFrom.secretKeyRef.key }}</span>
<span ng-if="envvar.valueFrom.fieldRef"
><i class="fa fa-asterisk" aria-hidden="true"></i> {{ envvar.valueFrom.fieldRef.fieldPath }} (<a
href="https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#capabilities-of-the-downward-api"
target="_blank"
>downward API</a
>)</span
>
<span ng-if="!envvar.value && !envvar.valueFrom.secretKeyRef && !envvar.valueFrom.configMapKeyRef && !envvar.valueFrom.fieldRef">-</span>
</td>
<td>
<span ng-if="envvar.value || envvar.valueFrom.fieldRef || (!envvar.valueFrom.secretKeyRef && !envvar.valueFrom.configMapKeyRef)">-</span>
<span ng-if="envvar.valueFrom.configMapKeyRef"
><a ui-sref="kubernetes.configurations.configuration({ name: envvar.valueFrom.configMapKeyRef.name, namespace: ctrl.application.ResourcePool })"
><i class="fa fa-file-code" aria-hidden="true"></i> {{ envvar.valueFrom.configMapKeyRef.name }}</a
></span
>
<span ng-if="envvar.valueFrom.secretKeyRef"
><a ui-sref="kubernetes.configurations.configuration({ name: envvar.valueFrom.secretKeyRef.name, namespace: ctrl.application.ResourcePool })"
><i class="fa fa-file-code" aria-hidden="true"></i> {{ envvar.valueFrom.secretKeyRef.name }}</a
></span
>
</td>
</tr>
</tbody>
</table>
<div ng-if="ctrl.hasVolumeConfiguration()">
<table class="table">
<tbody>
<tr class="text-muted">
<td style="width: 33%;">Configuration path</td>
<td style="width: 33%;">Value</td>
<td style="width: 33%;">Configuration</td>
</tr>
<tr ng-repeat="volume in ctrl.application.ConfigurationVolumes track by $index" style="border-top: 0;">
<td>
{{ volume.fileMountPath }}
</td>
<td> <i class="fa fa-key" ng-if="volume.configurationKey" aria-hidden="true"></i> {{ volume.configurationKey ? volume.configurationKey : '-' }} </td>
<td>
<a ui-sref="kubernetes.configurations.configuration({ name: volume.configurationName, namespace: ctrl.application.ResourcePool })"
><i class="fa fa-file-code" aria-hidden="true"></i> {{ volume.configurationName }}</a
>
</td>
</tr>
</tbody>
</table>
</div>
<table class="table" ng-if="ctrl.hasVolumeConfiguration()">
<tr class="text-muted">
<td style="width: 25%;">Container</td>
<td style="width: 25%;">Configuration path</td>
<td style="width: 25%;">Value</td>
<td style="width: 25%;">Configuration</td>
</tr>
<tbody ng-repeat="container in ctrl.application.Containers" style="border-top: 0;">
<tr ng-repeat="volume in container.ConfigurationVolumes track by $index" style="border-top: 0;">
<td>
{{ container.Name }}
<span ng-if="container.Type === ctrl.KubernetesPodContainerTypes.INIT"
><i class="fa fa-asterisk" aria-hidden="true"></i> {{ envvar.valueFrom.fieldRef.fieldPath }} (<a
href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/"
target="_blank"
>init container</a
>)</span
>
</td>
<td>
{{ volume.fileMountPath }}
</td>
<td> <i class="fa fa-key" ng-if="volume.configurationKey" aria-hidden="true"></i> {{ volume.configurationKey ? volume.configurationKey : '-' }} </td>
<td>
<a ui-sref="kubernetes.configurations.configuration({ name: volume.configurationName, namespace: ctrl.application.ResourcePool })"
><i class="fa fa-file-code" aria-hidden="true"></i> {{ volume.configurationName }}</a
>
</td>
</tr>
</tbody>
</table>
<!-- !CONFIGURATIONS -->
<!-- DATA PERSISTENCE -->
@ -457,12 +472,12 @@
</div>
<table class="table" ng-if="ctrl.application.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED">
<tbody>
<tr class="text-muted">
<td style="width: 50%;">Persisted folder</td>
<td style="width: 50%;">Persistence</td>
</tr>
<tr ng-repeat="volume in ctrl.application.PersistedFolders track by $index">
<tr class="text-muted">
<td style="width: 33%;">Persisted folder</td>
<td style="width: 66%;">Persistence</td>
</tr>
<tbody ng-repeat="container in ctrl.application.Containers" style="border-top: 0;">
<tr ng-repeat="volume in container.PersistedFolders track by $index">
<td>
{{ volume.MountPath }}
</td>
@ -479,22 +494,31 @@
<table class="table" ng-if="ctrl.application.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED">
<thead>
<tr class="text-muted">
<td style="width: 33%;">Pod</td>
<td style="width: 33%;">Persisted folder</td>
<td style="width: 33%;">Persistence</td>
<td style="width: 25%;">Container name</td>
<td style="width: 25%;">Pod name</td>
<td style="width: 25%;">Persisted folder</td>
<td style="width: 25%;">Persistence</td>
</tr>
</thead>
<tbody ng-repeat="pod in ctrl.application.Pods track by $index" style="border-top: none;">
<tr ng-repeat="volume in ctrl.application.PersistedFolders track by $index">
<tbody ng-repeat="container in ctrl.allContainers track by $index" style="border-top: none;">
<tr ng-repeat="volume in container.PersistedFolders track by $index">
<td>
{{ pod.Name }}
{{ container.Name }}
<span ng-if="container.Type === ctrl.KubernetesPodContainerTypes.INIT"
><i class="fa fa-asterisk" aria-hidden="true"></i> {{ envvar.valueFrom.fieldRef.fieldPath }} (<a
href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/"
target="_blank"
>init container</a
>)</span
>
</td>
<td>{{ container.PodName }}</td>
<td>
{{ volume.MountPath }}
</td>
<td ng-if="volume.PersistentVolumeClaimName">
<a ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName + '-' + pod.Name, namespace: ctrl.application.ResourcePool })">
<i class="fa fa-database" aria-hidden="true"></i> {{ volume.PersistentVolumeClaimName + '-' + pod.Name }}</a
<a ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName + '-' + container.PodName, namespace: ctrl.application.ResourcePool })">
<i class="fa fa-database" aria-hidden="true"></i> {{ volume.PersistentVolumeClaimName + '-' + container.PodName }}</a
>
</td>
<td ng-if="volume.HostPath"> {{ volume.HostPath }} on host filesystem </td>
@ -510,8 +534,14 @@
<div class="row">
<div class="col-sm-12">
<kubernetes-pods-datatable title-text="Application pods" title-icon="fa-server" dataset="ctrl.application.Pods" table-key="kubernetes.application.pods" order-by="Name">
</kubernetes-pods-datatable>
<kubernetes-containers-datatable
title-text="Application containers"
title-icon="fa-server"
dataset="ctrl.allContainers"
table-key="kubernetes.application.containers"
order-by="Name"
>
</kubernetes-containers-datatable>
</div>
</div>
</div>

View file

@ -6,6 +6,7 @@ import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper';
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
import { KubernetesServiceTypes } from 'Kubernetes/models/service/models';
import { KubernetesPodNodeAffinityNodeSelectorRequirementOperators } from 'Kubernetes/pod/models';
import { KubernetesPodContainerTypes } from 'Kubernetes/pod/models/index';
function computeTolerations(nodes, application) {
const pod = application.Pods[0];
@ -120,6 +121,7 @@ class KubernetesApplicationController {
this.ApplicationDataAccessPolicies = KubernetesApplicationDataAccessPolicies;
this.KubernetesServiceTypes = KubernetesServiceTypes;
this.KubernetesPodContainerTypes = KubernetesPodContainerTypes;
this.onInit = this.onInit.bind(this);
this.getApplication = this.getApplication.bind(this);
@ -284,6 +286,7 @@ class KubernetesApplicationController {
this.KubernetesNodeService.get(),
]);
this.application = application;
this.allContainers = KubernetesApplicationHelper.associateAllContainersAndApplication(application);
this.formValues.Note = this.application.Note;
if (this.application.Note) {
this.state.expandedNote = true;

View file

@ -3,7 +3,7 @@
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: ctrl.application.ResourcePool })">{{ ctrl.application.ResourcePool }}</a> &gt;
<a ui-sref="kubernetes.applications">Applications</a> &gt;
<a ui-sref="kubernetes.applications.application({ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool })">{{ ctrl.application.Name }}</a> &gt; Pods &gt;
{{ ctrl.podName }} &gt; Logs
{{ ctrl.podName }} &gt; Containers &gt; {{ ctrl.containerName }} &gt; Logs
</kubernetes-view-header>
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>

View file

@ -45,7 +45,7 @@ class KubernetesApplicationLogsController {
async getApplicationLogsAsync() {
try {
this.applicationLogs = await this.KubernetesPodService.logs(this.application.ResourcePool, this.podName);
this.applicationLogs = await this.KubernetesPodService.logs(this.application.ResourcePool, this.podName, this.containerName);
} catch (err) {
this.stopRepeater();
this.Notifications.error('Failure', err, 'Unable to retrieve application logs');
@ -63,14 +63,16 @@ class KubernetesApplicationLogsController {
const podName = this.$transition$.params().pod;
const applicationName = this.$transition$.params().name;
const namespace = this.$transition$.params().namespace;
const containerName = this.$transition$.params().container;
this.applicationLogs = [];
this.podName = podName;
this.containerName = containerName;
try {
const [application, applicationLogs] = await Promise.all([
this.KubernetesApplicationService.get(namespace, applicationName),
this.KubernetesPodService.logs(namespace, podName),
this.KubernetesPodService.logs(namespace, podName, containerName),
]);
this.application = application;

View file

@ -43,12 +43,12 @@ class KubernetesStackLogsController {
this.repeater = this.$interval(this.getStackLogsAsync, this.state.refreshRate);
}
async generateLogsPromise(pod) {
async generateLogsPromise(pod, container) {
const res = {
Pod: pod,
Logs: [],
};
res.Logs = await this.KubernetesPodService.logs(pod.Namespace, pod.Name);
res.Logs = await this.KubernetesPodService.logs(pod.Namespace, pod.Name, container.Name);
return res;
}
@ -58,7 +58,7 @@ class KubernetesStackLogsController {
Pods: [],
};
const promises = _.map(app.Pods, this.generateLogsPromise);
const promises = _.flatMap(_.map(app.Pods, (pod) => _.map(pod.Containers, (container) => this.generateLogsPromise(pod, container))));
const result = await $allSettled(promises);
res.Pods = result.fulfilled;
return res;