mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 07:49:41 +02:00
feat(k8s): Allow mix services for k8s app EE-1791 (#6198)
allow a mix of services for k8s in ui
This commit is contained in:
parent
edf048570b
commit
c47e840b37
26 changed files with 2336 additions and 1863 deletions
|
@ -166,7 +166,7 @@
|
|||
Status
|
||||
</th>
|
||||
<th>
|
||||
Publishing mode
|
||||
Published
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('CreationDate')">
|
||||
|
@ -233,15 +233,9 @@
|
|||
{{ item.Pods[0].Status }}
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="item.PublishedPorts.length">
|
||||
<span>
|
||||
<a ng-click="$ctrl.onPublishingModeClick(item); $event.stopPropagation()">
|
||||
<i class="fa {{ item.ServiceType | kubernetesApplicationServiceTypeIcon }}" aria-hidden="true" style="margin-right: 2px;"> </i>
|
||||
{{ item.ServiceType | kubernetesApplicationServiceTypeText }}
|
||||
</a>
|
||||
</span>
|
||||
<span>
|
||||
{{ item.Services.length === 0 ? 'No' : 'Yes' }}
|
||||
</span>
|
||||
<span ng-if="item.PublishedPorts.length === 0">-</span>
|
||||
</td>
|
||||
<td>{{ item.CreationDate | getisodate }} {{ item.ApplicationOwner ? 'by ' + item.ApplicationOwner : '' }}</td>
|
||||
</tr>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
import _ from 'lodash-es';
|
||||
import { KubernetesServicePort, KubernetesIngressServiceRoute } from 'Kubernetes/models/service/models';
|
||||
import { KubernetesFormValidationReferences } from 'Kubernetes/models/application/formValues';
|
||||
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper';
|
||||
import { KubernetesApplicationPublishingTypes } from 'Kubernetes/models/application/models/constants';
|
||||
|
||||
export default class KubeServicesItemViewController {
|
||||
/* @ngInject */
|
||||
constructor(EndpointProvider, Authentication) {
|
||||
this.EndpointProvider = EndpointProvider;
|
||||
this.Authentication = Authentication;
|
||||
}
|
||||
|
||||
addPort() {
|
||||
const p = new KubernetesServicePort();
|
||||
p.nodePort = '';
|
||||
p.port = '';
|
||||
p.targetPort = '';
|
||||
p.protocol = 'TCP';
|
||||
|
||||
if (this.ingressType) {
|
||||
const r = new KubernetesIngressServiceRoute();
|
||||
r.ServiceName = this.serviceName;
|
||||
p.ingress = r;
|
||||
p.Ingress = true;
|
||||
}
|
||||
this.servicePorts.push(p);
|
||||
}
|
||||
|
||||
removePort(index) {
|
||||
this.servicePorts.splice(index, 1);
|
||||
}
|
||||
|
||||
servicePort(index) {
|
||||
const targetPort = this.servicePorts[index].targetPort;
|
||||
this.servicePorts[index].port = targetPort;
|
||||
}
|
||||
|
||||
isAdmin() {
|
||||
return this.Authentication.isAdmin();
|
||||
}
|
||||
|
||||
onChangeContainerPort() {
|
||||
const state = this.state.duplicates.targetPort;
|
||||
const source = _.map(this.servicePorts, (sp) => sp.targetPort);
|
||||
const duplicates = KubernetesFormValidationHelper.getDuplicates(source);
|
||||
state.refs = duplicates;
|
||||
state.hasRefs = Object.keys(duplicates).length > 0;
|
||||
}
|
||||
|
||||
onChangeServicePort() {
|
||||
const state = this.state.duplicates.servicePort;
|
||||
const source = _.map(this.servicePorts, (sp) => sp.port);
|
||||
const duplicates = KubernetesFormValidationHelper.getDuplicates(source);
|
||||
state.refs = duplicates;
|
||||
state.hasRefs = Object.keys(duplicates).length > 0;
|
||||
}
|
||||
|
||||
onChangeNodePort() {
|
||||
const state = this.state.duplicates.nodePort;
|
||||
const source = _.map(this.servicePorts, (sp) => sp.nodePort);
|
||||
const duplicates = KubernetesFormValidationHelper.getDuplicates(source);
|
||||
state.refs = duplicates;
|
||||
state.hasRefs = Object.keys(duplicates).length > 0;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.servicePorts.length === 0) {
|
||||
this.addPort();
|
||||
}
|
||||
|
||||
this.KubernetesApplicationPublishingTypes = KubernetesApplicationPublishingTypes;
|
||||
|
||||
this.state = {
|
||||
duplicates: {
|
||||
targetPort: new KubernetesFormValidationReferences(),
|
||||
servicePort: new KubernetesFormValidationReferences(),
|
||||
nodePort: new KubernetesFormValidationReferences(),
|
||||
},
|
||||
endpointId: this.EndpointProvider.endpointID(),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
<form name="serviceForm">
|
||||
<div ng-if="$ctrl.isAdmin()" class="small text-warning" ng-show="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled">
|
||||
<p style="margin-top: 10px">
|
||||
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> No Load balancer is available in this cluster, click
|
||||
<a ui-sref="portainer.k8sendpoint.kubernetesConfig({id: $ctrl.state.endpointId})">here</a> to configure load balancer.
|
||||
</p>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin()" class="small text-warning" ng-show="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled">
|
||||
<p style="margin-top: 10px"> <i class="fa fa-exclamation-circle" aria-hidden="true"></i> No Load balancer is available in this cluster, contract your administrator. </p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ng-if="
|
||||
($ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && $ctrl.loadbalancerEnabled) ||
|
||||
$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP ||
|
||||
$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.NODE_PORT
|
||||
"
|
||||
>
|
||||
<div ng-show="!$ctrl.multiItemDisable" style="margin-top: 5px; margin-bottom: 5px">
|
||||
<label class="control-label text-left">Published ports</label>
|
||||
<span class="label label-default interactive" style="margin-left: 10px" ng-click="$ctrl.addPort()" data-cy="k8sAppCreate-addNewPortButton">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> publish a new port
|
||||
</span>
|
||||
</div>
|
||||
<div ng-repeat="servicePort in $ctrl.servicePorts" style="margin-top: 10px">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">container port</span>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="container_port_{{ $index }}"
|
||||
ng-model="servicePort.targetPort"
|
||||
placeholder="80"
|
||||
ng-min="1"
|
||||
ng-max="65535"
|
||||
ng-change="$ctrl.servicePort($index)"
|
||||
required
|
||||
ng-disabled="$ctrl.originalIngresses.length === 0 || ($ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled)"
|
||||
ng-change="$ctrl.onChangeContainerPort()"
|
||||
data-cy="k8sAppCreate-containerPort_{{ $index }}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">service port</span>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="service_port_{{ $index }}"
|
||||
ng-model="servicePort.port"
|
||||
placeholder="80"
|
||||
ng-min="1"
|
||||
ng-max="65535"
|
||||
required
|
||||
ng-disabled="$ctrl.originalIngresses.length === 0 || ($ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled)"
|
||||
ng-change="$ctrl.onChangeServicePort()"
|
||||
data-cy="k8sAppCreate-servicePort_{{ $index }}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.NODE_PORT" class="input-group input-group-sm">
|
||||
<span class="input-group-addon">nodeport</span>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="node_port_{{ $index }}"
|
||||
ng-model="servicePort.nodePort"
|
||||
placeholder="30080"
|
||||
ng-min="30000"
|
||||
ng-max="32767"
|
||||
ng-change="$ctrl.onChangeNodePort()"
|
||||
data-cy="k8sAppCreate-nodeportPort_{{ $index }}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER" class="input-group input-group-sm">
|
||||
<span class="input-group-addon">loadbalancer port</span>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="loadbalancer_port_{{ $index }}"
|
||||
ng-model="servicePort.port"
|
||||
placeholder="80"
|
||||
ng-min="1"
|
||||
ng-max="65535"
|
||||
required
|
||||
ng-disabled="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled"
|
||||
data-cy="k8sAppCreate-loadbalancerPort_{{ $index }}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP && $ctrl.ingressType" class="input-group input-group-sm">
|
||||
<span class="input-group-addon">ingress</span>
|
||||
<select
|
||||
ng-init="servicePort.ingress.IngressName = $ctrl.originalIngresses[0].Name"
|
||||
class="form-control"
|
||||
name="ingress_port_{{ $index }}"
|
||||
ng-model="servicePort.ingress.IngressName"
|
||||
required
|
||||
ng-disabled="$ctrl.originalIngresses.length === 0"
|
||||
ng-options="ingress.Name as ingress.Name for ingress in $ctrl.originalIngresses"
|
||||
data-cy="k8sAppCreate-ingressPort_{{ $index }}"
|
||||
>
|
||||
<option selected disabled hidden value="">Select an ingress</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP && $ctrl.ingressType" class="input-group input-group-sm">
|
||||
<span class="input-group-addon">hostname</span>
|
||||
<select
|
||||
ng-init="servicePort.ingress.Host = $ctrl.originalIngresses[0].Hosts"
|
||||
class="form-control"
|
||||
name="hostname_port_{{ $index }}"
|
||||
ng-model="servicePort.ingress.Host"
|
||||
required
|
||||
ng-disabled="$ctrl.originalIngresses.length === 0"
|
||||
ng-options="ingress.Hosts as ingress.Hosts for ingress in $ctrl.originalIngresses"
|
||||
data-cy="k8sAppCreate-hostnamePort_{{ $index }}"
|
||||
>
|
||||
<option selected disabled hidden value="">Select a hostname</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP && $ctrl.ingressType" class="input-group input-group-sm">
|
||||
<span class="input-group-addon">route</span>
|
||||
<input
|
||||
class="form-control"
|
||||
name="ingress_route_{{ $index }}"
|
||||
ng-model="servicePort.ingress.Path"
|
||||
placeholder="route"
|
||||
required
|
||||
ng-disabled="$ctrl.originalIngresses.length === 0"
|
||||
ng-pattern="/^(\/?[a-zA-Z0-9]+([a-zA-Z0-9-/_]*[a-zA-Z0-9])?|[a-zA-Z0-9]+)|(\/){1}$/"
|
||||
data-cy="k8sAppCreate-route_{{ $index }}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="input-group col-sm-2 input-group-sm">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<label
|
||||
class="btn btn-primary"
|
||||
ng-model="servicePort.protocol"
|
||||
uib-btn-radio="'TCP'"
|
||||
ng-change="ctrl.onChangePortProtocol($index)"
|
||||
ng-disabled="ctrl.isProtocolOptionDisabled($index, 'TCP')"
|
||||
data-cy="k8sAppCreate-TCPButton_{{ $index }}"
|
||||
>TCP</label
|
||||
>
|
||||
<label
|
||||
class="btn btn-primary"
|
||||
ng-model="servicePort.protocol"
|
||||
uib-btn-radio="'UDP'"
|
||||
ng-change="ctrl.onChangePortProtocol($index)"
|
||||
ng-disabled="ctrl.isProtocolOptionDisabled($index, 'UDP')"
|
||||
data-cy="k8sAppCreate-UDPButton_{{ $index }}"
|
||||
>UDP</label
|
||||
>
|
||||
</div>
|
||||
<button
|
||||
ng-disabled="$ctrl.servicePorts.length === 1"
|
||||
ng-show="!$ctrl.multiItemDisable"
|
||||
class="btn btn-sm btn-danger"
|
||||
type="button"
|
||||
ng-click="$ctrl.removePort($index)"
|
||||
data-cy="k8sAppCreate-rmPortButton_{{ $index }}"
|
||||
>
|
||||
<i class="fa fa-trash-alt" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 input-group input-group-sm">
|
||||
<div class="col-sm-2">
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<p ng-if="$ctrl.state.duplicates.targetPort.refs[$index] !== undefined">
|
||||
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This container port is already used.
|
||||
</p>
|
||||
</div>
|
||||
<div class="small text-warning" ng-messages="serviceForm['container_port_'+$index].$error">
|
||||
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Container port number is required.</p>
|
||||
<p ng-message="min"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Container port number must be inside the range 1-65535.</p>
|
||||
<p ng-message="max"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Container port number must be inside the range 1-65535.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<p ng-if="$ctrl.state.duplicates.servicePort.refs[$index] !== undefined">
|
||||
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This service port is already used.
|
||||
</p>
|
||||
</div>
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<div ng-messages="serviceForm['service_port_'+$index].$error">
|
||||
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Service port number is required.</p>
|
||||
<p ng-message="min"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Container port number must be inside the range 1-65535.</p>
|
||||
<p ng-message="max"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Container port number must be inside the range 1-65535.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<div ng-messages="serviceForm['node_port_'+$index].$error">
|
||||
<p ng-message="min"
|
||||
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Node port number must be inside the range 30000-32767 or blank for system allocated.</p
|
||||
>
|
||||
<p ng-message="max"
|
||||
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Node port number must be inside the range 30000-32767 or blank for system allocated.</p
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<div ng-messages="serviceForm['ingress_port_'+$index].$error">
|
||||
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Ingress selection is required.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<div ng-messages="serviceForm['hostname_port_'+$index].$error">
|
||||
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Host is required.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-8" ng-show="">
|
||||
<div class="small text-warning" style="margin-top: 5px">
|
||||
<div ng-messages="serviceForm['ingress_route_'+$index].$error">
|
||||
<p ng-message="required"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Route is required.</p>
|
||||
<p ng-message="pattern"
|
||||
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This field must consist of alphanumeric characters or the special characters: '-', '_' or '/'. It
|
||||
must start and end with an alphanumeric character (e.g. 'my-route', or 'route-123').</p
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,19 @@
|
|||
import angular from 'angular';
|
||||
import controller from './kube-services-item.controller';
|
||||
|
||||
angular.module('portainer.kubernetes').component('kubeServicesItemView', {
|
||||
templateUrl: './kube-services-item.html',
|
||||
controller,
|
||||
bindings: {
|
||||
serviceType: '<',
|
||||
servicePorts: '=',
|
||||
serviceRoutes: '=',
|
||||
ingressType: '<',
|
||||
originalIngresses: '<',
|
||||
isEdit: '<',
|
||||
serviceName: '<',
|
||||
multiItemDisable: '<',
|
||||
serviceIndex: '<',
|
||||
loadbalancerEnabled: '<',
|
||||
},
|
||||
});
|
|
@ -0,0 +1,105 @@
|
|||
import { KubernetesService, KubernetesServicePort, KubernetesServiceTypes } from 'Kubernetes/models/service/models';
|
||||
import { KubernetesApplicationPublishingTypes } from 'Kubernetes/models/application/models/constants';
|
||||
|
||||
export default class KubeServicesViewController {
|
||||
/* @ngInject */
|
||||
constructor($async, EndpointProvider, Authentication) {
|
||||
this.$async = $async;
|
||||
this.EndpointProvider = EndpointProvider;
|
||||
this.Authentication = Authentication;
|
||||
}
|
||||
|
||||
addEntry(service) {
|
||||
const p = new KubernetesService();
|
||||
if (service === KubernetesApplicationPublishingTypes.INGRESS) {
|
||||
p.Type = KubernetesApplicationPublishingTypes.CLUSTER_IP;
|
||||
p.Ingress = true;
|
||||
} else {
|
||||
p.Type = service;
|
||||
}
|
||||
|
||||
p.Selector = this.formValues.Selector;
|
||||
|
||||
p.Name = this.getUniqName();
|
||||
this.state.nameIndex += 1;
|
||||
this.formValues.Services.push(p);
|
||||
}
|
||||
|
||||
getUniqName() {
|
||||
let name = this.formValues.Name + '-' + this.state.nameIndex;
|
||||
const services = this.formValues.Services;
|
||||
services.forEach((service) => {
|
||||
if (service.Name === name) {
|
||||
this.state.nameIndex += 1;
|
||||
name = this.formValues.Name + '-' + this.state.nameIndex;
|
||||
}
|
||||
});
|
||||
const UniqName = this.formValues.Name + '-' + this.state.nameIndex;
|
||||
return UniqName;
|
||||
}
|
||||
|
||||
deleteService(index) {
|
||||
this.formValues.Services.splice(index, 1);
|
||||
this.state.nameIndex -= 1;
|
||||
}
|
||||
|
||||
addPort(index) {
|
||||
const p = new KubernetesServicePort();
|
||||
this.formValues.Services[index].Ports.push(p);
|
||||
}
|
||||
|
||||
serviceType(type) {
|
||||
switch (type) {
|
||||
case KubernetesApplicationPublishingTypes.CLUSTER_IP:
|
||||
return KubernetesServiceTypes.CLUSTER_IP;
|
||||
case KubernetesApplicationPublishingTypes.NODE_PORT:
|
||||
return KubernetesServiceTypes.NODE_PORT;
|
||||
case KubernetesApplicationPublishingTypes.LOAD_BALANCER:
|
||||
return KubernetesServiceTypes.LOAD_BALANCER;
|
||||
case KubernetesApplicationPublishingTypes.INGRESS:
|
||||
return KubernetesServiceTypes.INGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
isAdmin() {
|
||||
return this.Authentication.isAdmin();
|
||||
}
|
||||
|
||||
iconStyle(type) {
|
||||
switch (type) {
|
||||
case KubernetesApplicationPublishingTypes.CLUSTER_IP:
|
||||
return 'fa fa-list-alt';
|
||||
case KubernetesApplicationPublishingTypes.NODE_PORT:
|
||||
return 'fa fa-list';
|
||||
case KubernetesApplicationPublishingTypes.LOAD_BALANCER:
|
||||
return 'fa fa-project-diagram';
|
||||
case KubernetesApplicationPublishingTypes.INGRESS:
|
||||
return 'fa fa-route';
|
||||
}
|
||||
}
|
||||
$onInit() {
|
||||
this.state = {
|
||||
serviceType: [
|
||||
{
|
||||
typeName: KubernetesServiceTypes.CLUSTER_IP,
|
||||
typeValue: KubernetesApplicationPublishingTypes.CLUSTER_IP,
|
||||
},
|
||||
{
|
||||
typeName: KubernetesServiceTypes.NODE_PORT,
|
||||
typeValue: KubernetesApplicationPublishingTypes.NODE_PORT,
|
||||
},
|
||||
{
|
||||
typeName: KubernetesServiceTypes.LOAD_BALANCER,
|
||||
typeValue: KubernetesApplicationPublishingTypes.LOAD_BALANCER,
|
||||
},
|
||||
{
|
||||
typeName: KubernetesServiceTypes.INGRESS,
|
||||
typeValue: KubernetesApplicationPublishingTypes.INGRESS,
|
||||
},
|
||||
],
|
||||
selected: KubernetesApplicationPublishingTypes.CLUSTER_IP,
|
||||
nameIndex: this.formValues.Services.length,
|
||||
endpointId: this.EndpointProvider.endpointID(),
|
||||
};
|
||||
}
|
||||
}
|
94
app/kubernetes/components/kube-services/kube-services.html
Normal file
94
app/kubernetes/components/kube-services/kube-services.html
Normal file
|
@ -0,0 +1,94 @@
|
|||
<div class="col-sm-12 form-section-title">
|
||||
Publishing the application
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 form-inline">
|
||||
<div class="col-sm-5" style="padding-left: 0px;">
|
||||
<select class="form-control" ng-model="$ctrl.state.selected" ng-options="item.typeValue as item.typeName for item in $ctrl.state.serviceType"></select>
|
||||
<button type="button" class="btn btn-sm btn-default" style="margin-left: 0;" ng-click="$ctrl.addEntry( $ctrl.state.selected )" data-cy="k8sConfigCreate-createEntryButton">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> Create service
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 form-inline" style="margin-top: 20px;" ng-repeat="service in $ctrl.formValues.Services">
|
||||
<div ng-if="!$ctrl.formValues.Services[$index].Ingress">
|
||||
<div class="text-muted">
|
||||
<i class="{{ $ctrl.iconStyle(service.Type) }}" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
{{ $ctrl.serviceType(service.Type) }}
|
||||
</div>
|
||||
<kube-services-item-view
|
||||
service-routes="$ctrl.formValues.Services[$index].IngressRoute"
|
||||
ingress-type="$ctrl.formValues.Services[$index].Ingress"
|
||||
service-type="$ctrl.formValues.Services[$index].Type"
|
||||
service-ports="$ctrl.formValues.Services[$index].Ports"
|
||||
is-edit="$ctrl.isEdit"
|
||||
loadbalancer-enabled="$ctrl.loadbalancerEnabled"
|
||||
></kube-services-item-view>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-danger space-right"
|
||||
style="margin-left: 0; margin-top: 10px;"
|
||||
ng-click="$ctrl.deleteService( $index )"
|
||||
data-cy="k8sConfigCreate-removeButton"
|
||||
>
|
||||
<i class="fa fa-trash-alt" aria-hidden="true"></i> Remove
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.formValues.Services[$index].Ingress && $ctrl.formValues.OriginalIngresses.length === 0">
|
||||
<div class="text-muted">
|
||||
<i class="fa fa-route" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Ingress
|
||||
</div>
|
||||
<div ng-if="$ctrl.isAdmin()" class="small text-warning">
|
||||
<p style="margin-top: 10px;">
|
||||
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> Ingress is not configured in this namespace, select another namespace or click
|
||||
<a ui-sref="portainer.k8sendpoint.kubernetesConfig({id: $ctrl.state.endpointId})">here</a> to configure ingress.
|
||||
</p>
|
||||
</div>
|
||||
<div ng-if="!$ctrl.isAdmin()" class="small text-warning">
|
||||
<p style="margin-top: 10px;">
|
||||
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> Ingress is not configured in this namespace, select another namespace or contact your administrator.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-danger space-right"
|
||||
style="margin-left: 0; margin-top: 10px;"
|
||||
ng-click="$ctrl.deleteService( $index )"
|
||||
data-cy="k8sConfigCreate-removeButton"
|
||||
>
|
||||
<i class="fa fa-trash-alt" aria-hidden="true"></i> Remove
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.formValues.Services[$index].Ingress && $ctrl.formValues.OriginalIngresses.length !== 0">
|
||||
<div class="text-muted">
|
||||
<i class="fa fa-route" aria-hidden="true" style="margin-right: 2px;"></i>
|
||||
Ingress
|
||||
</div>
|
||||
<kube-services-item-view
|
||||
original-ingresses="$ctrl.formValues.OriginalIngresses"
|
||||
service-routes="$ctrl.formValues.Services[$index].IngressRoute"
|
||||
ingress-type="$ctrl.formValues.Services[$index].Ingress"
|
||||
service-type="$ctrl.formValues.Services[$index].Type"
|
||||
service-ports="$ctrl.formValues.Services[$index].Ports"
|
||||
service-name="$ctrl.formValues.Services[$index].Name"
|
||||
multi-item-disable="true"
|
||||
></kube-services-item-view>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-danger space-right"
|
||||
style="margin-left: 0; margin-top: 10px;"
|
||||
ng-click="$ctrl.deleteService( $index )"
|
||||
data-cy="k8sConfigCreate-removeButton"
|
||||
>
|
||||
<i class="fa fa-trash-alt" aria-hidden="true"></i> Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
12
app/kubernetes/components/kube-services/kube-services.js
Normal file
12
app/kubernetes/components/kube-services/kube-services.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import angular from 'angular';
|
||||
import controller from './kube-services.controller';
|
||||
|
||||
angular.module('portainer.kubernetes').component('kubeServicesView', {
|
||||
templateUrl: './kube-services.html',
|
||||
controller,
|
||||
bindings: {
|
||||
formValues: '=',
|
||||
isEdit: '<',
|
||||
loadbalancerEnabled: '<',
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue