mirror of https://github.com/portainer/portainer
				
				
				
			
		
			
				
	
	
		
			1361 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			HTML
		
	
	
			
		
		
	
	
			1361 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			HTML
		
	
	
| <page-header
 | |
|   ng-if="!ctrl.state.isEdit"
 | |
|   title="'Create application'"
 | |
|   breadcrumbs="[
 | |
|     { label:'Applications', link:'kubernetes.applications' },
 | |
|      'Create an application'
 | |
|      ]"
 | |
|   reload="true"
 | |
| >
 | |
| </page-header>
 | |
| 
 | |
| <page-header
 | |
|   ng-if="ctrl.state.isEdit"
 | |
|   title="'Edit application'"
 | |
|   breadcrumbs="[
 | |
|     { label:'Namespaces', link:'kubernetes.resourcePools' },
 | |
|     { 
 | |
|       label:ctrl.application.ResourcePool,
 | |
|       link: 'kubernetes.resourcePools.resourcePool', 
 | |
|       linkParams:{ id: ctrl.application.ResourcePool }
 | |
|     },
 | |
|     { label:'Applications', link:'kubernetes.applications' },
 | |
|     { 
 | |
|       label:ctrl.application.Name,
 | |
|       link: 'kubernetes.applications.application', 
 | |
|       linkParams:{ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool }
 | |
|     },
 | |
|      'Edit',
 | |
|      ]"
 | |
|   reload="true"
 | |
| >
 | |
| </page-header>
 | |
| 
 | |
| <kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>
 | |
| <div ng-if="ctrl.state.viewReady">
 | |
|   <div class="row kubernetes-create">
 | |
|     <div class="col-xs-12">
 | |
|       <rd-widget>
 | |
|         <rd-widget-body>
 | |
|           <form class="form-horizontal" name="kubernetesApplicationCreationForm" autocomplete="off">
 | |
|             <div ng-if="!ctrl.isExternalApplication()">
 | |
|               <git-form-info-panel
 | |
|                 ng-if="ctrl.state.appType == ctrl.KubernetesDeploymentTypes.GIT"
 | |
|                 class-name="text-muted"
 | |
|                 url="ctrl.stack.GitConfig.URL"
 | |
|                 config-file-path="ctrl.stack.GitConfig.ConfigFilePath"
 | |
|                 additional-files="ctrl.stack.AdditionalFiles"
 | |
|                 type="application"
 | |
|               ></git-form-info-panel>
 | |
|               <div class="col-sm-12 form-section-title" ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"> Namespace </div>
 | |
|               <!-- #region NAMESPACE -->
 | |
|               <div class="form-group" ng-if="ctrl.formValues.ResourcePool">
 | |
|                 <label for="resource-pool-selector" class="col-sm-3 col-lg-2 control-label text-left">Namespace</label>
 | |
|                 <div class="col-sm-8">
 | |
|                   <select
 | |
|                     class="form-control"
 | |
|                     id="resource-pool-selector"
 | |
|                     ng-model="ctrl.formValues.ResourcePool"
 | |
|                     ng-options="resourcePool.Namespace.Name for resourcePool in ctrl.resourcePools"
 | |
|                     ng-change="ctrl.onResourcePoolSelectionChange()"
 | |
|                     ng-disabled="ctrl.state.isEdit"
 | |
|                     data-cy="k8sAppCreate-nsSelect"
 | |
|                   ></select>
 | |
|                 </div>
 | |
|               </div>
 | |
|               <div class="form-group" ng-if="ctrl.state.resourcePoolHasQuota && ctrl.resourceQuotaCapacityExceeded() && ctrl.formValues.ResourcePool">
 | |
|                 <div class="col-sm-12 small text-danger">
 | |
|                   <pr-icon icon="'alert-triangle'" feather="true"></pr-icon>
 | |
|                   This namespace has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of the
 | |
|                   namespace.
 | |
|                 </div>
 | |
|               </div>
 | |
|               <div class="form-group" ng-if="!ctrl.formValues.ResourcePool">
 | |
|                 <div class="col-sm-12 small text-muted">
 | |
|                   <pr-icon icon="'alert-triangle'" feather="true"></pr-icon>
 | |
|                   You do not have access to any namespace. Contact your administrator to get access to a namespace.
 | |
|                 </div>
 | |
|               </div>
 | |
|               <!-- #endregion -->
 | |
| 
 | |
|               <!-- #region Git repository -->
 | |
|               <kubernetes-redeploy-app-git-form
 | |
|                 ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.GIT"
 | |
|                 stack="ctrl.stack"
 | |
|                 namespace="ctrl.formValues.ResourcePool.Namespace.Name"
 | |
|               ></kubernetes-redeploy-app-git-form>
 | |
|               <!-- #endregion -->
 | |
| 
 | |
|               <!-- #region web editor -->
 | |
|               <web-editor-form
 | |
|                 ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.CONTENT"
 | |
|                 value="ctrl.stackFileContent"
 | |
|                 yml="true"
 | |
|                 identifier="kubernetes-deploy-editor"
 | |
|                 placeholder="# Define or paste the content of your manifest file here"
 | |
|                 on-change="(ctrl.onChangeFileContent)"
 | |
|               >
 | |
|                 <editor-description>
 | |
|                   <span class="text-muted small" ng-show="ctrl.stack.IsComposeFormat">
 | |
|                     <p>
 | |
|                       <pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                       Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that not
 | |
|                       all the Compose format options are supported by Kompose at the moment.
 | |
|                     </p>
 | |
|                     <p>
 | |
|                       You can get more information about Compose file format in the
 | |
|                       <a href="https://docs.docker.com/compose/compose-file/" target="_blank">official documentation</a>.
 | |
|                     </p>
 | |
|                   </span>
 | |
|                   <span class="text-muted small" ng-show="!ctrl.stack.IsComposeFormat">
 | |
|                     <p>
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       This feature allows you to deploy any kind of Kubernetes resource in this environment (Deployment, Secret, ConfigMap...).
 | |
|                     </p>
 | |
|                     <p>
 | |
|                       You can get more information about Kubernetes file format in the
 | |
|                       <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/" target="_blank">official documentation</a>.
 | |
|                     </p>
 | |
|                   </span>
 | |
|                 </editor-description>
 | |
|               </web-editor-form>
 | |
|               <!-- #endregion -->
 | |
|               <div ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM">
 | |
|                 <div class="col-sm-12 form-section-title"> Application </div>
 | |
|                 <!-- #region NAME FIELD -->
 | |
|                 <div class="form-group">
 | |
|                   <label for="application_name" class="col-sm-3 col-lg-2 control-label text-left">Name</label>
 | |
|                   <div class="col-sm-8">
 | |
|                     <input
 | |
|                       type="text"
 | |
|                       class="form-control"
 | |
|                       name="application_name"
 | |
|                       ng-model="ctrl.formValues.Name"
 | |
|                       ng-change="ctrl.onChangeName()"
 | |
|                       placeholder="my-app"
 | |
|                       ng-pattern="/^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/"
 | |
|                       auto-focus
 | |
|                       required
 | |
|                       ng-disabled="ctrl.state.isEdit"
 | |
|                       data-cy="k8sAppCreate-applicationName"
 | |
|                     />
 | |
|                   </div>
 | |
|                 </div>
 | |
|                 <div class="form-group" ng-show="kubernetesApplicationCreationForm.application_name.$invalid || ctrl.state.alreadyExists">
 | |
|                   <div class="col-sm-12 small">
 | |
|                     <div ng-messages="kubernetesApplicationCreationForm.application_name.$error">
 | |
|                       <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This field is required.</p>
 | |
|                       <p ng-message="pattern">
 | |
|                         <pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                         This field must consist of lower case alphanumeric characters or '-', contain at most 63 characters, start with an alphabetic character, and end with an
 | |
|                         alphanumeric character (e.g. 'my-name', or 'abc-123').
 | |
|                       </p>
 | |
|                     </div>
 | |
|                     <p ng-if="ctrl.state.alreadyExists">
 | |
|                       <pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                       An application with the same name already exists inside the selected namespace.
 | |
|                     </p>
 | |
