mirror of https://github.com/portainer/portainer
618 lines
34 KiB
HTML
618 lines
34 KiB
HTML
<kubernetes-view-header title="Application details" state="kubernetes.applications.application" view-ready="ctrl.state.viewReady">
|
|
<a ui-sref="kubernetes.resourcePools">Namespaces</a> >
|
|
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: ctrl.application.ResourcePool })">{{ ctrl.application.ResourcePool }}</a> >
|
|
<a ui-sref="kubernetes.applications">Applications</a> > {{ ctrl.application.Name }}
|
|
</kubernetes-view-header>
|
|
|
|
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>
|
|
|
|
<div ng-if="ctrl.state.viewReady">
|
|
<div class="row">
|
|
<div class="col-sm-12">
|
|
<rd-widget>
|
|
<rd-widget-body classes="no-padding">
|
|
<uib-tabset active="ctrl.state.activeTab" justified="true" type="pills">
|
|
<uib-tab index="0" classes="btn-sm" select="ctrl.selectTab(0)">
|
|
<uib-tab-heading> <i class="fa fa-laptop-code space-right" aria-hidden="true"></i> Application </uib-tab-heading>
|
|
<div style="padding: 20px;">
|
|
<table class="table">
|
|
<tbody>
|
|
<tr>
|
|
<td>Name</td>
|
|
<td data-cy="k8sAppDetail-appName">
|
|
{{ ctrl.application.Name }}
|
|
<span class="label label-primary image-tag label-margins" ng-if="!ctrl.isSystemNamespace() && ctrl.isExternalApplication()">external</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Stack</td>
|
|
<td data-cy="k8sAppDetail-stackName">{{ ctrl.application.StackName || '-' }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Namespace</td>
|
|
<td data-cy="k8sAppDetail-resourcePoolName">
|
|
<a ui-sref="kubernetes.resourcePools.resourcePool({ id: ctrl.application.ResourcePool })">{{ ctrl.application.ResourcePool }}</a>
|
|
<span style="margin-left: 5px;" class="label label-info image-tag" ng-if="ctrl.isSystemNamespace()">system</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Application Type</td>
|
|
<td data-cy="k8sAppDetail-appType">
|
|
{{ ctrl.application.ApplicationType | kubernetesApplicationTypeText }}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Status</td>
|
|
<td ng-if="ctrl.application.ApplicationType !== ctrl.KubernetesApplicationTypes.POD">
|
|
<span ng-if="ctrl.application.DeploymentType === ctrl.KubernetesApplicationDeploymentTypes.REPLICATED" data-cy="k8sAppDetail-deployType">Replicated</span>
|
|
<span ng-if="ctrl.application.DeploymentType === ctrl.KubernetesApplicationDeploymentTypes.GLOBAL" data-cy="k8sAppDetail-appType">Global</span>
|
|
<code data-cy="k8sAppDetail-runningPods">{{ ctrl.application.RunningPodsCount }}</code> /
|
|
<code data-cy="k8sAppDetail-totalPods">{{ ctrl.application.TotalPodsCount }}</code>
|
|
</td>
|
|
<td ng-if="ctrl.application.ApplicationType === ctrl.KubernetesApplicationTypes.POD">
|
|
{{ ctrl.application.Pods[0].Status }}
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="ctrl.application.Requests.Cpu || ctrl.application.Requests.Memory">
|
|
<td>
|
|
<div>Resource reservations</div>
|
|
<div ng-if="ctrl.application.ApplicationType !== ctrl.KubernetesApplicationTypes.POD" class="text-muted small"> per instance </div>
|
|
</td>
|
|
<td>
|
|
<div ng-if="ctrl.application.Requests.Cpu" data-cy="k8sAppDetail-cpuReservation"
|
|
>CPU {{ ctrl.application.Requests.Cpu | kubernetesApplicationCPUValue }}</div
|
|
>
|
|
<div ng-if="ctrl.application.Requests.Memory" data-cy="k8sAppDetail-memoryReservation">Memory {{ ctrl.application.Requests.Memory | humansize }}</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Creation</td>
|
|
<td>
|
|
<span ng-if="ctrl.application.ApplicationOwner" style="margin-right: 5px;"> <i class="fas fa-user"></i> {{ ctrl.application.ApplicationOwner }} </span>
|
|
<span> <i class="fas fa-clock"></i> {{ ctrl.application.CreationDate | getisodate }}</span>
|
|
<span ng-if="ctrl.application.ApplicationOwner">
|
|
<i class="fa fa-file-code space-left space-right" aria-hidden="true"></i> Deployed from {{ ctrl.state.appType }}</span
|
|
>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2">
|
|
<form class="form-horizontal" name="kubernetesApplicationNoteForm">
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<i class="fa fa-edit" aria-hidden="true"></i> Note
|
|
<button class="btn btn-xs btn-primary" ng-click="ctrl.state.expandedNote = !ctrl.state.expandedNote;" data-cy="k8sAppDetail-expandNoteButton"
|
|
>{{ ctrl.state.expandedNote ? 'Collapse' : 'Expand' }}
|
|
<i class="fas {{ ctrl.state.expandedNote ? 'fa-angle-up' : 'fa-angle-down' }}" aria-hidden="true"></i
|
|
></button>
|
|
</div>
|
|
</div>
|
|
<div class="form-group" ng-if="ctrl.state.expandedNote">
|
|
<div class="col-sm-12">
|
|
<textarea
|
|
class="form-control"
|
|
name="application_note"
|
|
id="application_note"
|
|
ng-model="ctrl.formValues.Note"
|
|
rows="5"
|
|
placeholder="Enter a note about this application..."
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="form-group" ng-if="ctrl.state.expandedNote">
|
|
<div class="col-sm-12">
|
|
<button
|
|
class="btn btn-primary btn-sm"
|
|
style="margin-left: 0px;"
|
|
type="button"
|
|
ng-click="ctrl.updateApplication()"
|
|
ng-disabled="ctrl.formValues.Note === ctrl.application.Note"
|
|
data-cy="k8sAppDetail-saveNoteButton"
|
|
>{{ ctrl.application.Note ? 'Update' : 'Save' }} note</button
|
|
>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<!-- <tr>
|
|
<td colspan="2">
|
|
<form class="form-horizontal" name="KubernetesApplicationRollbackForm">
|
|
<div class="form-group">
|
|
<label for="resource-pool-selector" class="col-sm-2 col-lg-1 control-label text-left">Version</label>
|
|
<div class="col-sm-2">
|
|
<select class="form-control" id="resource-pool-selector" ng-model="ctrl.formValues.SelectedRevision"
|
|
ng-options="revision as revision.revision for revision in ctrl.application.Revisions"></select>
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<button class="btn btn-primary btn-sm" style="margin-left: 0px;" type="button" ng-click="ctrl.rollbackApplication()"
|
|
ng-disabled="ctrl.formValues.SelectedRevision.revision === ctrl.application.CurrentRevision.revision">Rollback</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</td>
|
|
</tr> -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</uib-tab>
|
|
|
|
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
|
|
<uib-tab-heading>
|
|
<i class="fas fa-compress-arrows-alt space-right" aria-hidden="true"></i> Placement
|
|
<div ng-if="ctrl.state.placementWarning">
|
|
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
warning
|
|
</div>
|
|
</uib-tab-heading>
|
|
<div class="small text-muted" style="padding: 20px;">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
The placement component helps you understand whether or not this application can be deployed on a specific node.
|
|
</div>
|
|
<kubernetes-application-placements-datatable
|
|
title-text="Placement constraints/preferences"
|
|
title-icon="fa-compress-arrows-alt"
|
|
dataset="ctrl.placements"
|
|
table-key="kubernetes.application.placements"
|
|
order-by="Name"
|
|
reverse-order="false"
|
|
loading="ctrl.state.dataLoading"
|
|
refresh-callback="ctrl.getApplication"
|
|
></kubernetes-application-placements-datatable>
|
|
</uib-tab>
|
|
|
|
<uib-tab index="2" classes="btn-sm" select="ctrl.selectTab(2)">
|
|
<uib-tab-heading>
|
|
<i class="fa fa-history space-right" aria-hidden="true"></i> Events
|
|
<div ng-if="ctrl.hasEventWarnings()">
|
|
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
{{ ctrl.state.eventWarningCount }} warning(s)
|
|
</div>
|
|
</uib-tab-heading>
|
|
<kubernetes-events-datatable
|
|
title-text="Events"
|
|
title-icon="fa-history"
|
|
dataset="ctrl.events"
|
|
table-key="kubernetes.application.events"
|
|
order-by="Date"
|
|
reverse-order="true"
|
|
loading="ctrl.state.eventsLoading"
|
|
refresh-callback="ctrl.getEvents"
|
|
></kubernetes-events-datatable>
|
|
</uib-tab>
|
|
|
|
<uib-tab index="3" ng-if="ctrl.application.Yaml" select="ctrl.showEditor()" classes="btn-sm">
|
|
<uib-tab-heading> <i class="fa fa-code space-right" aria-hidden="true"></i> YAML </uib-tab-heading>
|
|
<div style="padding-right: 25px;" ng-if="ctrl.state.showEditorTab">
|
|
<kubernetes-yaml-inspector key="application-yaml" data="ctrl.application.Yaml"></kubernetes-yaml-inspector>
|
|
</div>
|
|
</uib-tab>
|
|
</uib-tabset>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-sm-12">
|
|
<rd-widget>
|
|
<rd-widget-body>
|
|
<div ng-if="!ctrl.isSystemNamespace()" style="margin-bottom: 15px;">
|
|
<button
|
|
ng-if="!ctrl.isExternalApplication()"
|
|
type="button"
|
|
class="btn btn-sm btn-primary"
|
|
ui-sref="kubernetes.applications.application.edit"
|
|
style="margin-left: 0;"
|
|
data-cy="k8sAppDetail-editAppButton"
|
|
>
|
|
<i class="fa fa-file-code space-right" aria-hidden="true"></i>Edit this application
|
|
</button>
|
|
<button
|
|
ng-if="ctrl.application.ApplicationType !== ctrl.KubernetesApplicationTypes.POD"
|
|
type="button"
|
|
class="btn btn-sm btn-primary"
|
|
style="margin-left: 0;"
|
|
ng-click="ctrl.redeployApplication()"
|
|
data-cy="k8sAppDetail-redeployButton"
|
|
>
|
|
<i class="fa fa-redo space-right" aria-hidden="true"></i>Redeploy
|
|
</button>
|
|
<button
|
|
ng-if="!ctrl.isExternalApplication()"
|
|
type="button"
|
|
class="btn btn-sm btn-primary"
|
|
style="margin-left: 0;"
|
|
ng-click="ctrl.rollbackApplication()"
|
|
ng-disabled="ctrl.application.Revisions.length < 2 || ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"
|
|
data-cy="k8sAppDetail-rollbackButton"
|
|
>
|
|
<i class="fas fa-history space-right" aria-hidden="true"></i>Rollback to previous configuration
|
|
</button>
|
|
<a
|
|
ng-if="ctrl.isStack() && ctrl.stackFileContent"
|
|
class="btn btn-sm btn-primary space-left"
|
|
ui-sref="kubernetes.templates.custom.new({fileContent: ctrl.stackFileContent})"
|
|
>
|
|
<i class="fas fa-plus space-right" aria-hidden="true"></i>Create template from application
|
|
</a>
|
|
</div>
|
|
|
|
<!-- ACCESSING APPLICATION -->
|
|
<div class="text-muted" style="margin-bottom: 15px;">
|
|
<i class="fa fa-external-link-alt" aria-hidden="true" style="margin-right: 2px;"></i> Accessing the application
|
|
</div>
|
|
|
|
<div class="small text-muted" ng-if="ctrl.application.PublishedPorts.length === 0" style="margin-bottom: 15px;">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application is not exposing any port.
|
|
</div>
|
|
|
|
<div ng-if="ctrl.application.PublishedPorts.length > 0">
|
|
<!-- LB notice -->
|
|
<div ng-if="ctrl.application.ServiceType === ctrl.KubernetesServiceTypes.LOAD_BALANCER">
|
|
<div class="small text-muted">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application is exposed through an external load balancer. Use the links below to access the different ports exposed.
|
|
</div>
|
|
<div style="margin-top: 10px;" class="small text-muted">
|
|
<span ng-if="!ctrl.application.LoadBalancerIPAddress">
|
|
<p> Load balancer status: <i class="fa fa-cog fa-spin" style="margin-left: 2px;"></i> pending </p>
|
|
<p>
|
|
<u>what does the "pending" status means?</u>
|
|
<portainer-tooltip
|
|
position="bottom"
|
|
message="A pending status means that Portainer delegated the request to the provider responsible for creating the external load balancer. If it stays in pending state for long, this means that this capability might not be supported or you might have an issue with your cluster provider. Contact your cluster administrator for more information."
|
|
>
|
|
</portainer-tooltip>
|
|
</p>
|
|
</span>
|
|
<span ng-if="ctrl.application.LoadBalancerIPAddress">
|
|
<p> Load balancer status: <i class="fa fa-check green-icon" style="margin-left: 2px;"></i> available </p>
|
|
<p>
|
|
Load balancer IP address: {{ ctrl.application.LoadBalancerIPAddress }}
|
|
<span class="btn btn-primary btn-xs" ng-click="ctrl.copyLoadBalancerIP()" style="margin-left: 5px;">
|
|
<i class="fa fa-copy space-right" aria-hidden="true"></i>Copy
|
|
</span>
|
|
<span id="copyNotificationLB" style="margin-left: 7px; display: none; color: #23ae89;" class="small">
|
|
<i class="fa fa-check" aria-hidden="true"></i> copied
|
|
</span>
|
|
</p>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- cluster notice -->
|
|
<div ng-if="ctrl.application.ServiceType === ctrl.KubernetesServiceTypes.NODE_PORT">
|
|
<div class="small text-muted">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application is exposed globally on all nodes of your cluster. It can be reached using the IP address of any node in your cluster using the port configuration
|
|
below.
|
|
</div>
|
|
</div>
|
|
|
|
<!-- internal notice -->
|
|
<div ng-if="ctrl.application.ServiceType === ctrl.KubernetesServiceTypes.CLUSTER_IP && !ctrl.state.useIngress">
|
|
<div class="small text-muted">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application is only available for internal usage inside the cluster via the application name <code>{{ ctrl.application.ServiceName }}</code>
|
|
<span class="btn btn-primary btn-xs" ng-click="ctrl.copyApplicationName()"><i class="fa fa-copy space-right" aria-hidden="true"></i>Copy</span>
|
|
<span id="copyNotificationApplicationName" style="margin-left: 7px; display: none; color: #23ae89;" class="small"
|
|
><i class="fa fa-check" aria-hidden="true"></i> copied</span
|
|
>
|
|
</div>
|
|
<div class="small text-muted" style="margin-top: 2px;">
|
|
<p>Refer to the below port configuration to access the application.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ingress notice -->
|
|
<div ng-if="ctrl.application.ServiceType === ctrl.KubernetesServiceTypes.CLUSTER_IP && ctrl.state.useIngress">
|
|
<div class="small text-muted">
|
|
<p>
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application is available for internal usage inside the cluster via the application name <code>{{ ctrl.application.ServiceName }}</code>
|
|
<span class="btn btn-primary btn-xs" ng-click="ctrl.copyApplicationName()"><i class="fa fa-copy space-right" aria-hidden="true"></i>Copy</span>
|
|
<span id="copyNotificationApplicationName" style="margin-left: 7px; display: none; color: #23ae89;" class="small"
|
|
><i class="fa fa-check" aria-hidden="true"></i> copied</span
|
|
>
|
|
</p>
|
|
<p>It can also be accessed via specific HTTP route(s).</p>
|
|
</div>
|
|
<div class="small text-muted" style="margin-top: 2px;">
|
|
<p>Refer to the below port configuration to access the application.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- table -->
|
|
<div style="margin-top: 15px;">
|
|
<table class="table">
|
|
<tbody>
|
|
<tr class="text-muted">
|
|
<td style="width: 25%;">Container port</td>
|
|
<td style="width: 25%;">{{ ctrl.application.ServiceType | kubernetesApplicationPortsTableHeaderText }} port</td>
|
|
<td style="width: 50%;">HTTP route</td>
|
|
</tr>
|
|
<tr ng-repeat-start="port in ctrl.application.PublishedPorts">
|
|
<td ng-if="!ctrl.portHasIngressRules(port)" data-cy="k8sAppDetail-containerPort">{{ port.TargetPort }}/{{ port.Protocol }}</td>
|
|
<td ng-if="!ctrl.portHasIngressRules(port)">
|
|
<span ng-if="ctrl.application.ServiceType === ctrl.KubernetesServiceTypes.NODE_PORT" data-cy="k8sAppDetail-nodePort">
|
|
{{ port.NodePort }}
|
|
</span>
|
|
<span ng-if="ctrl.application.ServiceType !== ctrl.KubernetesServiceTypes.NODE_PORT" data-cy="k8sAppDetail-containerPort">
|
|
{{ port.Port }}
|
|
</span>
|
|
<a
|
|
ng-if="ctrl.application.LoadBalancerIPAddress"
|
|
ng-href="http://{{ ctrl.application.LoadBalancerIPAddress }}:{{ port.Port }}"
|
|
target="_blank"
|
|
style="margin-left: 5px;"
|
|
data-cy="k8sAppDetail-accessLink"
|
|
>
|
|
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access
|
|
</a>
|
|
</td>
|
|
<td ng-if="!ctrl.portHasIngressRules(port)">-</td>
|
|
</tr>
|
|
<tr ng-repeat-end ng-repeat="rule in port.IngressRules">
|
|
<td data-cy="k8sAppDetail-httpRoute">{{ port.TargetPort }}/{{ port.Protocol }}</td>
|
|
<td>
|
|
<span ng-if="ctrl.application.ServiceType === ctrl.KubernetesServiceTypes.NODE_PORT" data-cy="k8sAppDetail-nodePort">
|
|
{{ port.NodePort }}
|
|
</span>
|
|
<span ng-if="ctrl.application.ServiceType !== ctrl.KubernetesServiceTypes.NODE_PORT" data-cy="k8sAppDetail-port">
|
|
{{ port.Port }}
|
|
</span>
|
|
<a
|
|
ng-if="ctrl.application.LoadBalancerIPAddress"
|
|
ng-href="http://{{ ctrl.application.LoadBalancerIPAddress }}:{{ port.Port }}"
|
|
target="_blank"
|
|
style="margin-left: 5px;"
|
|
>
|
|
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<span
|
|
ng-if="!ctrl.ruleCanBeDisplayed(rule)"
|
|
class="text-muted"
|
|
tooltip-append-to-body="true"
|
|
tooltip-placement="bottom"
|
|
tooltip-class="portainer-tooltip"
|
|
uib-tooltip="Ingress controller IP address not available yet"
|
|
style="cursor: pointer;"
|
|
>pending
|
|
</span>
|
|
<span ng-if="ctrl.ruleCanBeDisplayed(rule)">
|
|
<a ng-href="{{ ctrl.buildIngressRuleURL(rule) }}" target="_blank" data-cy="k8sAppDetail-httpRouteLink">
|
|
{{ ctrl.buildIngressRuleURL(rule) | stripprotocol }}
|
|
</a>
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<!-- !ACCESSING APPLICATION -->
|
|
<!-- AUTO SCALING -->
|
|
<div class="text-muted" style="margin-bottom: 15px;"> <i class="fa fa-expand-arrows-alt" aria-hidden="true" style="margin-right: 2px;"></i> Auto-scaling</div>
|
|
|
|
<div class="small text-muted" ng-if="!ctrl.application.AutoScaler" style="margin-bottom: 15px;">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application does not have an autoscaling policy defined.
|
|
</div>
|
|
|
|
<div ng-if="ctrl.application.AutoScaler">
|
|
<div style="margin-top: 15px; width: 50%;">
|
|
<table class="table">
|
|
<tbody>
|
|
<tr class="text-muted">
|
|
<td style="width: 33%;">Minimum instances</td>
|
|
<td style="width: 33%;">Maximum instances</td>
|
|
<td style="width: 33%;">
|
|
Target CPU usage
|
|
<portainer-tooltip position="bottom" message="The autoscaler will ensure enough instances are running to maintain an average CPU usage across all instances.">
|
|
</portainer-tooltip>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td data-cy="k8sAppDetail-minReplicas">{{ ctrl.application.AutoScaler.MinReplicas }}</td>
|
|
<td data-cy="k8sAppDetail-maxReplicas">{{ ctrl.application.AutoScaler.MaxReplicas }}</td>
|
|
<td data-cy="k8sAppDetail-targetCPU">{{ ctrl.application.AutoScaler.TargetCPUUtilization }}%</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<!-- !AUTO SCALING -->
|
|
|
|
<!-- 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.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>
|
|
|
|
<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 | orderBy: 'name'">
|
|
<td data-cy="k8sAppDetail-containerName">
|
|
{{ 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 data-cy="k8sAppDetail-envVarName">{{ envvar.name }}</td>
|
|
<td>
|
|
<span ng-if="envvar.value" data-cy="k8sAppDetail-envVarValue">{{ envvar.value }}</span>
|
|
<span ng-if="envvar.valueFrom.configMapKeyRef" data-cy="k8sAppDetail-envVarValue"
|
|
><i class="fa fa-key" aria-hidden="true"></i> {{ envvar.valueFrom.configMapKeyRef.key }}</span
|
|
>
|
|
<span ng-if="envvar.valueFrom.secretKeyRef" data-cy="k8sAppDetail-envVarValue"
|
|
><i class="fa fa-key" aria-hidden="true"></i> {{ envvar.valueFrom.secretKeyRef.key }}</span
|
|
>
|
|
<span ng-if="envvar.valueFrom.fieldRef" data-cy="k8sAppDetail-envVarValue"
|
|
><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" data-cy="k8sAppDetail-configName"
|
|
><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" data-cy="k8sAppDetail-configName"
|
|
><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>
|
|
|
|
<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 -->
|
|
<div class="text-muted" style="margin-bottom: 15px; margin-top: 25px;">
|
|
<i class="fa fa-database" aria-hidden="true" style="margin-right: 2px;"></i> Data persistence
|
|
</div>
|
|
|
|
<div class="small text-muted" ng-if="!ctrl.hasPersistedFolders()">
|
|
<i class="fa fa-info-circle blue-icon" aria-hidden="true" style="margin-right: 2px;"></i>
|
|
This application has no persisted folders.
|
|
</div>
|
|
|
|
<div ng-if="ctrl.hasPersistedFolders()">
|
|
<div class="small text-muted" style="margin-bottom: 15px;">
|
|
Data access policy: <i class="fa {{ ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyIcon }}" aria-hidden="true"></i>
|
|
{{ ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyText }}
|
|
<portainer-tooltip position="right" message="{{ ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyTooltip }}"> </portainer-tooltip>
|
|
</div>
|
|
|
|
<table class="table" ng-if="ctrl.application.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED">
|
|
<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 data-cy="k8sAppDetail-volMountPath">
|
|
{{ volume.MountPath }}
|
|
</td>
|
|
<td ng-if="volume.PersistentVolumeClaimName">
|
|
<a ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName, namespace: ctrl.application.ResourcePool })" data-cy="k8sAppDetail-volClaimName"
|
|
><i class="fa fa-database" aria-hidden="true"></i> {{ volume.PersistentVolumeClaimName }}</a
|
|
>
|
|
</td>
|
|
<td ng-if="volume.HostPath"> {{ volume.HostPath }} on host filesystem </td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<table class="table" ng-if="ctrl.application.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED">
|
|
<thead>
|
|
<tr class="text-muted">
|
|
<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="container in ctrl.allContainers track by $index" style="border-top: none;">
|
|
<tr ng-repeat="volume in container.PersistedFolders 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>{{ container.PodName }}</td>
|
|
<td>
|
|
{{ volume.MountPath }}
|
|
</td>
|
|
<td ng-if="volume.PersistentVolumeClaimName">
|
|
<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>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<!-- !DATA PERSISTENCE -->
|
|
</div>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-sm-12">
|
|
<kubernetes-containers-datatable
|
|
title-text="Application containers"
|
|
title-icon="fa-server"
|
|
dataset="ctrl.allContainers"
|
|
table-key="kubernetes.application.containers"
|
|
is-pod="ctrl.application.ApplicationType === ctrl.KubernetesApplicationTypes.POD"
|
|
order-by="{{ ctrl.application.ApplicationType === ctrl.KubernetesApplicationTypes.POD ? 'Name' : 'PodName' }}"
|
|
use-server-metrics="ctrl.state.useServerMetrics"
|
|
>
|
|
</kubernetes-containers-datatable>
|
|
</div>
|
|
</div>
|
|
</div>
|