Skip to content

Commit d336956

Browse files
Ticket #38 : Support Kubernetes function
1 parent 850ff4d commit d336956

File tree

9 files changed

+157
-58
lines changed

9 files changed

+157
-58
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace FaasNet.Gateway.Core.Exceptions
4+
{
5+
public class FunctionAlreadyPublishedException : Exception
6+
{
7+
public FunctionAlreadyPublishedException(string code, string message, string functionId) : base(message)
8+
{
9+
Code = code;
10+
FunctionId = functionId;
11+
}
12+
13+
public string Code { get; set; }
14+
public string FunctionId { get; set; }
15+
}
16+
}

src/FaasNet.Gateway.Core/Functions/Commands/Handlers/PublishFunctionCommandHandler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ public PublishFunctionCommandHandler(IFunctionRepository functionRepository, IFu
2424
public async Task<string> Handle(PublishFunctionCommand command, CancellationToken cancellationToken)
2525
{
2626
var function = FunctionAggregate.Create(command.Name, command.Description, command.Image, command.Version, command.Command);
27-
if (_functionRepository.Query().FirstOrDefault(f => f.Id == function.Id) != null)
27+
var existingFunction = _functionRepository.Query().FirstOrDefault(f => f.Image == function.Image && f.Version == function.Version);
28+
if (existingFunction != null)
2829
{
29-
throw new BadRequestException(ErrorCodes.FunctionExists, string.Format(Global.FunctionExists, function.Id));
30+
throw new FunctionAlreadyPublishedException(ErrorCodes.FunctionExists, string.Format(Global.FunctionExists, $"{function.Image}:{function.Version}"), existingFunction.Id);
3031
}
3132

3233
await _functionInvoker.Publish(function.Id, function.Image, function.Version, function.Command, cancellationToken);

src/FaasNet.Gateway.Core/StateMachines/Commands/Handlers/UpdateStateMachineCommandHandler.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,15 @@ public async Task<AddStateMachineResult> Handle(UpdateStateMachineCommand reques
4040
{
4141
var image = customFunction.Metadata.SelectToken("image").ToString();
4242
var version = customFunction.Metadata.SelectToken("version").ToString();
43-
var id = await _functionService.Publish(customFunction.Name, image, version, cancellationToken);
44-
customFunction.FunctionId = id;
43+
try
44+
{
45+
var id = await _functionService.Publish(customFunction.Name, image, version, cancellationToken);
46+
customFunction.FunctionId = id;
47+
}
48+
catch (FunctionAlreadyPublishedException ex)
49+
{
50+
customFunction.FunctionId = ex.FunctionId;
51+
}
4552
}
4653

4754
workflowDefinition.IsLast = false;

src/FaasNet.Gateway.SqlServer.Startup/ServerlessWorkflows/TransformJson.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ states:
99
actions:
1010
- name: transformJson
1111
functionRef:
12-
referenceName: transform
12+
refName: transform
1313
end: true
1414
id: 9c8eeb08-3826-4a26-b11f-1e57a9dd6f97
1515
type: operation
@@ -18,8 +18,8 @@ functions:
1818
- name: transform
1919
type: custom
2020
metadata:
21-
provider: kubernetes
2221
image: localhost:5000/faastransform
22+
version: latest
2323
configuration:
2424
mappings:
2525
- input: firstName

src/FaasNet.Website/src/components/statediagram/components/functionseditor/functionseditor.component.html

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,58 @@ <h1 mat-dialog-title>Functions Editor</h1>
44
<div fxFlex="50%" class="firstColumn column">
55
<form [formGroup]="editFunctionFormGroup" (ngSubmit)="addFunction()">
66
<!-- Name -->
7-
<mat-form-field class="full-width" appearance="outline">
8-
<mat-label>{{ 'functions.name' | translate }}</mat-label>
9-
<input type="text" matInput formControlName="name" />
10-
<mat-error *ngIf="editFunctionFormGroup.get('name')?.errors?.required">{{ 'functions.nameRequired' | translate }}</mat-error>
11-
</mat-form-field>
7+
<div class="form-control">
8+
<div class="title">Name</div>
9+
<p class="description">Name of the function</p>
10+
<input type="text" formControlName="name" class="full-width" />
11+
<mat-error *ngIf="editFunctionFormGroup.get('name')?.errors?.required">Name is required</mat-error>
12+
</div>
13+
<mat-divider></mat-divider>
1214
<!-- Type -->
13-
<mat-form-field class="full-width" appearance="outline">
14-
<mat-label>{{ 'functions.type' | translate }}</mat-label>
15-
<mat-select formControlName="type">
16-
<mat-option value="rest">RESTful service invocation</mat-option>
17-
</mat-select>
15+
<div class="form-control">
16+
<div class="title">Type</div>
17+
<p class="description">Select the type of function</p>
18+
<select formControlName="type" class="full-width">
19+
<option value="rest">RESTful service invocation</option>
20+
<option value="kubernetes">Serverless function invocation</option>
21+
</select>
1822
<mat-error *ngIf="editFunctionFormGroup.get('type')?.errors?.required">{{ 'functions.typeRequired' | translate }}</mat-error>
19-
</mat-form-field>
20-
<!-- Operation -->
21-
<mat-form-field class="full-width" appearance="outline" *ngIf="editFunctionFormGroup.get('type')?.value">
22-
<mat-label>{{ getOperationTranslationKey() | translate }}</mat-label>
23-
<input type="text" matInput formControlName="operation" />
24-
</mat-form-field>
25-
<button mat-raised-button color="primary" [disabled]="!editFunctionFormGroup.valid">Add</button>
23+
</div>
24+
<div *ngIf="editFunctionFormGroup.get('type')?.value == 'rest'">
25+
<mat-divider></mat-divider>
26+
<!-- Operation -->
27+
<div class="form-control">
28+
<div class="title">Operation</div>
29+
<p class="description">{{ getOperationTranslationKey() }}</p>
30+
<input type="text" formControlName="operation" class="full-width" />
31+
</div>
32+
</div>
33+
<div *ngIf="editFunctionFormGroup.get('type')?.value == 'kubernetes'" [formGroup]="editKubernetesFormGroup">
34+
<mat-divider></mat-divider>
35+
<!-- Image -->
36+
<div class="form-control">
37+
<div class="title">Image</div>
38+
<p class="description">Docker image</p>
39+
<input type="text" formControlName="image" class="full-width" />
40+
<mat-error *ngIf="editKubernetesFormGroup.get('image')?.errors?.required">Image is required</mat-error>
41+
</div>
42+
<!-- Version -->
43+
<div class="form-control">
44+
<div class="title">Version</div>
45+
<p class="description">Docker version</p>
46+
<input type="text" formControlName="version" class="full-width" />
47+
<mat-error *ngIf="editKubernetesFormGroup.get('version')?.errors?.required">Version is required</mat-error>
48+
</div>
49+
<mat-divider></mat-divider>
50+
<!-- Configuration -->
51+
<div class="form-control">
52+
<div class="title">Configuration</div>
53+
<p class="description">Configuration passed to the serverless function</p>
54+
<input type="text" formControlName="configuration" class="full-width" />
55+
</div>
56+
</div>
57+
<mat-divider></mat-divider>
58+
<button mat-raised-button color="primary" [disabled]="!editFunctionFormGroup.valid" class="mt-10">Add</button>
2659
</form>
2760
</div>
2861
<div fxFlex="50%" class="secondColumn">
@@ -47,18 +80,11 @@ <h1 mat-dialog-title>Functions Editor</h1>
4780
</ng-container>
4881
<!-- Type -->
4982
<ng-container matColumnDef="type">
50-
<mat-header-cell *matHeaderCellDef>{{ "functions.description" | translate }}</mat-header-cell>
83+
<mat-header-cell *matHeaderCellDef>Type</mat-header-cell>
5184
<mat-cell *matCellDef="let function">
5285
{{ function.type }}
5386
</mat-cell>
5487
</ng-container>
55-
<!-- Operation -->
56-
<ng-container matColumnDef="operation">
57-
<mat-header-cell *matHeaderCellDef>{{ "functions.operation" | translate }}</mat-header-cell>
58-
<mat-cell *matCellDef="let function">
59-
{{ function.operation }}
60-
</mat-cell>
61-
</ng-container>
6288
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
6389
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
6490
</mat-table>

src/FaasNet.Website/src/components/statediagram/components/functionseditor/functionseditor.component.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ export class FunctionsEditorComponent {
2323
type: new FormControl('', [Validators.required]),
2424
operation: new FormControl(),
2525
});
26-
displayedColumns: string[] = ['actions', 'name', 'type', 'operation'];
26+
editKubernetesFormGroup: FormGroup = new FormGroup({
27+
image: new FormControl('', [Validators.required]),
28+
version: new FormControl('', [Validators.required]),
29+
configuration: new FormControl()
30+
});
31+
displayedColumns: string[] = ['actions', 'name', 'type' ];
2732

2833
constructor(
2934
@Inject(MAT_DIALOG_DATA) public data: FunctionsEditorData,
@@ -37,10 +42,30 @@ export class FunctionsEditorComponent {
3742
}
3843

3944
addFunction() {
45+
if (this.isDisabled()) {
46+
return;
47+
}
48+
4049
let record = new StateMachineFunction();
4150
record.name = this.editFunctionFormGroup.get('name')?.value;
4251
record.operation = this.editFunctionFormGroup.get('operation')?.value;
43-
record.type = this.editFunctionFormGroup.get('type')?.value;
52+
let type = this.editFunctionFormGroup.get('type')?.value;
53+
if (type === 'kubernetes') {
54+
type = 'custom';
55+
record.metadata = {
56+
version: this.editKubernetesFormGroup.get('version')?.value,
57+
image: this.editKubernetesFormGroup.get('image')?.value
58+
};
59+
var configuration = this.editKubernetesFormGroup.get('configuration')?.value;
60+
if (configuration) {
61+
try {
62+
var o = JSON.parse(configuration);
63+
record.metadata['configuration'] = o;
64+
} catch { }
65+
}
66+
}
67+
68+
record.type = type;
4469
this.functions.data.push(record);
4570
this.functions.data = this.functions.data;
4671
this.editFunctionFormGroup.reset();
@@ -50,10 +75,23 @@ export class FunctionsEditorComponent {
5075
let type = this.editFunctionFormGroup.get('type')?.value;
5176
switch (type) {
5277
case 'rest':
53-
return 'functions.openAPIOperation';
78+
return 'OPEN API url';
79+
}
80+
81+
return '';
82+
}
83+
84+
isDisabled() {
85+
if (!this.editFunctionFormGroup.valid) {
86+
return true;
87+
}
88+
89+
let type = this.editFunctionFormGroup.get('type')?.value;
90+
if (type == 'kubernetes') {
91+
return !this.editKubernetesFormGroup.valid;
5492
}
5593

56-
return 'functions.operation';
94+
return false;
5795
}
5896

5997
save() {

src/FaasNet.Website/src/components/statediagram/components/operation/actionseditor.component.html

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,46 @@ <h1 mat-dialog-title>Actions Editor</h1>
44
<div fxFlex="50%" class="firstColumn">
55
<form [formGroup]="addActionFormGroup" (ngSubmit)="addAction()">
66
<!-- Name -->
7-
<mat-form-field appearance="outline" class="full-width">
8-
<mat-label>Action name</mat-label>
9-
<input matInput formControlName="name" />
7+
<div class="form-control">
8+
<div class="title">Name</div>
9+
<p class="description">Action name</p>
10+
<input type="text" formControlName="name" class="full-width" />
1011
<mat-error *ngIf="addActionFormGroup.get('name')?.errors?.required">
1112
{{ 'functions.nameRequired' | translate }}
1213
</mat-error>
13-
</mat-form-field>
14+
</div>
15+
<mat-divider></mat-divider>
1416
<!-- Type -->
15-
<mat-form-field appearance="outline" class="full-width">
16-
<mat-label>Select the type of action</mat-label>
17-
<mat-select formControlName="type">
18-
<mat-option value="1">Function</mat-option>
19-
</mat-select>
20-
</mat-form-field>
21-
<!-- Function Ref -->
17+
<div class="form-control">
18+
<div class="title">Type</div>
19+
<p class="description">Select the type of action</p>
20+
<select formControlName="type" class="full-width">
21+
<option value="1">Function</option>
22+
</select>
23+
</div>
24+
<mat-divider></mat-divider>
2225
<div *ngIf="addActionFormGroup.get('type')?.value == 1" [formGroup]="addFunctionFormGroup">
2326
<!-- Reference Name -->
24-
<mat-form-field appearance="outline" class="full-width">
25-
<mat-label>Select a function</mat-label>
26-
<mat-select formControlName="refName">
27-
<mat-option *ngFor="let function of functions" [value]="function.name">{{ function.name + ' (' + function.type + ')'}}</mat-option>
28-
</mat-select>
27+
<div class="form-control">
28+
<div class="title">Reference Name</div>
29+
<p class="description">Name of the references function</p>
30+
<select formControlName="refName" class="full-width">
31+
<option *ngFor="let function of functions" [value]="function.name">{{ function.name + ' (' + function.type + ')'}}</option>
32+
</select>
2933
<mat-error *ngIf="addFunctionFormGroup.get('refName')?.errors?.required">A function must be selected</mat-error>
30-
</mat-form-field>
34+
</div>
35+
<mat-divider></mat-divider>
3136
<!-- Arguments -->
32-
<mat-form-field appearance="outline" class="full-width">
33-
<mat-label>Arguments</mat-label>
34-
<input matInput formControlName="arguments" />
35-
</mat-form-field>
37+
<div class="form-control">
38+
<div class="title">Arguments</div>
39+
<p class="description">Arguments (inputs) to be passed to the referenced function.</p>
40+
<input type="text" formControlName="arguments" class="full-width" />
41+
</div>
42+
</div>
43+
<mat-divider></mat-divider>
44+
<div class="mt-10">
45+
<button mat-raised-button color="primary" [disabled]="isDisabled()">Add</button>
3646
</div>
37-
<button mat-raised-button color="primary" [disabled]="isDisabled()">Add</button>
3847
</form>
3948
</div>
4049
<div fxFlex="50%" class="secondColumn">

src/FaasNet.Website/src/components/statediagram/components/operation/operation-state-editor.component.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ $border-color: #c1c1c1;
33
.actions {
44
border: 1px solid $border-color;
55
height: 30px;
6+
line-height: 30px;
67
cursor: pointer;
78
}

src/FaasNet.Website/src/stores/statemachines/models/statemachine-function.model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ export class StateMachineFunction {
88
return {
99
name: this.name,
1010
type: this.type,
11-
operation: this.operation
11+
operation: this.operation,
12+
metadata: this.metadata
1213
};
1314
}
1415

0 commit comments

Comments
 (0)