|                   </div>
 | |
|                 </div>
 | |
|                 <!-- #endregion -->
 | |
| 
 | |
|                 <!-- #region IMAGE FIELD -->
 | |
|                 <div class="form-group mb-0">
 | |
|                   <div class="col-sm-12">
 | |
|                     <por-image-registry
 | |
|                       model="ctrl.formValues.ImageModel"
 | |
|                       ng-if="ctrl.formValues.ResourcePool"
 | |
|                       auto-complete="false"
 | |
|                       label-class="col-sm-1"
 | |
|                       input-class="col-sm-11"
 | |
|                       namespace="ctrl.formValues.ResourcePool.Namespace.Name"
 | |
|                       endpoint="ctrl.endpoint"
 | |
|                       is-admin="ctrl.isAdmin"
 | |
|                       check-rate-limits="true"
 | |
|                       set-validity="ctrl.setPullImageValidity"
 | |
|                     ></por-image-registry>
 | |
|                   </div>
 | |
|                 </div>
 | |
|                 <!-- #end region IMAGE FIELD -->
 | |
| 
 | |
|                 <div ng-if="ctrl.formValues.ResourcePool">
 | |
|                   <div class="col-sm-12 form-section-title"> Stack </div>
 | |
|                   <!-- #region STACK -->
 | |
|                   <div class="form-group">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       Portainer can automatically bundle multiple applications inside a stack. Enter a name of a new stack or select an existing stack in the list. Leave empty to
 | |
|                       use the application name.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group">
 | |
|                     <label for="stack_name" class="col-sm-3 col-lg-2 control-label text-left">Stack</label>
 | |
|                     <div class="col-sm-8">
 | |
|                       <input
 | |
|                         type="text"
 | |
|                         class="form-control"
 | |
|                         placeholder="myStack"
 | |
|                         ng-model="ctrl.formValues.StackName"
 | |
|                         name="stack_name"
 | |
|                         uib-typeahead="stack for stack in ctrl.stacks | filter:$viewValue | limitTo:7"
 | |
|                         typeahead-show-hint="true"
 | |
|                         typeahead-min-length="0"
 | |
|                         data-cy="k8sAppCreate-stackName"
 | |
|                       />
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <div class="col-sm-12 form-section-title"> Environment </div>
 | |
|                   <!-- #region ENVIRONMENT VARIABLES -->
 | |
|                   <div class="form-group">
 | |
|                     <div class="col-sm-12">
 | |
|                       <label class="control-label text-left">Environment variables</label>
 | |
|                       <span
 | |
|                         ng-if="ctrl.formValues.Containers.length <= 1"
 | |
|                         class="label label-default interactive vertical-center"
 | |
|                         style="margin-left: 10px"
 | |
|                         ng-click="ctrl.addEnvironmentVariable()"
 | |
|                         data-cy="k8sAppCreate-addEnvVarButton"
 | |
|                       >
 | |
|                         <pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> add environment variable
 | |
|                       </span>
 | |
|                     </div>
 | |
| 
 | |
|                     <div class="col-sm-12 form-inline" style="margin-top: 10px">
 | |
|                       <div ng-repeat="envVar in ctrl.formValues.EnvironmentVariables | orderBy: 'NameIndex'" style="margin-top: 2px">
 | |
|                         <div style="margin-top: 2px">
 | |
|                           <div class="col-sm-4 input-group input-group-sm">
 | |
|                             <div class="input-group col-sm-12 input-group-sm" ng-class="{ striked: envVar.NeedsDeletion }">
 | |
|                               <span class="input-group-addon">name</span>
 | |
|                               <input
 | |
|                                 type="text"
 | |
|                                 name="environment_variable_name_{{ $index }}"
 | |
|                                 class="form-control"
 | |
|                                 ng-model="envVar.Name"
 | |
|                                 ng-change="ctrl.onChangeEnvironmentName()"
 | |
|                                 ng-pattern="/^[-._a-zA-Z][-._a-zA-Z0-9]*$/"
 | |
|                                 placeholder="foo"
 | |
|                                 ng-disabled="ctrl.formValues.Containers.length > 1"
 | |
|                                 data-cy="k8sAppCreate-envVarName_{{ $index }}"
 | |
|                                 required
 | |
|                               />
 | |
|                             </div>
 | |
|                           </div>
 | |
| 
 | |
|                           <div class="col-sm-4 input-group 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"
 | |
|                               ng-disabled="ctrl.formValues.Containers.length > 1"
 | |
|                               data-cy="k8sAppCreate-envVarValue_{{ $index }}"
 | |
|                             />
 | |
|                           </div>
 | |
| 
 | |
|                           <div class="col-sm-2 input-group input-group-sm" ng-if="ctrl.formValues.Containers.length <= 1">
 | |
|                             <button ng-if="!envVar.NeedsDeletion" class="btn btn-md btn-light btn-only-icon" type="button" ng-click="ctrl.removeEnvironmentVariable(envVar)">
 | |
|                               <pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon>
 | |
|                             </button>
 | |
|                             <button
 | |
|                               ng-if="envVar.NeedsDeletion"
 | |
|                               class="btn btn-sm btn-light btn-only-icon"
 | |
|                               type="button"
 | |
|                               ng-click="ctrl.restoreEnvironmentVariable(envVar)"
 | |
|                               data-cy="k8sAppCreate-removeEnvVarButton_{{ $index }}"
 | |
|                             >
 | |
|                               <pr-icon icon="'rotate-cw'" size="'md'" feather="true"></pr-icon>
 | |
|                             </button>
 | |
|                           </div>
 | |
|                         </div>
 | |
|                         <div
 | |
|                           ng-show="
 | |
|                             kubernetesApplicationCreationForm['environment_variable_name_' + $index].$invalid ||
 | |
|                             ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined
 | |
|                           "
 | |
|                         >
 | |
|                           <div class="col-sm-4 input-group input-group-sm">
 | |
|                             <div
 | |
|                               class="small"
 | |
|                               style="margin-top: 5px"
 | |
|                               ng-show="
 | |
|                                 kubernetesApplicationCreationForm['environment_variable_name_' + $index].$invalid ||
 | |
|                                 ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined
 | |
|                               "
 | |
|                             >
 | |
|                               <ng-messages for="kubernetesApplicationCreationForm['environment_variable_name_' + $index].$error">
 | |
|                                 <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Environment variable name is required.</p>
 | |
|                                 <p ng-message="pattern"
 | |
|                                   ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This field must consist of alphabetic characters, digits, '_', '-',
 | |
