Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 5352b48

Browse files
authored
Expand valid scaleset names (#3045)
Scaleset names are now permitted to be any (valid) strings, instead of only GUIDs. When we generate a scaleset name it is now based upon the pool name; for example the pool `pool` might get a scaleset named `pool-3b24ba211cad4b078655914754485838`. This should be backwards-compatible since GUIDs are [already serialized to table storage as strings](https://github.com/microsoft/onefuzz/blob/dddcfa49490e44834afc9a6910c350698022792c/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs#L190-L191), so this simply loosens the restrictions placed upon them. Scaleset IDs now have a strong type in the same way as other IDs; this helps to avoid mixing them up with other strings. Because of this I found one bug in the scaleset search query logic due to Pool ID/VMSS ID confusion. As part of fixing this I've changed the scaleset search query to only return nodes from the table rather than querying Azure to find a list; this seems to be sufficient for the CLI.
1 parent a143532 commit 5352b48

38 files changed

+380
-291
lines changed

docs/webhook_events.md

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,6 @@ If webhook is set to have Event Grid message format then the payload will look a
13301330
"type": "string"
13311331
},
13321332
"scaleset_id": {
1333-
"format": "uuid",
13341333
"title": "Scaleset Id",
13351334
"type": "string"
13361335
}
@@ -1370,7 +1369,6 @@ If webhook is set to have Event Grid message format then the payload will look a
13701369
"type": "string"
13711370
},
13721371
"scaleset_id": {
1373-
"format": "uuid",
13741372
"title": "Scaleset Id",
13751373
"type": "string"
13761374
}
@@ -1430,7 +1428,6 @@ If webhook is set to have Event Grid message format then the payload will look a
14301428
"type": "string"
14311429
},
14321430
"scaleset_id": {
1433-
"format": "uuid",
14341431
"title": "Scaleset Id",
14351432
"type": "string"
14361433
}
@@ -1488,7 +1485,6 @@ If webhook is set to have Event Grid message format then the payload will look a
14881485
"type": "string"
14891486
},
14901487
"scaleset_id": {
1491-
"format": "uuid",
14921488
"title": "Scaleset Id",
14931489
"type": "string"
14941490
},
@@ -2599,7 +2595,7 @@ If webhook is set to have Event Grid message format then the payload will look a
25992595
"image": "Canonical:0001-com-ubuntu-server-focal:20_04-lts:latest",
26002596
"pool_name": "example",
26012597
"region": "eastus",
2602-
"scaleset_id": "00000000-0000-0000-0000-000000000000",
2598+
"scaleset_id": "example-000",
26032599
"size": 10,
26042600
"vm_sku": "Standard_D2s_v3"
26052601
}
@@ -2623,7 +2619,6 @@ If webhook is set to have Event Grid message format then the payload will look a
26232619
"type": "string"
26242620
},
26252621
"scaleset_id": {
2626-
"format": "uuid",
26272622
"title": "Scaleset Id",
26282623
"type": "string"
26292624
},
@@ -2656,7 +2651,7 @@ If webhook is set to have Event Grid message format then the payload will look a
26562651
```json
26572652
{
26582653
"pool_name": "example",
2659-
"scaleset_id": "00000000-0000-0000-0000-000000000000"
2654+
"scaleset_id": "example-000"
26602655
}
26612656
```
26622657

