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

Commit 2f478d6

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 d84b72b commit 2f478d6

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
@@ -1329,7 +1329,6 @@ If webhook is set to have Event Grid message format then the payload will look a
13291329
"type": "string"
13301330
},
13311331
"scaleset_id": {
1332-
"format": "uuid",
13331332
"title": "Scaleset Id",
13341333
"type": "string"
13351334
}
@@ -1369,7 +1368,6 @@ If webhook is set to have Event Grid message format then the payload will look a
13691368
"type": "string"
13701369
},
13711370
"scaleset_id": {
1372-
"format": "uuid",
13731371
"title": "Scaleset Id",
13741372
"type": "string"
13751373
}
@@ -1429,7 +1427,6 @@ If webhook is set to have Event Grid message format then the payload will look a
14291427
"type": "string"
14301428
},
14311429
"scaleset_id": {
1432-
"format": "uuid",
14331430
"title": "Scaleset Id",
14341431
"type": "string"
14351432
}
@@ -1487,7 +1484,6 @@ If webhook is set to have Event Grid message format then the payload will look a
14871484
"type": "string"
14881485
},
14891486
"scaleset_id": {
1490-
"format": "uuid",
14911487
"title": "Scaleset Id",
14921488
"type": "string"
14931489
},
@@ -2597,7 +2593,7 @@ If webhook is set to have Event Grid message format then the payload will look a
25972593
"image": "Canonical:0001-com-ubuntu-server-focal:20_04-lts:latest",
25982594
"pool_name": "example",
25992595
"region": "eastus",
2600-
"scaleset_id": "00000000-0000-0000-0000-000000000000",
2596+
"scaleset_id": "example-000",
26012597
"size": 10,
26022598
"vm_sku": "Standard_D2s_v3"
26032599
}
@@ -2621,7 +2617,6 @@ If webhook is set to have Event Grid message format then the payload will look a
26212617
"type": "string"
26222618
},
26232619
"scaleset_id": {
2624-
"format": "uuid",
26252620
"title": "Scaleset Id",
26262621
"type": "string"
26272622
},
@@ -2654,7 +2649,7 @@ If webhook is set to have Event Grid message format then the payload will look a
26542649
```json
26552650
{
26562651
"pool_name": "example",
2657-
"scaleset_id": "00000000-0000-0000-0000-000000000000"
2652+
"scaleset_id": "example-000"
26582653
}
26592654
```
26602655

@@ -2668,7 +2663,6 @@ If webhook is set to have Event Grid message format then the payload will look a
26682663
"type": "string"
26692664
},
26702665
"scaleset_id": {
2671-
"format": "uuid",
26722666
"title": "Scaleset Id",
26732667
"type": "string"
26742668
}
@@ -2695,7 +2689,7 @@ If webhook is set to have Event Grid message format then the payload will look a
26952689
]
26962690
},
26972691
"pool_name": "example",
2698-
"scaleset_id": "00000000-0000-0000-0000-000000000000"
2692+
"scaleset_id": "example-000"
26992693
}
27002694
```
27012695

@@ -2764,7 +2758,6 @@ If webhook is set to have Event Grid message format then the payload will look a
27642758
"type": "string"
27652759
},
27662760
"scaleset_id": {
2767-
"format": "uuid",
27682761
"title": "Scaleset Id",
27692762
"type": "string"
27702763
}
@@ -2786,7 +2779,7 @@ If webhook is set to have Event Grid message format then the payload will look a
27862779
```json
27872780
{
27882781
"pool_name": "example",
2789-
"scaleset_id": "00000000-0000-0000-0000-000000000000",
2782+
"scaleset_id": "example-000",
27902783
"size": 0
27912784
}
27922785
```
@@ -2801,7 +2794,6 @@ If webhook is set to have Event Grid message format then the payload will look a
28012794
"type": "string"
28022795
},
28032796
"scaleset_id": {
2804-
"format": "uuid",
28052797
"title": "Scaleset Id",
28062798
"type": "string"
28072799
},
@@ -2827,7 +2819,7 @@ If webhook is set to have Event Grid message format then the payload will look a
28272819
```json
28282820
{
28292821
"pool_name": "example",
2830-
"scaleset_id": "00000000-0000-0000-0000-000000000000",
2822+
"scaleset_id": "example-000",
28312823
"state": "init"
28322824
}
28332825
```
@@ -2857,7 +2849,6 @@ If webhook is set to have Event Grid message format then the payload will look a
28572849
"type": "string"
28582850
},
28592851
"scaleset_id": {
2860-
"format": "uuid",
28612852
"title": "Scaleset Id",
28622853
"type": "string"
28632854
},
@@ -5658,7 +5649,6 @@ If webhook is set to have Event Grid message format then the payload will look a
56585649
"type": "string"
56595650
},
56605651
"scaleset_id": {
5661-
"format": "uuid",
56625652
"title": "Scaleset Id",
56635653
"type": "string"
56645654
}
@@ -5682,7 +5672,6 @@ If webhook is set to have Event Grid message format then the payload will look a
56825672
"type": "string"
56835673
},
56845674
"scaleset_id": {
5685-
"format": "uuid",
56865675
"title": "Scaleset Id",
56875676
"type": "string"
56885677
}
@@ -5709,7 +5698,6 @@ If webhook is set to have Event Grid message format then the payload will look a
57095698
"type": "string"
57105699
},
57115700
"scaleset_id": {
5712-
"format": "uuid",
57135701
"title": "Scaleset Id",
57145702
"type": "string"
57155703
}
@@ -5733,7 +5721,6 @@ If webhook is set to have Event Grid message format then the payload will look a
57335721
"type": "string"
57345722
},
57355723
"scaleset_id": {
5736-
"format": "uuid",
57375724
"title": "Scaleset Id",
57385725
"type": "string"
57395726
},
@@ -5926,7 +5913,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59265913
"type": "string"
59275914
},
59285915
"scaleset_id": {
5929-
"format": "uuid",
59305916
"title": "Scaleset Id",
59315917
"type": "string"
59325918
},
@@ -5957,7 +5943,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59575943
"type": "string"
59585944
},
59595945
"scaleset_id": {
5960-
"format": "uuid",
59615946
"title": "Scaleset Id",
59625947
"type": "string"
59635948
}
@@ -5979,7 +5964,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59795964
"type": "string"
59805965
},
59815966
"scaleset_id": {
5982-
"format": "uuid",
59835967
"title": "Scaleset Id",
59845968
"type": "string"
59855969
}
@@ -5999,7 +5983,6 @@ If webhook is set to have Event Grid message format then the payload will look a
59995983
"type": "string"
60005984
},
60015985
"scaleset_id": {
6002-
"format": "uuid",
60035986
"title": "Scaleset Id",
60045987
"type": "string"
60055988
},
@@ -6023,7 +6006,6 @@ If webhook is set to have Event Grid message format then the payload will look a
60236006
"type": "string"
60246007
},
60256008
"scaleset_id": {
6026-
"format": "uuid",
60276009
"title": "Scaleset Id",
60286010
"type": "string"
60296011
},

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)