|                                   or '.', and must not start with a digit (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1'.</p
 | |
|                                 >
 | |
|                               </ng-messages>
 | |
|                               <p ng-if="ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined"
 | |
|                                 ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This environment variable is already defined.</p
 | |
|                               >
 | |
|                             </div>
 | |
|                           </div>
 | |
|                           <div class="col-sm-4 input-group input-group-sm"></div>
 | |
|                           <div class="col-sm-2 input-group input-group-sm"></div>
 | |
|                         </div>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <div class="col-sm-12 form-section-title"> Configurations </div>
 | |
|                   <!-- #region CONFIGURATIONS -->
 | |
|                   <div class="form-group">
 | |
|                     <div class="col-sm-12">
 | |
|                       <label class="control-label text-left">Configurations</label>
 | |
|                       <span
 | |
|                         class="label label-default interactive vertical-center"
 | |
|                         style="margin-left: 10px"
 | |
|                         ng-click="ctrl.addConfiguration()"
 | |
|                         ng-if="ctrl.formValues.Containers.length <= 1"
 | |
|                         data-cy="k8sAppCreate-addConfigButton"
 | |
|                       >
 | |
|                         <pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> add configuration
 | |
|                       </span>
 | |
|                     </div>
 | |
|                     <div class="col-sm-12 small text-muted" style="margin-top: 15px" ng-if="ctrl.formValues.Configurations.length">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       Portainer will automatically expose all the keys of a configuration as environment variables. This behavior can be overridden to filesystem mounts for each
 | |
|                       key via the override button.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <!-- config-element -->
 | |
|                   <div class="form-group" ng-repeat="(index, config) in ctrl.formValues.Configurations">
 | |
|                     <label for="stack_name" class="col-sm-3 col-lg-2 control-label text-left">Configuration</label>
 | |
|                     <div class="col-sm-6">
 | |
|                       <select
 | |
|                         class="form-control"
 | |
|                         ng-model="config.SelectedConfiguration"
 | |
|                         ng-options="c as c.Name for c in ctrl.configurations track by c.Name"
 | |
|                         ng-change="ctrl.resetConfiguration(index)"
 | |
|                         ng-disabled="ctrl.formValues.Containers.length > 1"
 | |
|                         data-cy="k8sAppCreate-addConfigSelect_{{ $index }}"
 | |
|                       ></select>
 | |
|                     </div>
 | |
|                     <div class="col-sm-3" style="margin-top: 2px">
 | |
|                       <button
 | |
|                         class="btn btn-sm btn-light vertical-center"
 | |
|                         type="button"
 | |
|                         ng-if="!config.Overriden"
 | |
|                         ng-click="ctrl.overrideConfiguration(index)"
 | |
|                         ng-disabled="!config.SelectedConfiguration || ctrl.formValues.Containers.length > 1"
 | |
|                         data-cy="k8sAppCreate-configOverrideButton_{{ $index }}"
 | |
|                       >
 | |
|                         <pr-icon icon="'list'" size="'md'" feather="true"></pr-icon> Override
 | |
|                       </button>
 | |
|                       <button
 | |
|                         class="btn btn-sm btn-light vertical-center"
 | |
|                         type="button"
 | |
|                         ng-if="config.Overriden"
 | |
|                         ng-click="ctrl.resetConfiguration(index)"
 | |
|                         ng-disabled="ctrl.formValues.Containers.length > 1"
 | |
|                         data-cy="k8sAppCreate-configAutoButton_{{ $index }}"
 | |
|                       >
 | |
|                         <pr-icon icon="'rotate-cw'" size="'md'" feather="true"></pr-icon> Auto
 | |
|                       </button>
 | |
|                       <button
 | |
|                         class="btn btn-sm btn-dangerlight vertical-center"
 | |
|                         type="button"
 | |
|                         ng-click="ctrl.removeConfiguration(index)"
 | |
|                         ng-if="ctrl.formValues.Containers.length <= 1"
 | |
|                         data-cy="k8sAppCreate-configRemoveButton"
 | |
|                       >
 | |
|                         <pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon> Remove
 | |
|                       </button>
 | |
|                     </div>
 | |
|                     <!-- no-override -->
 | |
|                     <div class="col-sm-12" style="margin-top: 10px" ng-if="config.SelectedConfiguration && !config.Overriden">
 | |
|                       <div class="col-sm-3 col-lg-2"></div>
 | |
|                       <div class="col-sm-6 small text-muted" style="padding-left: 5px">
 | |
|                         The following keys will be loaded from the <code>{{ config.SelectedConfiguration.Name }}</code> configuration as environment variables:
 | |
|                         <span ng-repeat="(key, _) in config.SelectedConfiguration.Data">
 | |
|                           <code>{{ key }}</code
 | |
|                           >{{ $last ? '' : ', ' }}
 | |
|                         </span>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                     <!-- !no-override -->
 | |
| 
 | |
|                     <!-- has-override -->
 | |
|                     <div class="col-sm-12 form-inline" style="margin-top: 10px" ng-if="config.Overriden">
 | |
|                       <div ng-repeat="(keyIndex, overridenKey) in config.OverridenKeys" style="margin-top: 2px">
 | |
|                         <div class="row">
 | |
|                           <div class="col-sm-3 col-lg-2 form-group !m-0"><span> </span></div>
 | |
|                           <div class="col-sm-3 form-group" style="margin-left: -11px">
 | |
|                             <div class="input-group input-group-sm">
 | |
|                               <span class="input-group-addon">configuration key</span>
 | |
|                               <input type="text" class="form-control" ng-value="overridenKey.Key" disabled />
 | |
|                             </div>
 | |
|                           </div>
 | |
| 
 | |
|                           <div class="col-sm-3 form-group" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
 | |
|                             <div class="input-group input-group-sm">
 | |
|                               <span class="input-group-addon">path on disk</span>
 | |
|                               <input
 | |
|                                 type="text"
 | |
|                                 class="form-control"
 | |
|                                 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()"
 | |
|                                 data-cy="k8sAppCreate-pathOnDiskInput"
 | |
|                               />
 | |
|                             </div>
 | |
|                             <span
 | |
|                               ng-show="
 | |
|                                 kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$invalid ||
 | |
|                                 ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined
 | |
|                               "
 | |
|                             >
 | |
|                               <div class="input-group input-group-sm text-muted" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
 | |
|                                 <div
 | |
|                                   class="small"
 | |
|                                   style="margin-top: 5px"
 | |
|                                   ng-show="
 | |
|                                     kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$invalid ||
 | |
|                                     ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined
 | |
|                                   "
 | |
|                                 >
 | |
|                                   <ng-messages for="kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$error">
 | |
|                                     <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Path is required.</p>
 | |
|                                   </ng-messages>
 | |
|                                   <p ng-if="ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined"
 | |
|                                     ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This path is already used.</p
 | |
|                                   >
 | |
|                                 </div>
 | |
|                               </div>
 | |
|                             </span>
 | |
|                           </div>
 | |
| 
 | |
|                           <div class="col-sm-4 form-group">
 | |
|                             <div class="input-group btn-group btn-group-sm">
 | |
|                               <label class="btn btn-light" ng-model="overridenKey.Type" uib-btn-radio="ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT">
 | |
|                                 <pr-icon icon="'list'" feather="true"></pr-icon> Environment
 | |
|                               </label>
 | |
|                               <label class="btn btn-light" ng-model="overridenKey.Type" uib-btn-radio="ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
 | |
|                                 <pr-icon icon="'file-text'" feather="true"></pr-icon> Filesystem
 | |
|                               </label>
 | |
|                             </div>
 | |
|                           </div>
 | |
|                         </div>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                     <!-- !has-override -->
 | |
|                   </div>
 | |
|                   <!-- !config-element -->
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <div class="col-sm-12 form-section-title"> Persisting data </div>
 | |
|                   <!-- #region PERSISTED FOLDERS -->
 | |
|                   <div class="form-group" ng-if="!ctrl.storageClassAvailable()">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       No storage option is available to persist data, contact your administrator to enable a storage option.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.storageClassAvailable()">
 | |
|                     <div class="col-sm-12" style="margin-top: 5px" ng-if="!ctrl.allQuotasExhaustedAndNoVolumesAvailable()">
 | |
|                       <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.isAddPersistentFolderButtonShowed()"
 | |
|                         data-cy="k8sAppCreate-addPersistentFolderButton"
 | |
|                       >
 | |
|                         <pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> add persisted folder
 | |
|                       </span>
 | |
|                     </div>
 | |
| 
 | |
|                     <div class="col-sm-12" style="margin-top: 5px" ng-if="ctrl.allQuotasExhaustedAndNoVolumesAvailable()">
 | |
|                       <span class="small text-muted">
 | |
|                         <pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                         This namespace has exhausted its storage capacity. Contact your administrator to expand the capacity of the namespace.
 | |
|                       </span>
 | |
|                     </div>
 | |
| 
 | |
|                     <div class="col-sm-12 form-inline" style="margin-top: 10px" ng-repeat="persistedFolder in ctrl.formValues.PersistedFolders">
 | |
|                       <div style="margin-top: 2px">
 | |
|                         <div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: persistedFolder.NeedsDeletion }">
 | |
|                           <span class="input-group-addon">path in container</span>
 | |
|                           <input
 | |
|                             type="text"
 | |
|                             class="form-control"
 | |
|                             name="persisted_folder_path_{{ $index }}"
 | |
|                             ng-model="persistedFolder.ContainerPath"
 | |
|                             ng-change="ctrl.onChangePersistedFolderPath()"
 | |
|                             ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
 | |
|                             placeholder="/data"
 | |
|                             required
 | |
|                             data-cy="k8sAppCreate-containerPathInput_{{ $index }}"
 | |