@@ -2670,7 +2665,6 @@ If webhook is set to have Event Grid message format then the payload will look a
26702665
"type": "string"
26712666
},
26722667
"scaleset_id": {
2673-
"format": "uuid",
26742668
"title": "Scaleset Id",
26752669
"type": "string"
26762670
}
@@ -2697,7 +2691,7 @@ If webhook is set to have Event Grid message format then the payload will look a
26972691
]
26982692
},
26992693
"pool_name": "example",
2700-
"scaleset_id": "00000000-0000-0000-0000-000000000000"
2694+
"scaleset_id": "example-000"
27012695
}
27022696
```
27032697

@@ -2766,7 +2760,6 @@ If webhook is set to have Event Grid message format then the payload will look a
27662760
"type": "string"
27672761
},
27682762
"scaleset_id": {
2769-
"format": "uuid",
27702763
"title": "Scaleset Id",
27712764
"type": "string"
27722765
}
@@ -2788,7 +2781,7 @@ If webhook is set to have Event Grid message format then the payload will look a
27882781
```json
27892782
{
27902783
"pool_name": "example",
2791-
"scaleset_id": "00000000-0000-0000-0000-000000000000",
2784+
"scaleset_id": "example-000",
27922785
"size": 0
27932786
}
27942787
```
@@ -2803,7 +2796,6 @@ If webhook is set to have Event Grid message format then the payload will look a
28032796
"type": "string"
28042797
},
28052798
"scaleset_id": {
2806-
"format": "uuid",
28072799
"title": "Scaleset Id",
28082800
"type": "string"
28092801
},
@@ -2829,7 +2821,7 @@ If webhook is set to have Event Grid message format then the payload will look a
28292821
```json
28302822
{
28312823
"pool_name": "example",
2832-
"scaleset_id": "00000000-0000-0000-0000-000000000000",
2824+
"scaleset_id": "example-000",
28332825
"state": "init"
28342826
}
28352827
```
@@ -2859,7 +2851,6 @@ If webhook is set to have Event Grid message format then the payload will look a
28592851
"type": "string"
28602852
},
28612853
"scaleset_id": {
2862-
"format": "uuid",
28632854
"title": "Scaleset Id",
28642855
"type": "string"
28652856
},
@@ -5666,7 +5657,6 @@ If webhook is set to have Event Grid message format then the payload will look a
56665657
"type": "string"
56675658
},
56685659
"scaleset_id": {
5669-
"format": "uuid",
56705660
"title": "Scaleset Id",
56715661
"type": "string"
56725662
}
@@ -5690,7 +5680,6 @@ If webhook is set to have Event Grid message format then the payload will look a
56905680
"type": "string"
56915681
},
56925682
"scaleset_id": {
5693-
"format": "uuid",
56945683
"title": "Scaleset Id",
56955684
"type": "string"
56965685
}
@@ -5717,7 +5706,6 @@ If webhook is set to have Event Grid message format then the payload will look a
57175706
"type": "string"
57185707
},
57195708
"scaleset_id": {
5720-
"format": "uuid",
57215709
"title": "Scaleset Id",
57225710
"type": "string"
57235711
}
@@ -5741,7 +5729,6 @@ If webhook is set to have Event Grid message format then the payload will look a
57415729
"type": "string"
57425730
},
57435731
"scaleset_id": {
5744-
"format": "uuid",
57455732
"title": "Scaleset Id",
57465733
"type": "string"
57475734
},
@@ -5934,7 +5921,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59345921
"type": "string"
59355922
},
59365923
"scaleset_id": {
5937-
"format": "uuid",
59385924
"title": "Scaleset Id",
59395925
"type": "string"
59405926
},
@@ -5965,7 +5951,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59655951
"type": "string"
59665952
},
59675953
"scaleset_id": {
5968-
"format": "uuid",
59695954
"title": "Scaleset Id",
59705955
"type": "string"
59715956
}
@@ -5987,7 +5972,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59875972
"type": "string"
59885973
},
59895974
"scaleset_id": {
5990-
"format": "uuid",
59915975
"title": "Scaleset Id",
59925976
"type": "string"
59935977
}
@@ -6007,7 +5991,6 @@ If webhook is set to have Event Grid message format then the payload will look a
60075991
"type": "string"
60085992
},
60095993
"scaleset_id": {
6010-
"format": "uuid",
60115994
"title": "Scaleset Id",
60125995
"type": "string"
60135996
},
@@ -6031,7 +6014,6 @@ If webhook is set to have Event Grid message format then the payload will look a
60316014
"type": "string"
60326015
},
60336016
"scaleset_id": {
6034-
"format": "uuid",
60356017
"title": "Scaleset Id",
60366018
"type": "string"
60376019
},

src/ApiService/ApiService/Functions/Proxy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private async Async.Task<HttpResponseData> Get(HttpRequestData req) {
5252

5353
var proxyGet = request.OkV;
5454
switch ((proxyGet.ScalesetId, proxyGet.MachineId, proxyGet.DstPort)) {
55-
case (Guid scalesetId, Guid machineId, int dstPort):
55+
case (ScalesetId scalesetId, Guid machineId, int dstPort):
5656
var scaleset = await _context.ScalesetOperations.GetById(scalesetId);
5757
if (!scaleset.IsOk) {
5858
return await _context.RequestHandling.NotOk(req, scaleset.ErrorV, "ProxyGet");

src/ApiService/ApiService/Functions/Scaleset.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ private async Task<HttpResponseData> Post(HttpRequestData req) {
118118
}
119119

120120
var scaleset = new Service.Scaleset(
121-
ScalesetId: Guid.NewGuid(),
121+
ScalesetId: Service.Scaleset.GenerateNewScalesetId(create.PoolName),
122122
State: ScalesetState.Init,
123123
NeedsConfigUpdate: false,
124124
Auth: await Auth.BuildAuth(_log),
@@ -206,7 +206,7 @@ private async Task<HttpResponseData> Get(HttpRequestData req) {
206206
}
207207

208208
var search = request.OkV;
209-
if (search.ScalesetId is Guid id) {
209+
if (search.ScalesetId is ScalesetId id) {
210210
var scalesetResult = await _context.ScalesetOperations.GetById(id);
211211
if (!scalesetResult.IsOk) {
212212
return await _context.RequestHandling.NotOk(req, scalesetResult.ErrorV, "ScalesetSearch");

src/ApiService/ApiService/OneFuzzTypes/Events.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ Guid PingId
185185

186186
[EventType(EventType.ScalesetCreated)]
187187
public record EventScalesetCreated(
188-
Guid ScalesetId,
188+
ScalesetId ScalesetId,
189189
PoolName PoolName,
190190
string VmSku,
191191
string Image,
@@ -195,23 +195,23 @@ public record EventScalesetCreated(
195195

196196
[EventType(EventType.ScalesetFailed)]
197197
public sealed record EventScalesetFailed(
198-
Guid ScalesetId,
198+
ScalesetId ScalesetId,
199199
PoolName PoolName,
200200
Error Error
201201
) : BaseEvent();
202202

203203

204204
[EventType(EventType.ScalesetDeleted)]
205205
public record EventScalesetDeleted(
206-
Guid ScalesetId,
206+
ScalesetId ScalesetId,
207207
PoolName PoolName
208208

209209
) : BaseEvent();
210210

211211

212212
[EventType(EventType.ScalesetResizeScheduled)]
213213
public record EventScalesetResizeScheduled(
214-
Guid ScalesetId,
214+
ScalesetId ScalesetId,
215215
PoolName PoolName,
216216
long size
217217
) : BaseEvent();
@@ -267,14 +267,14 @@ VmState State
267267
[EventType(EventType.NodeCreated)]
268268
public record EventNodeCreated(
269269
Guid MachineId,
270-
Guid? ScalesetId,
270+
ScalesetId? ScalesetId,
271271
PoolName PoolName
272272
) : BaseEvent();
273273

274274
[EventType(EventType.NodeHeartbeat)]
275275
public record EventNodeHeartbeat(
276276
Guid MachineId,
277-
Guid? ScalesetId,
277+
ScalesetId? ScalesetId,
278278
PoolName PoolName,
279279
NodeState state
280280
) : BaseEvent();
@@ -283,23 +283,23 @@ NodeState state
283283
[EventType(EventType.NodeDeleted)]
284284
public record EventNodeDeleted(
285285
Guid MachineId,
286-
Guid? ScalesetId,
286+
ScalesetId? ScalesetId,
287287
PoolName PoolName,
288288
NodeState? MachineState
289289
) : BaseEvent();
290290

291291

292292
[EventType(EventType.ScalesetStateUpdated)]
293293
public record EventScalesetStateUpdated(
294-
Guid ScalesetId,
294+
ScalesetId ScalesetId,
295295
PoolName PoolName,
296296
ScalesetState State
297297
) : BaseEvent();
298298

299299
[EventType(EventType.NodeStateUpdated)]
300300
public record EventNodeStateUpdated(
301301
Guid MachineId,
302-
Guid? ScalesetId,
302+
ScalesetId? ScalesetId,
303303
PoolName PoolName,
304304
NodeState state
305305
) : BaseEvent();

src/ApiService/ApiService/OneFuzzTypes/Model.cs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Reflection;
22
using System.Text.Json;
33
using System.Text.Json.Serialization;
4+
using System.Text.RegularExpressions;
45
using System.Threading.Tasks;
56
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
67
using Endpoint = System.String;
@@ -107,7 +108,7 @@ public record Node
107108
// a string internally.
108109
string? InstanceId = null,
109110

110-
Guid? ScalesetId = null,
111+
ScalesetId? ScalesetId = null,
111112

112113
bool ReimageRequested = false,
113114
bool DeleteRequested = false,
@@ -132,7 +133,7 @@ public record ProxyForward
132133
(
133134
[PartitionKey] Region Region,
134135
[RowKey] long Port,
135-
Guid ScalesetId,
136+
ScalesetId ScalesetId,
136137
Guid MachineId,
137138
Guid? ProxyId,
138139
long DstPort,
@@ -263,7 +264,7 @@ string EventType
263264

264265
public record NodeAssignment(
265266
Guid NodeId,
266-
Guid? ScalesetId,
267+
ScalesetId? ScalesetId,
267268
NodeTaskState State
268269
);
269270

@@ -392,7 +393,7 @@ public ResultVoid<List<string>> CheckInstanceConfig() {
392393
}
393394

394395
public record AutoScale(
395-
[PartitionKey, RowKey] Guid ScalesetId,
396+
[PartitionKey, RowKey] ScalesetId ScalesetId,
396397
long Min,
397398
long Max,
398399
long Default,
@@ -402,15 +403,10 @@ public record AutoScale(
402403
long ScaleInCooldown
403404
) : EntityBase;
404405

405-
public record ScalesetNodeState(
406-
Guid MachineId,
407-
string InstanceId,
408-
NodeState? State
409-
);
410406

411-
public record Scaleset(
407+
public partial record Scaleset(
412408
[PartitionKey] PoolName PoolName,
413-
[RowKey] Guid ScalesetId,
409+
[RowKey] ScalesetId ScalesetId,
414410
ScalesetState State,
415411
string VmSku,
416412
ImageReference Image,
@@ -425,7 +421,31 @@ public record Scaleset(
425421
Guid? ClientId = null,
426422
Guid? ClientObjectId = null
427423
// 'Nodes' removed when porting from Python: only used in search response
428-
) : StatefulEntityBase<ScalesetState>(State);
424+
) : StatefulEntityBase<ScalesetState>(State) {
425+
426+
[GeneratedRegex(@"[^a-zA-Z0-9\-]+")]
427+
private static partial Regex InvalidCharacterRegex();
428+
429+
public static ScalesetId GenerateNewScalesetId(PoolName poolName)
430+
=> GenerateNewScalesetIdUsingGuid(poolName, Guid.NewGuid());
431+
432+
public static ScalesetId GenerateNewScalesetIdUsingGuid(PoolName poolName, Guid guid) {
433+
// poolnames permit underscores but not scaleset names; use hyphen instead:
434+
var name = poolName.ToString().Replace("_", "-");
435+
436+
// since poolnames are not actually validated, take only the valid characters:
437+
name = InvalidCharacterRegex().Replace(name, "");
438+
439+
// trim off any starting and ending dashes:
440+
name = name.Trim('-');
441+
442+
// this should now be a valid name; generate a unique suffix:
443+
// max length is 64; length of Guid in "N" format is 32, -1 for the hyphen
444+
name = name[..Math.Min(64 - 32 - 1, name.Length)] + "-" + guid.ToString("N");
445+
446+
return ScalesetId.Parse(name);
447+
}
448+
}
429449

430450
public record Notification(
431451
[PartitionKey] Guid NotificationId,
@@ -733,7 +753,7 @@ List<WorkUnitSummary> WorkUnits
733753
);
734754

735755
public record ScalesetSummary(
736-
Guid ScalesetId,
756+
ScalesetId ScalesetId,
737757
ScalesetState State
738758
);
739759

0 commit comments

Comments
 (0)