mirror of https://github.com/portainer/portainer
273 lines
15 KiB
HTML
273 lines
15 KiB
HTML
<page-header ng-if="ctrl.state.viewReady" title="'Node details'" breadcrumbs="[{ label:'Cluster', link:'kubernetes.cluster' }, ctrl.node.Name]" reload="true"></page-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 class="flex-center gap-1"> <pr-icon icon="'hard-drive'" size="'sm'" feather="true"></pr-icon> Node </uib-tab-heading>
|
|
|
|
<form class="form-horizontal" name="kubernetesNodeUpdateForm" style="padding: 20px" autocomplete="off">
|
|
<table class="table">
|
|
<tbody ng-if="ctrl.node">
|
|
<tr>
|
|
<td>Hostname</td>
|
|
<td>
|
|
{{ ctrl.node.Name }}
|
|
<span class="label label-primary image-tag" style="margin-left: 5px" ng-if="ctrl.node.Api">api</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="ctrl.node.Api">
|
|
<td> Kubernetes API </td>
|
|
<td>{{ ctrl.node.IPAddress }}:{{ ctrl.node.Port }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Role</td>
|
|
<td>{{ ctrl.node.Role }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Kubelet version</td>
|
|
<td>{{ ctrl.node.Version }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Creation date</td>
|
|
<td>{{ ctrl.node.CreationDate | getisodate }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Status</td>
|
|
<td>
|
|
<span class="label label-{{ ctrl.node.Status | kubernetesNodeStatusColor }}">
|
|
{{ ctrl.node.Status }}
|
|
</span>
|
|
<span ng-if="ctrl.node.Status == 'Warning'" class="text text-warning">
|
|
{{ ctrl.node.Conditions | kubernetesNodeConditionsMessage }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="col-xs-3"> Availability </td>
|
|
<td class="col-xs-9">
|
|
<select class="form-control" name="availability" style="display: inline-block; width: 16rem" ng-model="ctrl.formValues.Availability">
|
|
<option>{{ ctrl.availabilities.ACTIVE }}</option>
|
|
<option>{{ ctrl.availabilities.PAUSE }}</option>
|
|
<option>{{ ctrl.availabilities.DRAIN }}</option>
|
|
</select>
|
|
<span class="small vertical-center" ng-if="ctrl.state.isDrainOperation && ctrl.formValues.Availability === ctrl.availabilities.DRAIN">
|
|
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
|
|
Cannot use this action while another node is currently being drained.
|
|
</span>
|
|
<span class="small vertical-center" ng-if="ctrl.state.isContainPortainer && ctrl.formValues.Availability === ctrl.availabilities.DRAIN">
|
|
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
|
|
Cannot drain a node where this Portainer instance is running.
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div style="padding: 8px">
|
|
<kubernetes-resource-reservation
|
|
ng-if="ctrl.resourceReservation"
|
|
cpu-reservation="ctrl.resourceReservation.CPU"
|
|
cpu-usage="ctrl.resourceUsage.CPU"
|
|
cpu-limit="ctrl.node.CPU"
|
|
memory-reservation="ctrl.resourceReservation.Memory"
|
|
memory-usage="ctrl.resourceUsage.Memory"
|
|
memory-limit="ctrl.memoryLimit"
|
|
description="Resource reservation represents the total amount of resource assigned to all the applications running on this node."
|
|
display-usage="ctrl.hasResourceUsageAccess()"
|
|
>
|
|
</kubernetes-resource-reservation>
|
|
</div>
|
|
|
|
<div style="padding: 8px">
|
|
<!-- #region labels -->
|
|
<div class="col-sm-12 form-section-title"> Labels </div>
|
|
|
|
<div style="margin-bottom: 10px">
|
|
<span class="label label-default interactive vertical-center" ng-click="ctrl.addLabel()"> <pr-icon icon="'plus'" feather="true"></pr-icon> add label </span>
|
|
</div>
|
|
|
|
<div class="form-inline py-1" ng-repeat="label in ctrl.formValues.Labels">
|
|
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: label.NeedsDeletion }">
|
|
<span class="input-group-addon">Key</span>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
name="label_key_{{ $index }}"
|
|
ng-model="label.Key"
|
|
ng-change="ctrl.onChangeLabelKey($index)"
|
|
ng-disabled="ctrl.isSystemLabel($index)"
|
|
required
|
|
/>
|
|
</div>
|
|
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: label.NeedsDeletion }">
|
|
<span class="input-group-addon">Value</span>
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
name="label_value_{{ $index }}"
|
|
ng-change="ctrl.onChangeLabel($index)"
|
|
ng-model="label.Value"
|
|
ng-disabled="ctrl.isSystemLabel($index)"
|
|
/>
|
|
</div>
|
|
<div class="input-group col-sm-1 input-group-sm">
|
|
<div style="white-space: nowrap">
|
|
<button
|
|
ng-if="!ctrl.isSystemLabel($index) && !label.NeedsDeletion"
|
|
class="btn btn-sm btn-dangerlight btn-only-icon"
|
|
type="button"
|
|
ng-click="ctrl.removeLabel($index)"
|
|
>
|
|
<pr-icon icon="'x'" feather="true" mode="'error'" size="'sm'"></pr-icon>
|
|
</button>
|
|
<button ng-if="!ctrl.isSystemLabel($index) && label.NeedsDeletion" class="btn btn-sm btn-primary" type="button" ng-click="ctrl.restoreLabel($index)">
|
|
Restore
|
|
</button>
|
|
<span class="label label-warning label-sm image-tag" ng-if="label.IsUsed && !ctrl.isSystemLabel($index)" style="margin-left: 5px">used</span>
|
|
<span class="label label-info image-tag" ng-if="ctrl.isSystemLabel($index)" style="margin-left: 5px">system</span>
|
|
</div>
|
|
</div>
|
|
<div class="small mt-2" ng-show="kubernetesNodeUpdateForm['label_key_' + $index].$invalid || ctrl.state.duplicateLabelKeys[$index] !== undefined">
|
|
<ng-messages for="kubernetesNodeUpdateForm['label_key_' + $index].$error">
|
|
<p ng-message="required" class="vertical-center"> <pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Label key is required. </p>
|
|
</ng-messages>
|
|
<p ng-if="ctrl.state.duplicateLabelKeys[$index] !== undefined" class="vertical-center">
|
|
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> This label key is already defined.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- #endregion -->
|
|
|
|
<!-- #region taints -->
|
|
|
|
<div class="col-sm-12 form-section-title" style="margin-top: 20px"> Taints </div>
|
|
|
|
<div style="margin-bottom: 10px">
|
|
<span class="label label-default interactive vertical-center" ng-click="ctrl.addTaint()"> <pr-icon icon="'plus'" feather="true"></pr-icon> add taint </span>
|
|
</div>
|
|
|
|
<div class="form-inline" ng-repeat="taint in ctrl.formValues.Taints" style="padding: 3px 0 3px 0">
|
|
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: taint.NeedsDeletion }">
|
|
<span class="input-group-addon">Key</span>
|
|
<input type="text" class="form-control" name="taint_key_{{ $index }}" ng-model="taint.Key" ng-change="ctrl.onChangeTaintKey($index)" required />
|
|
</div>
|
|
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: taint.NeedsDeletion }">
|
|
<span class="input-group-addon">Value</span>
|
|
<input type="text" class="form-control" name="taint_value_{{ $index }}" ng-model="taint.Value" ng-change="ctrl.onChangeTaint($index)" />
|
|
</div>
|
|
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: taint.NeedsDeletion }">
|
|
<span class="input-group-addon">Effect</span>
|
|
<select
|
|
id="taint_effect_{{ $index }}"
|
|
name="taint_effect_{{ $index }}"
|
|
class="form-control"
|
|
ng-model="taint.Effect"
|
|
ng-change="ctrl.onChangeTaint($index)"
|
|
;
|
|
ng-options="effect as effect for effect in ctrl.availableEffects"
|
|
></select>
|
|
</div>
|
|
<div class="input-group col-sm-1 input-group-sm">
|
|
<div>
|
|
<button ng-if="!taint.NeedsDeletion" class="btn btn-sm btn-dangerlight btn-only-icon" type="button" ng-click="ctrl.removeTaint($index)">
|
|
<pr-icon icon="'x'" feather="true" mode="'error'" size="'sm'"></pr-icon>
|
|
</button>
|
|
<button ng-if="taint.NeedsDeletion" class="btn btn-sm btn-primary" type="button" ng-click="ctrl.restoreTaint($index)"> Restore </button>
|
|
</div>
|
|
</div>
|
|
<div
|
|
class="small"
|
|
style="margin-top: 5px"
|
|
ng-show="kubernetesNodeUpdateForm['taint_key_' + $index].$invalid || ctrl.state.duplicateTaintKeys[$index] !== undefined"
|
|
>
|
|
<ng-messages for="kubernetesNodeUpdateForm['taint_key_' + $index].$error">
|
|
<p ng-message="required" class="vertical-center"> <pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Taint key is required. </p>
|
|
</ng-messages>
|
|
<p ng-if="ctrl.state.duplicateTaintKeys[$index] !== undefined">
|
|
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> This taint key is already defined.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- #endregion -->
|
|
|
|
<!-- #region actions -->
|
|
|
|
<div class="col-sm-12 form-section-title" style="margin-top: 20px"> Actions </div>
|
|
|
|
<div class="form-group">
|
|
<div class="col-sm-12">
|
|
<button
|
|
class="btn btn-primary btn-sm"
|
|
type="button"
|
|
style="margin-left: 0"
|
|
ng-click="ctrl.updateNode()"
|
|
ng-disabled="kubernetesNodeUpdateForm.$invalid || !ctrl.isFormValid()"
|
|
>
|
|
Update node
|
|
</button>
|
|
<button class="btn btn-default btn-sm" type="button" ng-click="ctrl.resetFormValues()" ng-disabled="ctrl.isNoChangesMade()"> Cancel </button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- #endregion -->
|
|
</div>
|
|
</form>
|
|
</uib-tab>
|
|
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
|
|
<uib-tab-heading>
|
|
<div class="flex-center gap-1"> <pr-icon icon="'rotate-ccw'" size="'sm'" feather="true"></pr-icon> Events </div>
|
|
<div class="flex-center gap-1" ng-if="ctrl.hasEventWarnings()">
|
|
<pr-icon icon="'alert-circle'" mode="'warning-alt'" size="'sm'" feather="true"></pr-icon>
|
|
{{ 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.node.events"
|
|
order-by="Date"
|
|
reverse-order="true"
|
|
loading="ctrl.state.eventsLoading"
|
|
refresh-callback="ctrl.getEvents"
|
|
>
|
|
</kubernetes-events-datatable>
|
|
</uib-tab>
|
|
<uib-tab index="2" ng-if="ctrl.node.Yaml" select="ctrl.showEditor()" classes="btn-sm">
|
|
<uib-tab-heading class="vertical-center">
|
|
<div class="flex-center gap-1"> <pr-icon icon="'code'" size="'sm'" feather="true"></pr-icon> YAML </div>
|
|
</uib-tab-heading>
|
|
<div style="padding-right: 25px" ng-if="ctrl.state.showEditorTab">
|
|
<kubernetes-yaml-inspector key="node-yaml" data="ctrl.node.Yaml"> </kubernetes-yaml-inspector>
|
|
</div>
|
|
</uib-tab>
|
|
</uib-tabset>
|
|
</rd-widget-body>
|
|
</rd-widget>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" ng-if="ctrl.applications && ctrl.applications.length > 0">
|
|
<div class="col-sm-12">
|
|
<kubernetes-node-applications-datatable
|
|
dataset="ctrl.applications"
|
|
table-key="kubernetes.node.applications"
|
|
order-by="Name"
|
|
refresh-callback="ctrl.getApplications"
|
|
loading="ctrl.state.applicationsLoading"
|
|
title-text="Applications running on this node"
|
|
title-icon="fa-laptop-code"
|
|
>
|
|
</kubernetes-node-applications-datatable>
|
|
</div>
|
|
</div>
|
|
</div>
|