|                           />
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-2 input-group-sm">
 | |
|                           <span
 | |
|                             class="btn-group btn-group-sm"
 | |
|                             ng-class="{ striked: persistedFolder.NeedsDeletion }"
 | |
|                             ng-if="
 | |
|                               !ctrl.isEditAndExistingPersistedFolder($index) &&
 | |
|                               ctrl.application.ApplicationType !== ctrl.ApplicationTypes.STATEFULSET &&
 | |
|                               ctrl.formValues.Containers.length <= 1
 | |
|                             "
 | |
|                           >
 | |
|                             <label
 | |
|                               class="btn btn-primary"
 | |
|                               ng-model="persistedFolder.UseNewVolume"
 | |
|                               uib-btn-radio="true"
 | |
|                               ng-change="ctrl.useNewVolume($index)"
 | |
|                               ng-disabled="ctrl.isNewVolumeButtonDisabled($index)"
 | |
|                               >New volume</label
 | |
|                             >
 | |
|                             <label
 | |
|                               class="btn btn-primary"
 | |
|                               ng-model="persistedFolder.UseNewVolume"
 | |
|                               uib-btn-radio="false"
 | |
|                               ng-change="ctrl.useExistingVolume($index)"
 | |
|                               ng-disabled="ctrl.isExistingVolumeButtonDisabled()"
 | |
|                               >Existing volume</label
 | |
|                             >
 | |
|                           </span>
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: persistedFolder.NeedsDeletion }" ng-if="persistedFolder.UseNewVolume">
 | |
|                           <span class="input-group-addon">requested size</span>
 | |
|                           <input
 | |
|                             type="number"
 | |
|                             class="form-control"
 | |
|                             name="persisted_folder_size_{{ $index }}"
 | |
|                             ng-model="persistedFolder.Size"
 | |
|                             placeholder="20"
 | |
|                             ng-min="0"
 | |
|                             required
 | |
|                             ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
 | |
|                             ng-change="ctrl.onChangeVolumeRequestedSize()"
 | |
|                           />
 | |
|                           <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) || ctrl.formValues.Containers.length > 1"
 | |
|                               ng-change="ctrl.onChangeVolumeRequestedSize()"
 | |
|                             ></select>
 | |
|                           </span>
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-2 input-group-sm" ng-class="{ striked: persistedFolder.NeedsDeletion }" ng-if="persistedFolder.UseNewVolume">
 | |
|                           <span class="input-group-addon">storage</span>
 | |
|                           <select
 | |
|                             ng-if="ctrl.hasMultipleStorageClassesAvailable()"
 | |
|                             class="form-control"
 | |
|                             ng-model="persistedFolder.StorageClass"
 | |
|                             ng-options="storageClass as storageClass.Name for storageClass in ctrl.storageClasses"
 | |
|                             ng-disabled="ctrl.state.isEdit || ctrl.formValues.Containers.length > 1"
 | |
|                             data-cy="k8sAppCreate-storageSelect_{{ $index }}"
 | |
|                           ></select>
 | |
|                           <input
 | |
|                             ng-if="!ctrl.hasMultipleStorageClassesAvailable()"
 | |
|                             type="text"
 | |
|                             class="form-control"
 | |
|                             disabled
 | |
|                             ng-model="persistedFolder.StorageClass.Name"
 | |
|                             data-cy="k8sAppCreate-storageClassNameInput_{{ $index }}"
 | |
|                           />
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-5 input-group-sm" ng-if="!persistedFolder.UseNewVolume" ng-class="{ striked: persistedFolder.NeedsDeletion }">
 | |
|                           <span class="input-group-addon">volume</span>
 | |
|                           <select
 | |
|                             class="form-control"
 | |
|                             name="existing_volumes_{{ $index }}"
 | |
|                             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) || ctrl.formValues.Containers.length > 1"
 | |
|                             required
 | |
|                           >
 | |
|                             <option selected disabled hidden value="">Select a volume</option>
 | |
|                           </select>
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-1 input-group-sm">
 | |
|                           <div 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)"
 | |
|                               data-cy="k8sAppCreate-rmPersistentFolderButton"
 | |
|                             >
 | |
|                               <pr-icon icon="'trash-2'" feather="true"></pr-icon>
 | |
|                             </button>
 | |
|                             <button
 | |
|                               ng-if="persistedFolder.NeedsDeletion"
 | |
|                               class="btn btn-sm btn-primary"
 | |
|                               type="button"
 | |
|                               ng-click="ctrl.restorePersistedFolder($index)"
 | |
|                               data-cy="k8sAppCreate-restorePersistentButton"
 | |
|                             >
 | |
|                               <pr-icon icon="'rotate-cw'" feather="true"></pr-icon>
 | |
|                             </button>
 | |
|                           </div>
 | |
|                         </div>
 | |
|                       </div>
 | |
| 
 | |
|                       <div
 | |
|                         ng-show="
 | |
|                           kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid ||
 | |
|                           ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined ||
 | |
|                           kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$invalid ||
 | |
|                           ctrl.state.exceeded.persistedFolders.refs[$index] !== undefined ||
 | |
|                           kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid ||
 | |
|                           ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined
 | |
|                         "
 | |
|                       >
 | |
|                         <div class="input-group col-sm-3 input-group-sm">
 | |
|                           <div
 | |
|                             class="small text-warning"
 | |
|                             style="margin-top: 5px"
 | |
|                             ng-show="
 | |
|                               kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid || ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined
 | |
|                             "
 | |
|                           >
 | |
|                             <ng-messages for="kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$error">
 | |
|                               <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Path is required.</p>
 | |
|                             </ng-messages>
 | |
|                             <p ng-if="ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
 | |
|                               ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This path is already defined.</p
 | |
|                             >
 | |
|                           </div>
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-2 input-group-sm"></div>
 | |
| 
 | |
|                         <div class="input-group col-sm-5 input-group-sm">
 | |
|                           <div
 | |
|                             class="small text-warning"
 | |
|                             style="margin-top: 5px"
 | |
|                             ng-show="
 | |
|                               kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$invalid || ctrl.state.exceeded.persistedFolders.refs[$index] !== undefined
 | |
|                             "
 | |
|                           >
 | |
|                             <ng-messages for="kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$error">
 | |
|                               <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Size is required.</p>
 | |
|                               <p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This value must be greater than zero.</p>
 | |
|                             </ng-messages>
 | |
|                             <p ng-if="ctrl.state.exceeded.persistedFolders.refs[$index] !== undefined">
 | |
|                               <pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                               You can only request up to
 | |
|                               {{ ctrl.state.storages.availabilities[persistedFolder.StorageClass.Name] | kubernetesAppStorageRequestSizeHumanReadable }} for
 | |
|                               {{ persistedFolder.StorageClass.Name }}
 | |
|                             </p>
 | |
|                           </div>
 | |
|                           <div
 | |
|                             class="small text-warning"
 | |
|                             ng-show="kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid || ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined"
 | |
|                           >
 | |
|                             <ng-messages for="kubernetesApplicationCreationForm['existing_volumes_' + $index].$error">
 | |
|                               <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Volume is required.</p>
 | |
|                             </ng-messages>
 | |
|                             <p ng-if="ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined"
 | |
|                               ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This volume is already used.</p
 | |
|                             >
 | |
|                           </div>
 | |
|                         </div>
 | |
| 
 | |
|                         <div class="input-group col-sm-1 input-group-sm"> </div>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <!-- #region DATA ACCESS POLICY -->
 | |
|                   <div ng-if="ctrl.showDataAccessPolicySection()">
 | |
|                     <div class="form-group">
 | |
|                       <div class="col-sm-12">
 | |
|                         <label class="control-label text-left">Data access policy</label>
 | |
|                       </div>
 | |
|                     </div>
 | |
| 
 | |
|                     <div class="form-group">
 | |
|                       <div class="col-sm-12 small text-muted"> Specify how the data will be used across instances. </div>
 | |
|                     </div>
 | |
| 
 | |
|                     <!-- access policy options -->
 | |
|                     <div class="form-group" style="margin-bottom: 0">
 | |
|                       <div class="boxselector_wrapper">
 | |
|                         <div
 | |
|                           ng-if="
 | |
|                             (!ctrl.state.isEdit && !ctrl.state.persistedFoldersUseExistingVolumes) ||
 | |
|                             (ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED)
 | |
|                           "
 | |
|                         >
 | |
|                           <input
 | |
|                             type="radio"
 | |
|                             id="data_access_isolated"
 | |
|                             ng-value="ctrl.ApplicationDataAccessPolicies.ISOLATED"
 | |
|                             ng-model="ctrl.formValues.DataAccessPolicy"
 | |
|                             ng-change="ctrl.resetDeploymentType()"
 | |
|                           />
 | |
|                           <label for="data_access_isolated">
 | |
|                             <div class="boxselector_header">
 | |
|                               <pr-icon icon="'box'" feather="true"></pr-icon>
 | |
|                               Isolated
 | |
|                             </div>
 | |
|                             <p>Application will be deployed as a StatefulSet with each instantiating their own data</p>
 | |
|                           </label>
 | |
|                         </div>
 | |
|                         <div
 | |
|                           style="color: #767676"
 | |
|                           ng-if="
 | |
|                             (ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED) || ctrl.state.persistedFoldersUseExistingVolumes
 | |
|                           "
 | |
|                         >
 | |
|                           <input type="radio" id="data_access_isolated" disabled />
 | |
|                           <label
 | |
|                             for="data_access_isolated"
 | |
|                             tooltip-append-to-body="true"
 | |
|                             tooltip-placement="bottom"
 | |
|                             tooltip-class="portainer-tooltip"
 | |
|                             uib-tooltip="Changing the data access policy is not allowed"
 | |
|                             style="cursor: pointer; border-color: #767676"
 | |
|                           >
 | |
|                             <div class="boxselector_header">
 | |
|                               <pr-icon icon="'box'" feather="true"></pr-icon>
 | |
|                               Isolated
 | |
|                             </div>
 | |
|                             <p>Application will be deployed as a StatefulSet with each instantiating their own data</p>
 | |
|                           </label>
 | |
|                         </div>
 | |
|                         <div ng-if="!ctrl.state.isEdit || (ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED)">
 | |
|                           <input
 | |
|                             type="radio"
 | |
|                             id="data_access_shared"
 | |
|                             ng-value="ctrl.ApplicationDataAccessPolicies.SHARED"
 | |
|                             ng-model="ctrl.formValues.DataAccessPolicy"
 | |
|                             ng-change="ctrl.resetDeploymentType()"
 | |
|                           />
 | |
|                           <label for="data_access_shared">
 | |
|                             <div class="boxselector_header">
 | |
|                               <pr-icon icon="'sliders'" feather="true"></pr-icon>
 | |
|                               Shared
 | |
|                             </div>
 | |
|                             <p>Application will be deployed as a Deployment with a shared storage access</p>
 | |
|                           </label>
 | |
|                         </div>
 | |
|                         <div style="color: #767676" ng-if="ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED">
 | |
|                           <input type="radio" id="data_access_shared" disabled />
 | |
|                           <label
 | |
|                             for="data_access_shared"
 | |
|                             tooltip-append-to-body="true"
 | |
|                             tooltip-placement="bottom"
 | |
|                             tooltip-class="portainer-tooltip"
 | |
|                             uib-tooltip="Changing the data access policy is not allowed"
 | |
|                             style="cursor: pointer; border-color: #767676"
 | |
|                           >
 | |
|                             <div class="boxselector_header">
 | |
|                               <pr-icon icon="'sliders'" feather="true"></pr-icon>
 | |
|                               Shared
 | |
|                             </div>
 | |
|                             <p>Application will be deployed as a Deployment with a shared storage access</p>
 | |
|                           </label>
 | |
|                         </div>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                     <!-- !access policy options -->
 | |
|                   </div>
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <div class="col-sm-12 form-section-title"> Resource reservations </div>
 | |
|                   <!-- #region RESOURCE RESERVATIONS -->
 | |
|                   <div class="form-group" ng-if="!ctrl.state.resourcePoolHasQuota">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       Resource reservations are applied per instance of the application.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded()">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       A resource quota is set on this namespace, you must specify resource reservations. Resource reservations are applied per instance of the application. Maximums
 | |
|                       are inherited from the namespace quota.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.state.resourcePoolHasQuota && ctrl.resourceQuotaCapacityExceeded()">
 | |
|                     <div class="col-sm-12 small text-danger">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
 | |
|                       This namespace has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of
 | |
|                       the namespace.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <!-- memory-limit-input -->
 | |
|                   <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
 | |
|                         message="'An instance of this application will reserve this amount of memory. If the instance memory usage exceeds the reservation, it might be subject to OOM.'"
 | |
|                       >
 | |
|                       </portainer-tooltip>
 | |
|                     </label>
 | |
|                     <div class="col-sm-3">
 | |
|                       <slider model="ctrl.formValues.MemoryLimit" floor="ctrl.state.sliders.memory.min" ceil="ctrl.state.sliders.memory.max" step="128"></slider>
 | |
|                     </div>
 | |
|                     <div class="col-sm-2">
 | |
|                       <input
 | |
|                         name="memory_limit"
 | |
|                         ng-model="ctrl.formValues.MemoryLimit"
 | |
|                         type="number"
 | |
|                         min="{{ ctrl.state.sliders.memory.min }}"
 | |
|                         max="{{ ctrl.state.sliders.memory.max }}"
 | |
|                         class="form-control"
 | |
|                         id="memory-limit"
 | |
|                         required
 | |
|                         data-cy="k8sAppCreate-memoryLimit"
 | |
|                       />
 | |
|                     </div>
 | |
|                     <div class="col-sm-4">
 | |
|                       <p class="small text-muted" style="margin-top: 7px"> Maximum memory usage (<b>MB</b>) </p>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <div class="form-group" ng-show="kubernetesApplicationCreationForm.memory_limit.$invalid">
 | |
|                     <div class="col-sm-12 small text-warning">
 | |
|                       <div ng-messages="kubernetesApplicationCreationForm.memory_limit.$error">
 | |
|                         <p
 | |
|                           ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Value must be between {{ ctrl.state.sliders.memory.min }} and
 | |
|                           {{ ctrl.state.sliders.memory.max }}
 | |
|                         </p>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- !memory-limit-input -->
 | |
|                   <!-- cpu-limit-input -->
 | |
|                   <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
 | |
|                         message="'An instance of this application will reserve this amount of CPU. If the instance CPU usage exceeds the reservation, it might be subject to CPU throttling.'"
 | |
|                       >
 | |
|                       </portainer-tooltip>
 | |
|                     </label>
 | |
|                     <div class="col-sm-5">
 | |
|                       <slider model="ctrl.formValues.CpuLimit" floor="ctrl.state.sliders.cpu.min" ceil="ctrl.state.sliders.cpu.max" step="0.10" precision="2"></slider>
 | |
|                     </div>
 | |
|                     <div class="col-sm-4" style="margin-top: 20px">
 | |
|                       <p class="small text-muted"> Maximum CPU usage </p>
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.nodeLimitsOverflow()">
 | |
|                     <div class="col-sm-12 small text-danger">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
 | |
|                       These reservations would exceed the resources currently available in the cluster.
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- !cpu-limit-input -->
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <div class="col-sm-12 form-section-title"> Deployment </div>
 | |
|                   <!-- #region DEPLOYMENT -->
 | |
|                   <div class="form-group">
 | |
|                     <div class="col-sm-12 small text-muted"> Select how you want to deploy your application inside the cluster. </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <!-- deployment options -->
 | |
|                   <div class="form-group" style="margin-bottom: 0">
 | |
|                     <div class="boxselector_wrapper">
 | |
|                       <div>
 | |
|                         <input
 | |
|                           type="radio"
 | |
|                           id="deployment_replicated"
 | |
|                           ng-value="ctrl.ApplicationDeploymentTypes.REPLICATED"
 | |
|                           ng-model="ctrl.formValues.DeploymentType"
 | |
|                           data-cy="k8sAppCreate-replicatedDeploymentButton"
 | |
|                         />
 | |
|                         <label for="deployment_replicated">
 | |
|                           <div class="boxselector_header">
 | |
|                             <pr-icon icon="'sliders'" feather="true"></pr-icon>
 | |
|                             Replicated
 | |
|                           </div>
 | |
|                           <p>Run one or multiple instances of this container</p>
 | |
|                         </label>
 | |
|                       </div>
 | |
|                       <div style="color: #767676" ng-if="!ctrl.supportGlobalDeployment()">
 | |
|                         <input type="radio" id="deployment_global" disabled />
 | |
|                         <label
 | |
|                           for="deployment_global"
 | |
|                           tooltip-append-to-body="true"
 | |
|                           tooltip-placement="bottom"
 | |
|                           tooltip-class="portainer-tooltip"
 | |
|                           uib-tooltip="The storage or access policy used for persisted folders cannot be used with this option"
 | |
|                           style="cursor: pointer; border-color: #767676"
 | |
|                         >
 | |
|                           <div class="boxselector_header">
 | |
|                             <i class="fa fa-cubes" aria-hidden="true" style="margin-right: 2px"></i>
 | |
|                             Global
 | |
|                           </div>
 | |
|                           <p>Application will be deployed as a DaemonSet with an instance on each node of the cluster</p>
 | |
|                         </label>
 | |
|                       </div>
 | |
|                       <div ng-if="ctrl.supportGlobalDeployment()">
 | |
|                         <input
 | |
|                           type="radio"
 | |
|                           id="deployment_global"
 | |
|                           ng-value="ctrl.ApplicationDeploymentTypes.GLOBAL"
 | |
|                           ng-model="ctrl.formValues.DeploymentType"
 | |
|                           ng-click="ctrl.unselectAutoScaler()"
 | |
|                           data-cy="k8sAppCreate-globalDeployButton"
 | |
|                         />
 | |
|                         <label for="deployment_global">
 | |
|                           <div class="boxselector_header">
 | |
|                             <i class="fa fa-cubes" aria-hidden="true" style="margin-right: 2px"></i>
 | |
|                             Global
 | |
|                           </div>
 | |
|                           <p>Application will be deployed as a DaemonSet with an instance on each node of the cluster</p>
 | |
|                         </label>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- !deployment options -->
 | |
| 
 | |
|                   <!-- replica count -->
 | |
|                   <div class="form-group form-inline" ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED">
 | |
|                     <div class="col-sm-12">
 | |
|                       <label class="control-label text-left"> Instance count </label>
 | |
|                       <input
 | |
|                         type="number"
 | |
|                         name="replica_count"
 | |
|                         class="form-control"
 | |
|                         min="1"
 | |
|                         max="9999"
 | |
|                         placeholder="1"
 | |
|                         style="margin-left: 20px"
 | |
|                         ng-model="ctrl.formValues.ReplicaCount"
 | |
|                         ng-disabled="!ctrl.supportScalableReplicaDeployment()"
 | |
|                         ng-change="ctrl.enforceReplicaCountMinimum()"
 | |
|                         required
 | |
|                         data-cy="k8sAppCreate-replicaCountInput"
 | |
|                       />
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <div class="form-group" ng-if="kubernetesApplicationCreationForm['replica_count'].$invalid">
 | |
|                     <div class="col-sm-12 small">
 | |
|                       <ng-messages for="kubernetesApplicationCreationForm['replica_count'].$error">
 | |
|                         <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Instance count is required.</p>
 | |
|                         <p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Instance count must be greater than 0.</p>
 | |
|                       </ng-messages>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- !replica count -->
 | |
| 
 | |
|                   <div
 | |
|                     class="form-group"
 | |
|                     ng-if="!ctrl.resourceReservationsOverflow() && ctrl.formValues.ReplicaCount > 1 && (ctrl.formValues.CpuLimit !== 0 || ctrl.formValues.MemoryLimit !== 0)"
 | |
|                   >
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                       This application will reserve the following resources:
 | |
|                       <b>{{ ctrl.formValues.CpuLimit * ctrl.formValues.ReplicaCount | kubernetesApplicationCPUValue }} CPU</b> and
 | |
|                       <b>{{ ctrl.formValues.MemoryLimit * ctrl.formValues.ReplicaCount }} MB</b> of memory.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.resourceReservationsOverflow()">
 | |
|                     <div class="col-sm-12 small">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
 | |
|                       This application would exceed available resources. Please review resource reservations or the instance count.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.state.storages.quotaExceeded">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                       This application would exceed available storage. Please review the persisted folders or the instance count.
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="!ctrl.supportScalableReplicaDeployment()">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                       The following storage option(s) do not support concurrent access from multiples instances: <code>{{ ctrl.getNonScalableStorage() }}</code
 | |
|                       >. You will not be able to scale that application.
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <!-- #region AUTO SCALING -->
 | |
|                   <div class="col-sm-12 form-section-title" ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL"> Auto-scaling </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && ctrl.state.useServerMetrics">
 | |
|                     <div class="col-sm-12">
 | |
|                       <label for="enable_auto_scaling" class="control-label text-left"> Enable auto scaling for this application </label>
 | |
|                       <label class="switch" style="margin-left: 20px">
 | |
|                         <input
 | |
|                           type="checkbox"
 | |
|                           class="form-control"
 | |
|                           name="enable_auto_scaling"
 | |
|                           ng-model="ctrl.formValues.AutoScaler.IsUsed"
 | |
|                           data-cy="k8sAppCreate-autoScaleCheckbox"
 | |
|                         />
 | |
|                         <i></i>
 | |
|                       </label>
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-group" ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && !ctrl.state.useServerMetrics">
 | |
|                     <div class="col-sm-12 small text-muted">
 | |
|                       <p ng-if="!ctrl.isAdmin"> This feature is currently disabled and must be enabled by an administrator user. </p>
 | |
|                       <p ng-if="ctrl.isAdmin">
 | |
|                         Server metrics features must be enabled in the
 | |
|                         <a ui-sref="kubernetes.cluster.setup" class="ctrl.isAdmin">environment configuration view</a>.
 | |
|                       </p>
 | |
|                     </div>
 | |
|                   </div>
 | |
| 
 | |
|                   <div class="form-inline" ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && ctrl.formValues.AutoScaler.IsUsed">
 | |
|                     <table class="table" style="margin-bottom: 0px">
 | |
|                       <tbody>
 | |
|                         <tr class="small">
 | |
|                           <td style="width: 33%; border: none; padding: 2px 0 2px 0">Minimum instances</td>
 | |
|                           <td style="width: 33%; border: none; padding: 2px 0 2px 0">Maximum instances</td>
 | |
|                           <td style="width: 33%; border: none; padding: 2px 0 2px 0">
 | |
|                             Target CPU usage (<b>%</b>)
 | |
|                             <portainer-tooltip message="'The autoscaler will ensure enough instances are running to maintain an average CPU usage across all instances.'">
 | |
|                             </portainer-tooltip>
 | |
|                           </td>
 | |
|                         </tr>
 | |
|                         <tr>
 | |
|                           <td style="padding: 8px 5px 5px 0; border: none">
 | |
|                             <div class="input-group input-group-sm" style="width: 100%">
 | |
|                               <input
 | |
|                                 type="number"
 | |
|                                 class="form-control"
 | |
|                                 name="auto_scaler_min"
 | |
|                                 min="0"
 | |
|                                 ng-max="ctrl.formValues.AutoScaler.MaxReplicas"
 | |
|                                 ng-model="ctrl.formValues.AutoScaler.MinReplicas"
 | |
|                                 data-cy="k8sAppCreate-autoScaleMin"
 | |
|                                 required
 | |
|                               />
 | |
|                             </div>
 | |
|                             <div class="input-group input-group-sm" ng-show="kubernetesApplicationCreationForm['auto_scaler_min'].$invalid">
 | |
|                               <div class="small text-warning" style="margin-top: 5px">
 | |
|                                 <ng-messages for="kubernetesApplicationCreationForm['auto_scaler_min'].$error">
 | |
|                                   <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Minimum instances is required.</p>
 | |
|                                   <p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Minimum instances must be greater than 0.</p>
 | |
|                                   <p ng-message="max"
 | |
|                                     ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Minimum instances must be smaller than maximum instances.</p
 | |
|                                   >
 | |
|                                 </ng-messages>
 | |
|                               </div>
 | |
|                             </div>
 | |
|                           </td>
 | |
|                           <td style="padding: 8px 5px 5px 0; border: none">
 | |
|                             <div class="input-group input-group-sm" style="width: 100%">
 | |
|                               <input
 | |
|                                 type="number"
 | |
|                                 class="form-control"
 | |
|                                 name="auto_scaler_max"
 | |
|                                 ng-min="ctrl.formValues.AutoScaler.MinReplicas"
 | |
|                                 ng-model="ctrl.formValues.AutoScaler.MaxReplicas"
 | |
|                               />
 | |
|                             </div>
 | |
|                             <div class="input-group input-group-sm" ng-show="kubernetesApplicationCreationForm['auto_scaler_max'].$invalid || ctrl.autoScalerOverflow()">
 | |
|                               <div class="small text-warning" style="margin-top: 5px">
 | |
|                                 <ng-messages for="kubernetesApplicationCreationForm['auto_scaler_max'].$error">
 | |
|                                   <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Maximum instances is required.</p>
 | |
|                                   <p ng-message="min"
 | |
|                                     ><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Maximum instances must be greater than minimum instances.</p
 | |
|                                   >
 | |
|                                 </ng-messages>
 | |
|                               </div>
 | |
|                             </div>
 | |
|                           </td>
 | |
|                           <td style="padding: 8px 5px 5px 0; border: none">
 | |
|                             <div class="input-group input-group-sm" style="width: 100%">
 | |
|                               <input
 | |
|                                 type="number"
 | |
|                                 class="form-control"
 | |
|                                 name="auto_scaler_cpu"
 | |
|                                 ng-model="ctrl.formValues.AutoScaler.TargetCPUUtilization"
 | |
|                                 min="1"
 | |
|                                 max="100"
 | |
|                                 required
 | |
|                                 data-cy="k8sAppCreate-targetCPUInput"
 | |
|                               />
 | |
|                             </div>
 | |
|                             <div class="input-group input-group-sm" ng-show="kubernetesApplicationCreationForm['auto_scaler_cpu'].$invalid">
 | |
|                               <div class="small text-warning" style="margin-top: 5px">
 | |
|                                 <ng-messages for="kubernetesApplicationCreationForm['auto_scaler_cpu'].$error">
 | |
|                                   <p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Target CPU usage is required.</p>
 | |
|                                   <p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Target CPU usage must be greater than 0.</p>
 | |
|                                   <p ng-message="max"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Target CPU usage must be smaller than 100.</p>
 | |
|                                 </ng-messages>
 | |
|                               </div>
 | |
|                             </div>
 | |
|                           </td>
 | |
|                         </tr>
 | |
|                       </tbody>
 | |
|                     </table>
 | |
| 
 | |
|                     <div class="form-group" ng-if="ctrl.autoScalerOverflow()" style="margin-bottom: 10px">
 | |
|                       <div class="col-sm-12 small text-danger">
 | |
|                         <pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
 | |
|                         This application would exceed available resources. Please review resource reservations or the maximum instance count of the auto-scaling policy.
 | |
|                       </div>
 | |
|                     </div>
 | |
|                   </div>
 | |
|                   <!-- #endregion -->
 | |
| 
 | |
|                   <div ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED">
 | |
|                     <div class="col-sm-12 form-section-title"> Placement preferences and constraints </div>
 | |
| 
 | |
|                     <!-- #region PLACEMENTS -->
 | |
|                     <div class="form-group">
 | |
|                       <div class="col-sm-12">
 | |
|                         <label class="control-label text-left">Placement rules</label>
 | |
|                         <span class="label label-default interactive vertical-center" style="margin-left: 10px" ng-click="ctrl.addPlacement()">
 | |
|                           <pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> add rule
 | |
|                         </span>
 | |
|                       </div>
 | |
| 
 | |
|                       <div class="col-sm-12 small text-muted" ng-if="ctrl.formValues.Placements.length > 0" style="margin-top: 10px">
 | |
|                         <pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
 | |
|                         Deploy this application on nodes that respect <b>ALL</b> of the following placement rules. Placement rules are based on node labels.
 | |
|                       </div>
 | |
| 
 | |
|                       <div class="col-sm-12 form-inline" style="margin-top: 10px">
 | |
|                         <div ng-repeat-start="placement in ctrl.formValues.Placements" style="margin-top: 2px">
 | |
|                           <div class="col-sm-5 input-group" ng-class="{ striked: placement.NeedsDeletion }">
 | |
|                             <select
 | |
|                               class="form-control"
 | |
|                               ng-model="placement.Label"
 | |
|                               ng-options="label as (label.Key | kubernetesNodeLabelHumanReadbleText) for label in ctrl.nodesLabels"
 | |
|                               ng-change="ctrl.onChangePlacementLabel($index)"
 | |
|                               ng-disabled="ctrl.isEditAndNotNewPlacement($index)"
 | |
|                               data-cy="k8sAppCreate-placementLabel_{{ $index }}"
 | |
|                             >
 | |
|                             </select>
 | |
|                           </div>
 | |
|                           <div class="col-sm-5 input-group" ng-class="{ striked: placement.NeedsDeletion }">
 | |
|                             <select
 | |
|                               class="form-control"
 | |
|                               ng-model="placement.Value"
 | |
|                               ng-options="value for value in placement.Label.Values"
 | |
|                               ng-disabled="ctrl.isEditAndNotNewPlacement($index)"
 | |
|                               data-cy="k8sAppCreate-placementName_{{ $index }}"
 | |
|                             >
 | |
|                             </select>
 | |
|                           </div>
 | |
| 
 | |
|                           <div class="col-sm-1 input-group">
 | |
|                             <button
 | |
|                               ng-if="!placement.NeedsDeletion"
 | |
|                               class="btn btn-sm btn-light btn-only-icon"
 | |
|                               type="button"
 | |
|                               ng-click="ctrl.removePlacement($index)"
 | |
|                               data-cy="k8sAppCreate-deletePlacementButton"
 | |
|                             >
 | |
|                               <pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon>
 | |
|                             </button>
 | |
|                             <button
 | |
|                               ng-if="placement.NeedsDeletion"
 | |
|                               class="btn btn-sm btn-light btn-only-icon"
 | |
|                               type="button"
 | |
|                               ng-click="ctrl.restorePlacement($index)"
 | |
|                               data-cy="k8sAppCreate-restorePlacementButton"
 | |
|                             >
 | |
|                               <pr-icon icon="'rotate-cw'" size="'md'" feather="true"></pr-icon>
 | |
|                             </button>
 | |
|                           </div>
 | |
|                         </div>
 | |
|                         <div ng-repeat-end ng-show="ctrl.state.duplicates.placements.refs[$index] !== undefined">
 | |
|                           <div class="col-sm-5 input-group">
 | |
|                             <div class="small text-warning" style="margin-top: 5px" ng-if="ctrl.state.duplicates.placements.refs[$index] !== undefined">
 | |
|                               <p ng-if="ctrl.state.duplicates.placements.refs[$index] !== undefined">
 | |
|                                 <pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This label is already defined.
 | |
|                               </p>
 | |
|                             </div>
 | |
|                           </div>
 | |
|                         </div>
 | |
|                       </div>
 | |
|                     </div>
 | |
|                     <div ng-if="ctrl.showPlacementPolicySection()">
 | |
|                       <div class="form-group">
 | |
|                         <div class="col-sm-12">
 | |
|                           <label class="control-label text-left">Placement policy</label>
 | |
|                         </div>
 | |
|                       </div>
 | |
| 
 | |
|                       <div class="form-group">
 | |
|                         <div class="col-sm-12 small text-muted"> Specify the policy associated to the placement rules. </div>
 | |
|                       </div>
 | |
| 
 | |
|                       <!-- placement policy options -->
 | |
|                       <div class="form-group" style="margin-bottom: 0" ng-if="ctrl.formValues.Placements.length">
 | |
|                         <div class="boxselector_wrapper">
 | |
|                           <div>
 | |
|                             <input
 | |
|                               type="radio"
 | |
|                               id="placement_hard"
 | |
|                               ng-value="ctrl.ApplicationPlacementTypes.MANDATORY"
 | |
|                               ng-model="ctrl.formValues.PlacementType"
 | |
|                               data-cy="k8sAppCreate-mandatoryPlacementButton"
 | |
|                             />
 | |
|                             <label for="placement_hard">
 | |
|                               <div class="boxselector_header">
 | |
|                                 <pr-icon icon="'sliders'" feather="true"></pr-icon>
 | |
|                                 Mandatory
 | |
|                               </div>
 | |
|                               <p>Schedule this application <b>ONLY</b> on nodes that match <b>ALL</b> Rules</p>
 | |
|                             </label>
 | |
|                           </div>
 | |
|                           <div>
 | |
|                             <input
 | |
|                               type="radio"
 | |
|                               id="placement_soft"
 | |
|                               ng-value="ctrl.ApplicationPlacementTypes.PREFERRED"
 | |
|                               ng-model="ctrl.formValues.PlacementType"
 | |
|                               data-cy="k8sAppCreate-prefferedPlacementButton"
 | |
|                             />
 | |
|                             <label for="placement_soft">
 | |
|                               <div class="boxselector_header">
 | |
|                                 <pr-icon icon="'align-justify'" feather="true"></pr-icon>
 | |
|                                 Preferred
 | |
|                               </div>
 | |
|                               <p>Schedule this application on nodes that match the rules if possible</p>
 | |
|                             </label>
 | |
|                           </div>
 | |
|                         </div>
 | |
|                       </div>
 | |
|                       <!-- !placement policy options -->
 | |
|                     </div>
 | |
|                     <!-- #endregion -->
 | |
|                   </div>
 | |
| 
 | |
|                   <!-- kubernetes services options -->
 | |
|                   <kube-services-view form-values="ctrl.formValues" is-edit="ctrl.state.isEdit" loadbalancer-enabled="ctrl.publishViaLoadBalancerEnabled()"></kube-services-view>
 | |
|                   <!-- kubernetes services options -->
 | |
| 
 | |
|                   <!-- summary -->
 | |
|                   <kubernetes-summary-view
 | |
|                     ng-if="!(!kubernetesApplicationCreationForm.$valid || ctrl.isDeployUpdateButtonDisabled() || !ctrl.state.pullImageValidity)"
 | |
|                     form-values="ctrl.formValues"
 | |
|                     old-form-values="ctrl.savedFormValues"
 | |
|                   ></kubernetes-summary-view>
 | |
|                 </div>
 | |
|               </div>
 | |
|             </div>
 | |
|             <div ng-if="ctrl.isExternalApplication()">
 | |
|               <div class="col-sm-12 form-section-title" ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"> Namespace </div>
 | |
|               <!-- #region NAMESPACE -->
 | |
|               <div class="form-group" ng-if="ctrl.formValues.ResourcePool">
 | |
|                 <label for="resource-pool-selector" class="col-sm-1 control-label text-left">Namespace</label>
 | |
|                 <div class="col-sm-11">
 | |
|                   <select
 | |
|                     class="form-control"
 | |
|                     id="resource-pool-selector"
 | |
|                     ng-model="ctrl.formValues.ResourcePool"
 | |
|                     ng-options="resourcePool.Namespace.Name for resourcePool in ctrl.resourcePools"
 | |
|                     ng-change="ctrl.onResourcePoolSelectionChange()"
 | |
|                     ng-disabled="ctrl.state.isEdit"
 | |
|                     data-cy="k8sAppCreate-nsSelect"
 | |
|                   ></select>
 | |
|                 </div>
 | |
|               </div>
 | |
|               <div class="form-group" ng-if="ctrl.state.resourcePoolHasQuota && ctrl.resourceQuotaCapacityExceeded() && ctrl.formValues.ResourcePool">
 | |
|                 <div class="col-sm-12 small text-danger">
 | |
|                   <pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
 | |
|                   This namespace has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of the
 | |
|                   namespace.
 | |
|                 </div>
 | |
|               </div>
 | |
|               <div class="form-group" ng-if="!ctrl.formValues.ResourcePool">
 | |
|                 <div class="col-sm-12 small text-muted">
 | |
|                   <pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
 | |
|                   You do not have access to any namespace. Contact your administrator to get access to a namespace.
 | |
|                 </div>
 | |
|               </div>
 | |
|               <!-- kubernetes services options -->
 | |
|               <kube-services-view form-values="ctrl.formValues" is-edit="ctrl.state.isEdit" loadbalancer-enabled="ctrl.publishViaLoadBalancerEnabled()"></kube-services-view>
 | |
|               <!-- kubernetes services options -->
 | |
|             </div>
 | |
| 
 | |
|             <!-- kubernetes summary for external application -->
 | |
|             <kubernetes-summary-view ng-if="ctrl.isExternalApplication()" form-values="ctrl.formValues" old-form-values="ctrl.savedFormValues"></kubernetes-summary-view>
 | |
|             <!-- kubernetes summary for external application -->
 | |
|             <div class="col-sm-12 form-section-title" ng-if="ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.GIT"> Actions </div>
 | |
|             <!-- #region ACTIONS -->
 | |
|             <div class="form-group">
 | |
|               <div class="col-sm-12">
 | |
|                 <button
 | |
|                   ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"
 | |
|                   type="button"
 | |
|                   class="btn btn-primary btn-sm"
 | |
|                   ng-disabled="!kubernetesApplicationCreationForm.$valid || ctrl.isDeployUpdateButtonDisabled() || !ctrl.imageValidityIsValid()"
 | |
|                   ng-click="ctrl.deployApplication()"
 | |
|                   button-spinner="ctrl.state.actionInProgress"
 | |
|                   data-cy="k8sAppCreate-deployButton"
 | |
|                 >
 | |
|                   <span ng-show="!ctrl.state.isEdit && !ctrl.state.actionInProgress">Deploy application</span>
 | |
|                   <span ng-show="!ctrl.state.isEdit && ctrl.state.actionInProgress">Deployment in progress...</span>
 | |
|                   <span ng-show="ctrl.state.isEdit && !ctrl.state.actionInProgress">Update application</span>
 | |
|                   <span ng-show="ctrl.state.isEdit && ctrl.state.actionInProgress">Update in progress...</span>
 | |
|                 </button>
 | |
|                 <button
 | |
|                   ng-if="ctrl.state.isEdit && !ctrl.state.actionInProgress && ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"
 | |
|                   type="button"
 | |
|                   class="btn btn-sm btn-default"
 | |
|                   ui-sref="kubernetes.applications.application({ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool })"
 | |
|                   data-cy="k8sAppCreate-appCancelButton"
 | |
|                 >
 | |
|                   Cancel
 | |
|                 </button>
 | |
|                 <!-- #Web editor buttons -->
 | |
|                 <button
 | |
|                   class="btn btn-sm btn-primary"
 | |
|                   ng-click="ctrl.updateApplicationViaWebEditor()"
 | |
|                   ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.CONTENT || ctrl.state.updateWebEditorInProgress"
 | |
|                   ng-disabled="!kubernetesApplicationCreationForm.$valid || !ctrl.state.isEditorDirty || ctrl.state.updateWebEditorInProgress"
 | |
|                   style="margin-top: 7px; margin-left: 0"
 | |
|                   button-spinner="ctrl.state.updateWebEditorInProgress"
 | |
|                 >
 | |
|                   <span ng-show="!ctrl.state.updateWebEditorInProgress">Update the application</span>
 | |
|                   <span ng-show="ctrl.state.updateWebEditorInProgress">Update in progress...</span>
 | |
|                 </button>
 | |
|               </div>
 | |
|             </div>
 | |
|             <!-- #endregion -->
 | |
|           </form>
 | |
|         </rd-widget-body>
 | |
|       </rd-widget>
 | |
|     </div>
 | |
|   </div>
 | |
| </div>
 |