nanoping-api 11.1.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4182 @@
1
+ # Generated from the gRPC bridge protos and HTTP rules. Do not edit.
2
+
3
+ from __future__ import annotations
4
+
5
+ import dataclasses
6
+ import datetime
7
+ from collections.abc import Mapping, Sequence
8
+
9
+ from ._runtime import (
10
+ AsyncBidiStream,
11
+ AsyncServerStream,
12
+ AsyncTransport,
13
+ BidiStream,
14
+ ProtoEnum,
15
+ Route,
16
+ ServerStream,
17
+ Transport,
18
+ )
19
+
20
+ __all__ = [
21
+ "Address",
22
+ "AsyncBlueprintsClient",
23
+ "AsyncConfigServiceClient",
24
+ "AsyncHubClientServiceClient",
25
+ "AsyncHubServerServiceClient",
26
+ "AsyncLoggingServiceClient",
27
+ "AsyncNetworkInstancesClient",
28
+ "AsyncNetworksClient",
29
+ "AsyncPipelinesServiceClient",
30
+ "AsyncResourcesServiceClient",
31
+ "AuthenticateByRequestRequest",
32
+ "AuthenticateByRequestResponse",
33
+ "AuthenticationByRequestAnswer",
34
+ "AuthenticationByRequestRequest",
35
+ "Blueprint",
36
+ "BlueprintWrite",
37
+ "BlueprintsClient",
38
+ "BoolMetric",
39
+ "Carrier",
40
+ "Collection",
41
+ "ConfigCompatability",
42
+ "ConfigServiceClient",
43
+ "ConnectionState",
44
+ "Constant",
45
+ "CreateBlueprintRequest",
46
+ "CreateBlueprintResponse",
47
+ "CreateNetworkRequest",
48
+ "CreateNetworkResponse",
49
+ "CreatePipelineRequest",
50
+ "CreatePipelineResponse",
51
+ "DefaultNetworkCarrier",
52
+ "DefaultNetworkCarrierAddress",
53
+ "DefaultNetworkCarriers",
54
+ "DeleteBlueprintRequest",
55
+ "DeleteBlueprintResponse",
56
+ "DeleteNetworkRequest",
57
+ "DeleteNetworkResponse",
58
+ "DeletePipelineRequest",
59
+ "DeletePipelineResponse",
60
+ "DisconnectRequest",
61
+ "DisconnectResponse",
62
+ "DownloadAppLogFileRequest",
63
+ "DownloadLogFileChunk",
64
+ "DownloadLogFileRequest",
65
+ "DownloadNetworkInstanceLogFileRequest",
66
+ "DownloadNetworkLogFileRequest",
67
+ "DownloadPipelineRunLogFileRequest",
68
+ "Enum8Metric",
69
+ "Enum8Metric_EnumValue",
70
+ "Float32Metric",
71
+ "Float64Metric",
72
+ "Flow",
73
+ "FlowsSample",
74
+ "GetBlueprintRequest",
75
+ "GetBlueprintResponse",
76
+ "GetBlueprintsRequest",
77
+ "GetBlueprintsResponse",
78
+ "GetDefaultNetworkCarriersRequest",
79
+ "GetDefaultNetworkCarriersResponse",
80
+ "GetLocalNodeIdRequest",
81
+ "GetLocalNodeIdResponse",
82
+ "GetNetworkInstancesRequest",
83
+ "GetNetworkInstancesResponse",
84
+ "GetNetworkPipelinesRequest",
85
+ "GetNetworkPipelinesResponse",
86
+ "GetNetworkRequest",
87
+ "GetNetworkResponse",
88
+ "GetNetworksRequest",
89
+ "GetNetworksResponse",
90
+ "GetNodeRequest",
91
+ "GetNodeResponse",
92
+ "GetNodesRequest",
93
+ "GetNodesResponse",
94
+ "GetPipelineByIdRequest",
95
+ "GetPipelineByIdResponse",
96
+ "GetPipelineByNameRequest",
97
+ "GetPipelineByNameResponse",
98
+ "GetPipelineByRunIdRequest",
99
+ "GetPipelineByRunIdResponse",
100
+ "GetPipelinesRequest",
101
+ "GetPipelinesResponse",
102
+ "HubClientServiceClient",
103
+ "HubNode",
104
+ "HubServerServiceClient",
105
+ "Int32Metric",
106
+ "Int64Metric",
107
+ "Kind",
108
+ "Kpi",
109
+ "Level",
110
+ "LogFileChunk",
111
+ "LogStreamMessages",
112
+ "LoggingOpenLogStreamRequest",
113
+ "LoggingOpenNetworkInstanceLogStreamRequest",
114
+ "LoggingOpenNetworkLogStreamRequest",
115
+ "LoggingServiceClient",
116
+ "Message",
117
+ "Messages",
118
+ "Metric",
119
+ "MetricsSample",
120
+ "Network",
121
+ "NetworkBlueprints",
122
+ "NetworkInstance",
123
+ "NetworkInstanceLogStreamMessages",
124
+ "NetworkInstancesClient",
125
+ "NetworkLogStreamMessages",
126
+ "NetworkPipeline",
127
+ "NetworksClient",
128
+ "NetworksNode",
129
+ "NetworksOpenNetworkInstanceLogStreamRequest",
130
+ "NetworksOpenNetworkLogStreamRequest",
131
+ "NodeMetadata",
132
+ "NodeMetadataItem",
133
+ "NodeService",
134
+ "NodeType",
135
+ "OpenAppLogStreamRequest",
136
+ "OpenFlowsStreamRequest",
137
+ "OpenMetricsStreamRequest",
138
+ "OpenPipelineRunLogStreamRequest",
139
+ "OpenTelemetryStreamRequest",
140
+ "Options",
141
+ "Pipeline",
142
+ "PipelineOpenLogStreamRequest",
143
+ "PipelinesServiceClient",
144
+ "RemoveNodeRequest",
145
+ "RemoveNodeResponse",
146
+ "ResourcesServiceClient",
147
+ "RestartPolicy",
148
+ "RestartPolicyAlways",
149
+ "RestartPolicyNever",
150
+ "RestartPolicyOnFailure",
151
+ "SetDefaultNetworkCarriersRequest",
152
+ "SetDefaultNetworkCarriersResponse",
153
+ "SetNodeRequest",
154
+ "SetNodeResponse",
155
+ "StartPipelineRequest",
156
+ "StartPipelineResponse",
157
+ "StartupPolicy",
158
+ "StartupPolicyAuto",
159
+ "StartupPolicyManual",
160
+ "StopPipelineRequest",
161
+ "StopPipelineResponse",
162
+ "StreamConnectionStateRequest",
163
+ "StreamConnectionStateResponse",
164
+ "StreamNetworkInstanceCreateEvent",
165
+ "StreamNetworkInstanceDeleteEvent",
166
+ "StreamNetworkInstanceEvent",
167
+ "StreamNetworkInstanceUpdateEvent",
168
+ "StreamNetworkInstancesRequest",
169
+ "StreamNetworkPipelineCreateEvent",
170
+ "StreamNetworkPipelineDeleteEvent",
171
+ "StreamNetworkPipelineEvent",
172
+ "StreamNetworkPipelineUpdateEvent",
173
+ "StreamNetworkPipelinesRequest",
174
+ "StreamNetworksCreateEvent",
175
+ "StreamNetworksDeleteEvent",
176
+ "StreamNetworksEvent",
177
+ "StreamNetworksRequest",
178
+ "StreamNetworksUpdateEvent",
179
+ "StreamNodesInitialResponse",
180
+ "StreamNodesResponse",
181
+ "StreamNodesUpdateResponse",
182
+ "StreamPipelinesCreateEvent",
183
+ "StreamPipelinesDeleteEvent",
184
+ "StreamPipelinesEvent",
185
+ "StreamPipelinesRequest",
186
+ "StreamPipelinesUpdateEvent",
187
+ "TelemetrySample",
188
+ "ToggleNetworkPipelineRequest",
189
+ "ToggleNetworkPipelineResponse",
190
+ "UInt32Metric",
191
+ "UInt64Metric",
192
+ "UpdateBlueprintRequest",
193
+ "UpdateBlueprintResponse",
194
+ "UpdateNetworkRequest",
195
+ "UpdateNetworkResponse",
196
+ "UpdatePipelineRequest",
197
+ "UpdatePipelineResponse",
198
+ ]
199
+
200
+
201
+ class ConnectionState(ProtoEnum):
202
+ """Connection state between a node and its hub server."""
203
+
204
+ UNAUTHENTICATED = "UNAUTHENTICATED"
205
+ """The node is not authenticated with a hub server."""
206
+ DISCONNECTED = "DISCONNECTED"
207
+ """The node is authenticated but not connected to the hub server."""
208
+ CONNECTED = "CONNECTED"
209
+ """The node is connected to the hub server."""
210
+
211
+
212
+ class NodeService(ProtoEnum):
213
+ """Services a node can offer."""
214
+
215
+ HUB_SERVER = "HUB_SERVER"
216
+ """The node hosts a hub server."""
217
+ RESOURCES = "RESOURCES"
218
+ """The node offers resources."""
219
+ LOGGING = "LOGGING"
220
+ """The node offers logging."""
221
+ PIPELINES = "PIPELINES"
222
+ """The node can run pipelines."""
223
+
224
+
225
+ class Level(ProtoEnum):
226
+ """Severity of a log message, from the most verbose to the most severe."""
227
+
228
+ STATE = "STATE"
229
+ """State information, the most verbose level."""
230
+ DEBUG = "DEBUG"
231
+ """Debugging details."""
232
+ INFO = "INFO"
233
+ """General information."""
234
+ WARNING = "WARNING"
235
+ """Something unexpected that did not stop the operation."""
236
+ ERROR = "ERROR"
237
+ """An operation failed."""
238
+ FATAL = "FATAL"
239
+ """A failure the process could not recover from."""
240
+
241
+
242
+ class Kind(ProtoEnum):
243
+ """How the value of a metric changes over time."""
244
+
245
+ GAUGE = "GAUGE"
246
+ """The value can both increase and decrease, for example memory in use."""
247
+ COUNTER = "COUNTER"
248
+ """The value can only increase, for example a total byte count."""
249
+
250
+
251
+ class NodeType(ProtoEnum):
252
+ """The role of a node in a network."""
253
+
254
+ NODE_TYPE_CLIENT = "NODE_TYPE_CLIENT"
255
+ """A client node."""
256
+ NODE_TYPE_RELAY = "NODE_TYPE_RELAY"
257
+ """The relay node, named by the network's `relay_node_id`."""
258
+
259
+
260
+ class ConfigCompatability(ProtoEnum):
261
+ """Whether the node can run a pipeline configuration."""
262
+
263
+ COMPATIBLE = "COMPATIBLE"
264
+ """The node can run the configuration."""
265
+ INCOMPATIBLE = "INCOMPATIBLE"
266
+ """The configuration was made for a newer NanoPing version than the one running on
267
+ the node.
268
+ """
269
+
270
+
271
+ @dataclasses.dataclass(kw_only=True)
272
+ class AuthenticateByRequestRequest:
273
+ """Request for authenticateByRequest."""
274
+
275
+ hub_server_address: str = ""
276
+ """HTTP or HTTPS address of the hub server. Example: `http://127.0.0.1:8769`"""
277
+
278
+
279
+ @dataclasses.dataclass(kw_only=True)
280
+ class AuthenticateByRequestResponse:
281
+ """Response for authenticateByRequest. Empty on success."""
282
+
283
+
284
+ @dataclasses.dataclass(kw_only=True)
285
+ class AuthenticationByRequestAnswer:
286
+ """An answer to an authentication by request, sent by the caller."""
287
+
288
+ request_id: int = 0
289
+ """Id of the request being answered, as received in the request."""
290
+ accept: bool = False
291
+ """True to accept the request, false to reject it."""
292
+
293
+
294
+ @dataclasses.dataclass(kw_only=True)
295
+ class AuthenticationByRequestRequest:
296
+ """An authentication by request from a node that wants to authenticate with the hub
297
+ server.
298
+ """
299
+
300
+ node: HubNode = dataclasses.field(default_factory=lambda: HubNode())
301
+ """Information about the node asking to authenticate."""
302
+ request_id: int = 0
303
+ """Id of the request, used when answering it."""
304
+
305
+
306
+ @dataclasses.dataclass(kw_only=True)
307
+ class DefaultNetworkCarrier:
308
+ """A carrier a node receives every time it joins a new network. Every setting is
309
+ optional.
310
+ """
311
+
312
+ address: DefaultNetworkCarrierAddress | None = None
313
+ """Address the carrier uses."""
314
+ interface: str | None = None
315
+ """Name of the network interface the carrier uses. Example: `eth0`"""
316
+ bandwidth_priority: int | None = None
317
+ """Bandwidth priority of the carrier. Example: `100`"""
318
+
319
+
320
+ @dataclasses.dataclass(kw_only=True)
321
+ class DefaultNetworkCarrierAddress:
322
+ """Address of a default network carrier."""
323
+
324
+ ip: str = ""
325
+ """IP address of the carrier. Example: `192.168.1.20`"""
326
+ port: int = 0
327
+ """Port of the carrier. Example: `3425`"""
328
+ external_ip: str | None = None
329
+ """IP address the carrier is reachable at from outside, for example behind NAT.
330
+ Example: `203.0.113.10`
331
+ """
332
+
333
+
334
+ @dataclasses.dataclass(kw_only=True)
335
+ class DefaultNetworkCarriers:
336
+ """A list of default network carriers."""
337
+
338
+ carriers: list[DefaultNetworkCarrier] = dataclasses.field(default_factory=list)
339
+ """The default network carriers."""
340
+
341
+
342
+ @dataclasses.dataclass(kw_only=True)
343
+ class DisconnectRequest:
344
+ """Request for disconnect."""
345
+
346
+
347
+ @dataclasses.dataclass(kw_only=True)
348
+ class DisconnectResponse:
349
+ """Response for disconnect."""
350
+
351
+
352
+ @dataclasses.dataclass(kw_only=True)
353
+ class GetDefaultNetworkCarriersRequest:
354
+ """Request for getDefaultNetworkCarriers."""
355
+
356
+ node_id: str = ""
357
+ """Id of the node to read the default network carriers from."""
358
+
359
+
360
+ @dataclasses.dataclass(kw_only=True)
361
+ class GetDefaultNetworkCarriersResponse:
362
+ """Response for getDefaultNetworkCarriers."""
363
+
364
+ carriers: list[DefaultNetworkCarrier] = dataclasses.field(default_factory=list)
365
+ """The default network carriers of the node. Empty when none are configured."""
366
+
367
+
368
+ @dataclasses.dataclass(kw_only=True)
369
+ class GetLocalNodeIdRequest:
370
+ """Request for getLocalNodeId."""
371
+
372
+
373
+ @dataclasses.dataclass(kw_only=True)
374
+ class GetLocalNodeIdResponse:
375
+ """Response for getLocalNodeId."""
376
+
377
+ node_id: str = ""
378
+ """Id of the node hosting the API."""
379
+ is_authenticated: bool = False
380
+ """True if the node holds a sign-in to a hub server. It may still be disconnected
381
+ from it at the moment.
382
+ """
383
+
384
+
385
+ @dataclasses.dataclass(kw_only=True)
386
+ class GetNodeRequest:
387
+ """Request for getNode."""
388
+
389
+ node_id: str = ""
390
+ """Id of the node to get information about, for example the id returned by
391
+ getLocalNodeId.
392
+ """
393
+
394
+
395
+ @dataclasses.dataclass(kw_only=True)
396
+ class GetNodeResponse:
397
+ """Response for getNode."""
398
+
399
+ node: HubNode = dataclasses.field(default_factory=lambda: HubNode())
400
+ """Information about the node."""
401
+
402
+
403
+ @dataclasses.dataclass(kw_only=True)
404
+ class GetNodesRequest:
405
+ """Filters for listing the nodes of the hub server. All given filters must match for
406
+ a node to be included.
407
+ """
408
+
409
+ metadata_filters: dict[str, NodeMetadataItem] = dataclasses.field(default_factory=dict)
410
+ """Metadata filters keyed by metadata key. A node is included only if it has every
411
+ key with an equal value of the same type. Leave empty to not filter by metadata.
412
+ """
413
+ service_filters: list[NodeService] = dataclasses.field(default_factory=list)
414
+ """Service filters. A node is included only if it offers every listed service. Leave
415
+ empty to not filter by service.
416
+ """
417
+
418
+
419
+ @dataclasses.dataclass(kw_only=True)
420
+ class GetNodesResponse:
421
+ """Response for getNodes."""
422
+
423
+ nodes: list[HubNode] = dataclasses.field(default_factory=list)
424
+ """The nodes matching the filters."""
425
+
426
+
427
+ @dataclasses.dataclass(kw_only=True)
428
+ class HubNode:
429
+ """Information about a node."""
430
+
431
+ id: str = ""
432
+ """Unique id of the node."""
433
+ name: str = ""
434
+ """Human readable name of the node."""
435
+ online: bool = False
436
+ """Whether the node is currently online and connected to the hub server."""
437
+ services: list[NodeService] = dataclasses.field(default_factory=list)
438
+ """Services offered by the node."""
439
+ metadata: NodeMetadata = dataclasses.field(default_factory=lambda: NodeMetadata())
440
+ """Metadata of the node."""
441
+
442
+
443
+ @dataclasses.dataclass(kw_only=True)
444
+ class NodeMetadata:
445
+ """User defined key/value metadata attached to a node."""
446
+
447
+ items: dict[str, NodeMetadataItem] = dataclasses.field(default_factory=dict)
448
+ """Metadata items keyed by name."""
449
+
450
+
451
+ @dataclasses.dataclass(kw_only=True)
452
+ class NodeMetadataItem:
453
+ """A single metadata value of a node. Set exactly one of the value fields."""
454
+
455
+ bytes_value: bytes | None = None
456
+ """Raw bytes value."""
457
+ string_value: str | None = None
458
+ """Text value."""
459
+ int_value: int | None = None
460
+ """Signed 64-bit integer value."""
461
+ uint_value: int | None = None
462
+ """Unsigned 64-bit integer value."""
463
+ double_value: float | None = None
464
+ """64-bit floating point value."""
465
+ float_value: float | None = None
466
+ """32-bit floating point value."""
467
+ bool_value: bool | None = None
468
+ """Boolean value."""
469
+
470
+
471
+ @dataclasses.dataclass(kw_only=True)
472
+ class RemoveNodeRequest:
473
+ """Request for removeNode."""
474
+
475
+ node_id: str = ""
476
+ """Id of the node to remove."""
477
+
478
+
479
+ @dataclasses.dataclass(kw_only=True)
480
+ class RemoveNodeResponse:
481
+ """Response for removeNode."""
482
+
483
+
484
+ @dataclasses.dataclass(kw_only=True)
485
+ class SetDefaultNetworkCarriersRequest:
486
+ """Request for setDefaultNetworkCarriers."""
487
+
488
+ node_id: str = ""
489
+ """Id of the node to set the default network carriers on."""
490
+ carriers: DefaultNetworkCarriers | None = None
491
+ """The new default network carriers, replacing the current ones. Leave unset to
492
+ remove all default carriers.
493
+ """
494
+
495
+
496
+ @dataclasses.dataclass(kw_only=True)
497
+ class SetDefaultNetworkCarriersResponse:
498
+ """Response for setDefaultNetworkCarriers."""
499
+
500
+
501
+ @dataclasses.dataclass(kw_only=True)
502
+ class SetNodeRequest:
503
+ """Request for setNode."""
504
+
505
+ node_id: str = ""
506
+ """Id of the node to change."""
507
+ name: str = ""
508
+ """New name of the node. Example: `edge-node-1`"""
509
+ metadata: NodeMetadata = dataclasses.field(default_factory=lambda: NodeMetadata())
510
+ """New metadata of the node. Replaces all existing metadata, so leaving it empty
511
+ removes the metadata.
512
+ """
513
+
514
+
515
+ @dataclasses.dataclass(kw_only=True)
516
+ class SetNodeResponse:
517
+ """Response for setNode."""
518
+
519
+ node: HubNode = dataclasses.field(default_factory=lambda: HubNode())
520
+ """The node information after the change."""
521
+
522
+
523
+ @dataclasses.dataclass(kw_only=True)
524
+ class StreamConnectionStateRequest:
525
+ """Request for streamConnectionState."""
526
+
527
+
528
+ @dataclasses.dataclass(kw_only=True)
529
+ class StreamConnectionStateResponse:
530
+ """A connection state update."""
531
+
532
+ state: ConnectionState = ConnectionState.UNAUTHENTICATED
533
+ """The current connection state."""
534
+
535
+
536
+ @dataclasses.dataclass(kw_only=True)
537
+ class StreamNodesInitialResponse:
538
+ """The nodes of the hub server when the stream opened."""
539
+
540
+ nodes: list[HubNode] = dataclasses.field(default_factory=list)
541
+ """The nodes matching the filters."""
542
+
543
+
544
+ @dataclasses.dataclass(kw_only=True)
545
+ class StreamNodesResponse:
546
+ """A message on the streamNodes stream."""
547
+
548
+ initial_response: StreamNodesInitialResponse | None = None
549
+ """Sent once as the first message, with the nodes matching the filters when the
550
+ stream opened.
551
+ """
552
+ update_response: StreamNodesUpdateResponse | None = None
553
+ """Sent for every later change to a node."""
554
+
555
+
556
+ @dataclasses.dataclass(kw_only=True)
557
+ class StreamNodesUpdateResponse:
558
+ """A change to a single node. Exactly one field is set, telling what changed."""
559
+
560
+ connected_node: HubNode | None = None
561
+ """The node connected to the hub server."""
562
+ disconnected_node: HubNode | None = None
563
+ """The node disconnected from the hub server."""
564
+ authenticated_node: HubNode | None = None
565
+ """The node was authenticated with the hub server."""
566
+ deauthenticated_node: HubNode | None = None
567
+ """The node was deauthenticated and removed from the hub server."""
568
+ updated_metadata_node: HubNode | None = None
569
+ """The node's metadata changed."""
570
+ updated_name_node: HubNode | None = None
571
+ """The node's name changed."""
572
+
573
+
574
+ @dataclasses.dataclass(kw_only=True)
575
+ class DownloadAppLogFileRequest:
576
+ """Selects the node's application log file. Takes no parameters."""
577
+
578
+
579
+ @dataclasses.dataclass(kw_only=True)
580
+ class DownloadLogFileChunk:
581
+ """One message of a log file download: either a piece of the file or an error."""
582
+
583
+ error: str | None = None
584
+ """Why the file could not be read, for example because it does not exist. No more
585
+ chunks follow.
586
+ """
587
+ file_chunk: LogFileChunk | None = None
588
+ """The next piece of the file."""
589
+
590
+
591
+ @dataclasses.dataclass(kw_only=True)
592
+ class DownloadLogFileRequest:
593
+ """Downloads one log file from a node."""
594
+
595
+ node_id: str = ""
596
+ """ID of the node that holds the log file."""
597
+ app_log_file_request: DownloadAppLogFileRequest | None = None
598
+ """Download the node's application log."""
599
+ pipeline_run_log_file_request: DownloadPipelineRunLogFileRequest | None = None
600
+ """Download the log of a pipeline run."""
601
+ network_log_file_request: DownloadNetworkLogFileRequest | None = None
602
+ """Download the log of a network."""
603
+ network_instance_log_file_request: DownloadNetworkInstanceLogFileRequest | None = None
604
+ """Download the log of a network instance."""
605
+
606
+
607
+ @dataclasses.dataclass(kw_only=True)
608
+ class DownloadNetworkInstanceLogFileRequest:
609
+ """Selects the log file of a network instance."""
610
+
611
+ network_instance_id: str = ""
612
+ """ID of the network instance. Must not be empty."""
613
+
614
+
615
+ @dataclasses.dataclass(kw_only=True)
616
+ class DownloadNetworkLogFileRequest:
617
+ """Selects the log file of a network."""
618
+
619
+ network_id: str = ""
620
+ """ID of the network. Must not be empty."""
621
+
622
+
623
+ @dataclasses.dataclass(kw_only=True)
624
+ class DownloadPipelineRunLogFileRequest:
625
+ """Selects the log file of a pipeline run."""
626
+
627
+ pipeline_run_id: str = ""
628
+ """ID of the pipeline run. Must not be empty."""
629
+
630
+
631
+ @dataclasses.dataclass(kw_only=True)
632
+ class LogFileChunk:
633
+ """A piece of a log file."""
634
+
635
+ content: bytes = b""
636
+ """Raw file bytes, up to 64 KiB per chunk."""
637
+
638
+
639
+ @dataclasses.dataclass(kw_only=True)
640
+ class Message:
641
+ """A single log entry."""
642
+
643
+ timestamp: datetime.datetime | None = None
644
+ """When the entry was logged."""
645
+ level: Level = Level.STATE
646
+ """Severity of the entry."""
647
+ message: str = ""
648
+ """The log text. Holds the whole raw line when no message could be extracted from
649
+ it.
650
+ """
651
+ data: str = ""
652
+ """The raw log line when it is valid JSON, so structured fields can be read from it.
653
+ Empty otherwise.
654
+ """
655
+
656
+
657
+ @dataclasses.dataclass(kw_only=True)
658
+ class Messages:
659
+ """A batch of log entries, oldest first."""
660
+
661
+ messages: list[Message] = dataclasses.field(default_factory=list)
662
+ """The log entries."""
663
+
664
+
665
+ @dataclasses.dataclass(kw_only=True)
666
+ class OpenAppLogStreamRequest:
667
+ """Selects the node's application log. Takes no parameters."""
668
+
669
+
670
+ @dataclasses.dataclass(kw_only=True)
671
+ class LoggingOpenLogStreamRequest:
672
+ """Opens a stream of log messages from one log on a node."""
673
+
674
+ node_id: str = ""
675
+ """ID of the node whose log to stream."""
676
+ options: Options = dataclasses.field(default_factory=lambda: Options())
677
+ """Stream options. When unset, only new entries are sent."""
678
+ app_log_stream_request: OpenAppLogStreamRequest | None = None
679
+ """Stream the node's application log."""
680
+ pipeline_run_log_stream_request: OpenPipelineRunLogStreamRequest | None = None
681
+ """Stream the log of a pipeline run."""
682
+ network_log_stream_request: LoggingOpenNetworkLogStreamRequest | None = None
683
+ """Stream the log of a network."""
684
+ network_instance_log_stream_request: LoggingOpenNetworkInstanceLogStreamRequest | None = None
685
+ """Stream the log of a network instance."""
686
+
687
+
688
+ @dataclasses.dataclass(kw_only=True)
689
+ class LoggingOpenNetworkInstanceLogStreamRequest:
690
+ """Selects the log of a network instance."""
691
+
692
+ network_instance_id: str = ""
693
+ """ID of the network instance. Must not be empty."""
694
+
695
+
696
+ @dataclasses.dataclass(kw_only=True)
697
+ class LoggingOpenNetworkLogStreamRequest:
698
+ """Selects the log of a network."""
699
+
700
+ network_id: str = ""
701
+ """ID of the network. Must not be empty."""
702
+
703
+
704
+ @dataclasses.dataclass(kw_only=True)
705
+ class OpenPipelineRunLogStreamRequest:
706
+ """Selects the log of a pipeline run."""
707
+
708
+ pipeline_run_id: str = ""
709
+ """ID of the pipeline run. Must not be empty."""
710
+
711
+
712
+ @dataclasses.dataclass(kw_only=True)
713
+ class Options:
714
+ """Options for opening a log stream."""
715
+
716
+ lines: int | None = None
717
+ """The number of entries."""
718
+
719
+
720
+ @dataclasses.dataclass(kw_only=True)
721
+ class BoolMetric:
722
+ """A metric holding a true or false value."""
723
+
724
+ value: bool | None = None
725
+ """The value. Unset when the metric has no value in this sample."""
726
+ description: str = ""
727
+ """Human-readable description of what the metric measures."""
728
+ unit: str | None = None
729
+ """The unit. Unset when the value has no unit."""
730
+
731
+
732
+ @dataclasses.dataclass(kw_only=True)
733
+ class Collection:
734
+ """A group of related metrics, such as the memory metrics of a node."""
735
+
736
+ path: str = ""
737
+ """Path identifying the collection, for example `/system/memory`."""
738
+ metrics: dict[str, Metric] = dataclasses.field(default_factory=dict)
739
+ """The metrics in the collection, keyed by metric name."""
740
+
741
+
742
+ @dataclasses.dataclass(kw_only=True)
743
+ class Constant:
744
+ """A metric whose value never changes, such as the CPU architecture."""
745
+
746
+ uint64: int | None = None
747
+ """An unsigned integer value."""
748
+ int64: int | None = None
749
+ """A signed integer value."""
750
+ float64: float | None = None
751
+ """A floating-point value."""
752
+ boolean: bool | None = None
753
+ """A true or false value."""
754
+ string: str | None = None
755
+ """A text value."""
756
+ description: str = ""
757
+ """Human-readable description of what the constant describes."""
758
+ unit: str | None = None
759
+ """The unit. Unset when the value has no unit."""
760
+
761
+
762
+ @dataclasses.dataclass(kw_only=True)
763
+ class Enum8Metric:
764
+ """A metric holding one value out of a fixed set of named values."""
765
+
766
+ value: int | None = None
767
+ """The index. Unset when the metric has no value in this sample."""
768
+ description: str = ""
769
+ """Human-readable description of what the metric measures."""
770
+ values: dict[int, Enum8Metric_EnumValue] = dataclasses.field(default_factory=dict)
771
+ """The values the metric can take, keyed by index."""
772
+ unit: str | None = None
773
+ """The unit. Unset when the value has no unit."""
774
+
775
+
776
+ @dataclasses.dataclass(kw_only=True)
777
+ class Enum8Metric_EnumValue:
778
+ """A named value the metric can take."""
779
+
780
+ name: str = ""
781
+ """Name of the value."""
782
+ description: str | None = None
783
+ """The description."""
784
+
785
+
786
+ @dataclasses.dataclass(kw_only=True)
787
+ class Float32Metric:
788
+ """A metric holding a 32-bit floating-point value."""
789
+
790
+ value: float | None = None
791
+ """The value. Unset when the metric has no value in this sample."""
792
+ description: str = ""
793
+ """Human-readable description of what the metric measures."""
794
+ kind: Kind = Kind.GAUGE
795
+ """Whether the value can only increase or can also decrease."""
796
+ unit: str | None = None
797
+ """The unit, for example `bytes` or `percent`. Unset when the value has no unit."""
798
+ min: float | None = None
799
+ """The minimum. Unset when there is no known lower bound."""
800
+ max: float | None = None
801
+ """The maximum. Unset when there is no known upper bound."""
802
+
803
+
804
+ @dataclasses.dataclass(kw_only=True)
805
+ class Float64Metric:
806
+ """A metric holding a 64-bit floating-point value."""
807
+
808
+ value: float | None = None
809
+ """The value. Unset when the metric has no value in this sample."""
810
+ description: str = ""
811
+ """Human-readable description of what the metric measures."""
812
+ kind: Kind = Kind.GAUGE
813
+ """Whether the value can only increase or can also decrease."""
814
+ unit: str | None = None
815
+ """The unit, for example `bytes` or `percent`. Unset when the value has no unit."""
816
+ min: float | None = None
817
+ """The minimum. Unset when there is no known lower bound."""
818
+ max: float | None = None
819
+ """The maximum. Unset when there is no known upper bound."""
820
+
821
+
822
+ @dataclasses.dataclass(kw_only=True)
823
+ class Int32Metric:
824
+ """A metric holding a signed 32-bit integer value."""
825
+
826
+ value: int | None = None
827
+ """The value. Unset when the metric has no value in this sample."""
828
+ description: str = ""
829
+ """Human-readable description of what the metric measures."""
830
+ kind: Kind = Kind.GAUGE
831
+ """Whether the value can only increase or can also decrease."""
832
+ unit: str | None = None
833
+ """The unit, for example `bytes` or `percent`. Unset when the value has no unit."""
834
+ min: int | None = None
835
+ """The minimum. Unset when there is no known lower bound."""
836
+ max: int | None = None
837
+ """The maximum. Unset when there is no known upper bound."""
838
+
839
+
840
+ @dataclasses.dataclass(kw_only=True)
841
+ class Int64Metric:
842
+ """A metric holding a signed 64-bit integer value."""
843
+
844
+ value: int | None = None
845
+ """The value. Unset when the metric has no value in this sample."""
846
+ description: str = ""
847
+ """Human-readable description of what the metric measures."""
848
+ kind: Kind = Kind.GAUGE
849
+ """Whether the value can only increase or can also decrease."""
850
+ unit: str | None = None
851
+ """The unit, for example `bytes` or `percent`. Unset when the value has no unit."""
852
+ min: int | None = None
853
+ """The minimum. Unset when there is no known lower bound."""
854
+ max: int | None = None
855
+ """The maximum. Unset when there is no known upper bound."""
856
+
857
+
858
+ @dataclasses.dataclass(kw_only=True)
859
+ class Metric:
860
+ """A single metric. Exactly one of the fields is set, depending on the metric's
861
+ type.
862
+ """
863
+
864
+ constant: Constant | None = None
865
+ """A metric with a fixed value."""
866
+ uint64: UInt64Metric | None = None
867
+ """An unsigned 64-bit integer metric."""
868
+ int64: Int64Metric | None = None
869
+ """A signed 64-bit integer metric."""
870
+ uint32: UInt32Metric | None = None
871
+ """An unsigned 32-bit integer metric."""
872
+ int32: Int32Metric | None = None
873
+ """A signed 32-bit integer metric."""
874
+ float64: Float64Metric | None = None
875
+ """A 64-bit floating-point metric."""
876
+ float32: Float32Metric | None = None
877
+ """A 32-bit floating-point metric."""
878
+ boolean: BoolMetric | None = None
879
+ """A true or false metric."""
880
+ enum8: Enum8Metric | None = None
881
+ """A metric with one of a fixed set of named values."""
882
+
883
+
884
+ @dataclasses.dataclass(kw_only=True)
885
+ class UInt32Metric:
886
+ """A metric holding an unsigned 32-bit integer value."""
887
+
888
+ value: int | None = None
889
+ """The value. Unset when the metric has no value in this sample."""
890
+ description: str = ""
891
+ """Human-readable description of what the metric measures."""
892
+ kind: Kind = Kind.GAUGE
893
+ """Whether the value can only increase or can also decrease."""
894
+ unit: str | None = None
895
+ """The unit, for example `bytes` or `percent`. Unset when the value has no unit."""
896
+ min: int | None = None
897
+ """The minimum. Unset when there is no known lower bound."""
898
+ max: int | None = None
899
+ """The maximum. Unset when there is no known upper bound."""
900
+
901
+
902
+ @dataclasses.dataclass(kw_only=True)
903
+ class UInt64Metric:
904
+ """A metric holding an unsigned 64-bit integer value."""
905
+
906
+ value: int | None = None
907
+ """The value. Unset when the metric has no value in this sample."""
908
+ description: str = ""
909
+ """Human-readable description of what the metric measures."""
910
+ kind: Kind = Kind.GAUGE
911
+ """Whether the value can only increase or can also decrease."""
912
+ unit: str | None = None
913
+ """The unit, for example `bytes` or `percent`. Unset when the value has no unit."""
914
+ min: int | None = None
915
+ """The minimum. Unset when there is no known lower bound."""
916
+ max: int | None = None
917
+ """The maximum. Unset when there is no known upper bound."""
918
+
919
+
920
+ @dataclasses.dataclass(kw_only=True)
921
+ class Address:
922
+ """The address of a carrier."""
923
+
924
+ ip: str = ""
925
+ """The IP address. Example: `192.168.1.20`"""
926
+ port: int = 0
927
+ """The port. Example: `3425`"""
928
+ external_ip: str | None = None
929
+ """The external IP address of the carrier. Example: `203.0.113.10`"""
930
+
931
+
932
+ @dataclasses.dataclass(kw_only=True)
933
+ class Blueprint:
934
+ """A network blueprint."""
935
+
936
+ name: str = ""
937
+ """The name of the blueprint."""
938
+ template: str = ""
939
+ """The template that renders a pipeline configuration. Placeholders such as `{{
940
+ .node.ip }}` are filled in with network and node parameters.
941
+ """
942
+ read_only: bool = False
943
+ """Whether the blueprint is read-only. The built-in blueprints are read-only and
944
+ cannot be updated or deleted.
945
+ """
946
+
947
+
948
+ @dataclasses.dataclass(kw_only=True)
949
+ class BlueprintWrite:
950
+ """The editable fields of a blueprint."""
951
+
952
+ name: str = ""
953
+ """The name of the blueprint. Example: `UDP relay`"""
954
+ template: str = ""
955
+ """The template that renders a pipeline configuration. Placeholders such as `{{
956
+ .node.ip }}` are filled in with network and node parameters.
957
+ """
958
+
959
+
960
+ @dataclasses.dataclass(kw_only=True)
961
+ class Carrier:
962
+ """A connection a node uses to carry network traffic."""
963
+
964
+ address: Address | None = None
965
+ """The IP address and port of the carrier."""
966
+ interface: str | None = None
967
+ """The name of the network interface to use. Example: `eth0`"""
968
+ bandwidth_priority: int | None = None
969
+ """The bandwidth priority of the carrier."""
970
+
971
+
972
+ @dataclasses.dataclass(kw_only=True)
973
+ class CreateBlueprintRequest:
974
+ """Request to create a blueprint."""
975
+
976
+ blueprint: BlueprintWrite = dataclasses.field(default_factory=lambda: BlueprintWrite())
977
+ """The blueprint to create. Required."""
978
+
979
+
980
+ @dataclasses.dataclass(kw_only=True)
981
+ class CreateBlueprintResponse:
982
+ """The created blueprint."""
983
+
984
+ id: str = ""
985
+ """The generated ID of the blueprint."""
986
+ blueprint: Blueprint = dataclasses.field(default_factory=lambda: Blueprint())
987
+ """The created blueprint."""
988
+
989
+
990
+ @dataclasses.dataclass(kw_only=True)
991
+ class CreateNetworkRequest:
992
+ """Request to create a network."""
993
+
994
+ network: Network = dataclasses.field(default_factory=lambda: Network())
995
+ """The network to create. Required."""
996
+
997
+
998
+ @dataclasses.dataclass(kw_only=True)
999
+ class CreateNetworkResponse:
1000
+ """The created network."""
1001
+
1002
+ id: str = ""
1003
+ """The generated ID of the network."""
1004
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1005
+ """The created network."""
1006
+
1007
+
1008
+ @dataclasses.dataclass(kw_only=True)
1009
+ class DeleteBlueprintRequest:
1010
+ """Request to delete a blueprint."""
1011
+
1012
+ id: str = ""
1013
+ """The ID of the blueprint to delete."""
1014
+
1015
+
1016
+ @dataclasses.dataclass(kw_only=True)
1017
+ class DeleteBlueprintResponse:
1018
+ """Empty response to a blueprint deletion."""
1019
+
1020
+
1021
+ @dataclasses.dataclass(kw_only=True)
1022
+ class DeleteNetworkRequest:
1023
+ """Request to delete a network."""
1024
+
1025
+ id: str = ""
1026
+ """The ID of the network to delete."""
1027
+
1028
+
1029
+ @dataclasses.dataclass(kw_only=True)
1030
+ class DeleteNetworkResponse:
1031
+ """Empty response to a network deletion."""
1032
+
1033
+
1034
+ @dataclasses.dataclass(kw_only=True)
1035
+ class GetBlueprintRequest:
1036
+ """Request for a single blueprint."""
1037
+
1038
+ id: str = ""
1039
+ """The ID of the blueprint to fetch."""
1040
+
1041
+
1042
+ @dataclasses.dataclass(kw_only=True)
1043
+ class GetBlueprintResponse:
1044
+ """A blueprint and its ID."""
1045
+
1046
+ id: str = ""
1047
+ """The ID of the blueprint."""
1048
+ blueprint: Blueprint = dataclasses.field(default_factory=lambda: Blueprint())
1049
+ """The blueprint."""
1050
+
1051
+
1052
+ @dataclasses.dataclass(kw_only=True)
1053
+ class GetBlueprintsRequest:
1054
+ """Request for all blueprints."""
1055
+
1056
+
1057
+ @dataclasses.dataclass(kw_only=True)
1058
+ class GetBlueprintsResponse:
1059
+ """All blueprints."""
1060
+
1061
+ blueprints: list[GetBlueprintResponse] = dataclasses.field(default_factory=list)
1062
+ """The blueprints with their IDs."""
1063
+
1064
+
1065
+ @dataclasses.dataclass(kw_only=True)
1066
+ class GetNetworkInstancesRequest:
1067
+ """Request for the network instances on a node."""
1068
+
1069
+ node_id: str = ""
1070
+ """The ID of the node to fetch network instances from."""
1071
+
1072
+
1073
+ @dataclasses.dataclass(kw_only=True)
1074
+ class GetNetworkInstancesResponse:
1075
+ """The network instances on a node."""
1076
+
1077
+ network_instances: list[NetworkInstance] = dataclasses.field(default_factory=list)
1078
+ """The network instances of the node."""
1079
+
1080
+
1081
+ @dataclasses.dataclass(kw_only=True)
1082
+ class GetNetworkPipelinesRequest:
1083
+ """Request for the network instance pipelines on a node. Leave a filter unset to not
1084
+ filter on it.
1085
+ """
1086
+
1087
+ node_id: str = ""
1088
+ """The ID of the node to fetch network instance pipelines from."""
1089
+ optional_network_id: str | None = None
1090
+ """Only return pipelines belonging to this network ID."""
1091
+ optional_instance_id: str | None = None
1092
+ """Only return pipelines belonging to this network instance ID."""
1093
+ optional_blueprint_id: str | None = None
1094
+ """Only return pipelines generated from this blueprint ID."""
1095
+
1096
+
1097
+ @dataclasses.dataclass(kw_only=True)
1098
+ class GetNetworkPipelinesResponse:
1099
+ """The matching network instance pipelines."""
1100
+
1101
+ network_pipelines: list[NetworkPipeline] = dataclasses.field(default_factory=list)
1102
+ """The network instance pipelines."""
1103
+
1104
+
1105
+ @dataclasses.dataclass(kw_only=True)
1106
+ class GetNetworkRequest:
1107
+ """Request for a single network."""
1108
+
1109
+ id: str = ""
1110
+ """The ID of the network to fetch."""
1111
+
1112
+
1113
+ @dataclasses.dataclass(kw_only=True)
1114
+ class GetNetworkResponse:
1115
+ """A network and its ID."""
1116
+
1117
+ id: str = ""
1118
+ """The ID of the network."""
1119
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1120
+ """The network."""
1121
+
1122
+
1123
+ @dataclasses.dataclass(kw_only=True)
1124
+ class GetNetworksRequest:
1125
+ """Request for all networks."""
1126
+
1127
+
1128
+ @dataclasses.dataclass(kw_only=True)
1129
+ class GetNetworksResponse:
1130
+ """All networks."""
1131
+
1132
+ networks: list[GetNetworkResponse] = dataclasses.field(default_factory=list)
1133
+ """The networks with their IDs."""
1134
+
1135
+
1136
+ @dataclasses.dataclass(kw_only=True)
1137
+ class Network:
1138
+ """A virtual network connecting nodes through a central relay node."""
1139
+
1140
+ name: str = ""
1141
+ """The name of the network. Must not be empty. Example: `Office network`"""
1142
+ subnet_cidr: str = ""
1143
+ """The IPv4 subnet, in CIDR notation, that node IP addresses are assigned from.
1144
+ Example: `100.65.254.0/24`
1145
+ """
1146
+ blueprints: NetworkBlueprints = dataclasses.field(default_factory=lambda: NetworkBlueprints())
1147
+ """The blueprints used to generate the network's pipelines."""
1148
+ parameters: str = ""
1149
+ """Parameters available to the network's blueprints, as a JSON object. May be empty.
1150
+ Example: `{ "raft_timeout": 9000, "loss_emulation_percentage": 1 }`
1151
+ """
1152
+ relay_node_id: str = ""
1153
+ """The node ID of the relay node. Must be the node that has networks enabled."""
1154
+ nodes: list[NetworksNode] = dataclasses.field(default_factory=list)
1155
+ """The nodes in the network, each with its assigned IP address and carriers."""
1156
+
1157
+
1158
+ @dataclasses.dataclass(kw_only=True)
1159
+ class NetworkBlueprints:
1160
+ """The blueprint IDs used for each role in a network. A blueprint left unset falls
1161
+ back to the default blueprint for that role configured on the networks node.
1162
+ """
1163
+
1164
+ relay_blueprint: str | None = None
1165
+ """ID of the blueprint deployed to the relay node."""
1166
+ relay_client_blueprint: str | None = None
1167
+ """ID of the blueprint deployed to the relay node once for every client in the
1168
+ network.
1169
+ """
1170
+ client_blueprint: str | None = None
1171
+ """ID of the blueprint deployed to every node in the network."""
1172
+
1173
+
1174
+ @dataclasses.dataclass(kw_only=True)
1175
+ class NetworkInstance:
1176
+ """A network's instance on one node."""
1177
+
1178
+ id: str = ""
1179
+ """The ID of the network instance."""
1180
+ network_id: str = ""
1181
+ """The ID of the network the instance belongs to."""
1182
+ network_name: str = ""
1183
+ """The name of the network the instance belongs to."""
1184
+ pipeline_ids: list[str] = dataclasses.field(default_factory=list)
1185
+ """The IDs of the pipelines managed by the network instance."""
1186
+
1187
+
1188
+ @dataclasses.dataclass(kw_only=True)
1189
+ class NetworkInstanceLogStreamMessages:
1190
+ """A batch of network instance log messages."""
1191
+
1192
+ messages: list[Message] = dataclasses.field(default_factory=list)
1193
+ """The log messages."""
1194
+
1195
+
1196
+ @dataclasses.dataclass(kw_only=True)
1197
+ class NetworkLogStreamMessages:
1198
+ """A batch of network log messages."""
1199
+
1200
+ messages: list[Message] = dataclasses.field(default_factory=list)
1201
+ """The log messages."""
1202
+
1203
+
1204
+ @dataclasses.dataclass(kw_only=True)
1205
+ class NetworkPipeline:
1206
+ """A pipeline generated for a network instance from one of the network's blueprints.
1207
+ """
1208
+
1209
+ id: str = ""
1210
+ """The ID of this network instance pipeline record. Not the same as `pipeline_id`.
1211
+ """
1212
+ network_id: str = ""
1213
+ """The ID of the network the pipeline belongs to."""
1214
+ instance_id: str = ""
1215
+ """The ID of the network instance the pipeline belongs to."""
1216
+ blueprint_id: str = ""
1217
+ """The ID of the blueprint the pipeline was generated from."""
1218
+ pipeline_id: str = ""
1219
+ """The ID of the pipeline on the node."""
1220
+ pipeline_name: str = ""
1221
+ """The name of the pipeline."""
1222
+ enabled: bool = False
1223
+ """Whether the pipeline is enabled, meaning it should be running."""
1224
+
1225
+
1226
+ @dataclasses.dataclass(kw_only=True)
1227
+ class NetworksNode:
1228
+ """A node's membership in a network."""
1229
+
1230
+ node_id: str = ""
1231
+ """The ID of the node."""
1232
+ node_ip: str = ""
1233
+ """The node's IP address in the network. Must be unique within the network and
1234
+ cannot be changed. Example: `100.65.254.2`
1235
+ """
1236
+ carriers: list[Carrier] = dataclasses.field(default_factory=list)
1237
+ """The carriers the node uses in the network. Each carrier of the relay node needs
1238
+ an `address`; each carrier of a client needs an `address` or an `interface`.
1239
+ """
1240
+ type: NodeType = NodeType.NODE_TYPE_CLIENT
1241
+ """The node's role, derived from the network's `relay_node_id`. Cannot be changed
1242
+ directly.
1243
+ """
1244
+ parameters: str = ""
1245
+ """Parameters for this node available to the blueprints, as a JSON object. May be
1246
+ empty.
1247
+ """
1248
+
1249
+
1250
+ @dataclasses.dataclass(kw_only=True)
1251
+ class NetworksOpenNetworkInstanceLogStreamRequest:
1252
+ """Request to stream the log of a network instance."""
1253
+
1254
+ node_id: str = ""
1255
+ """The ID of the node the network instance runs on."""
1256
+ network_instance_id: str = ""
1257
+ """The ID of the network instance whose log to stream."""
1258
+ options: Options = dataclasses.field(default_factory=lambda: Options())
1259
+ """Log stream options, such as how many past lines to send first."""
1260
+
1261
+
1262
+ @dataclasses.dataclass(kw_only=True)
1263
+ class NetworksOpenNetworkLogStreamRequest:
1264
+ """Request to stream the log of a network."""
1265
+
1266
+ network_id: str = ""
1267
+ """The ID of the network whose log to stream."""
1268
+ options: Options = dataclasses.field(default_factory=lambda: Options())
1269
+ """Log stream options, such as how many past lines to send first."""
1270
+
1271
+
1272
+ @dataclasses.dataclass(kw_only=True)
1273
+ class StreamNetworkInstanceCreateEvent:
1274
+ """Sent when a network instance is created."""
1275
+
1276
+ network_instance: NetworkInstance = dataclasses.field(default_factory=lambda: NetworkInstance())
1277
+ """The created network instance."""
1278
+
1279
+
1280
+ @dataclasses.dataclass(kw_only=True)
1281
+ class StreamNetworkInstanceDeleteEvent:
1282
+ """Sent when a network instance is deleted."""
1283
+
1284
+ network_instance: NetworkInstance = dataclasses.field(default_factory=lambda: NetworkInstance())
1285
+ """The deleted network instance."""
1286
+
1287
+
1288
+ @dataclasses.dataclass(kw_only=True)
1289
+ class StreamNetworkInstanceEvent:
1290
+ """A change to a network instance."""
1291
+
1292
+ create: StreamNetworkInstanceCreateEvent | None = None
1293
+ """A network instance was created."""
1294
+ update: StreamNetworkInstanceUpdateEvent | None = None
1295
+ """A network instance was updated."""
1296
+ delete: StreamNetworkInstanceDeleteEvent | None = None
1297
+ """A network instance was deleted."""
1298
+
1299
+
1300
+ @dataclasses.dataclass(kw_only=True)
1301
+ class StreamNetworkInstanceUpdateEvent:
1302
+ """Sent when a network instance or one of its pipelines is updated."""
1303
+
1304
+ network_instance: NetworkInstance = dataclasses.field(default_factory=lambda: NetworkInstance())
1305
+ """The network instance after the update."""
1306
+
1307
+
1308
+ @dataclasses.dataclass(kw_only=True)
1309
+ class StreamNetworkInstancesRequest:
1310
+ """Request to stream network instance changes on a node."""
1311
+
1312
+ node_id: str = ""
1313
+ """The ID of the node to stream network instances from."""
1314
+
1315
+
1316
+ @dataclasses.dataclass(kw_only=True)
1317
+ class StreamNetworkPipelineCreateEvent:
1318
+ """Sent when a network instance pipeline is created."""
1319
+
1320
+ network_pipeline: NetworkPipeline = dataclasses.field(default_factory=lambda: NetworkPipeline())
1321
+ """The created pipeline."""
1322
+
1323
+
1324
+ @dataclasses.dataclass(kw_only=True)
1325
+ class StreamNetworkPipelineDeleteEvent:
1326
+ """Sent when a network instance pipeline is deleted."""
1327
+
1328
+ network_pipeline: NetworkPipeline = dataclasses.field(default_factory=lambda: NetworkPipeline())
1329
+ """The deleted pipeline."""
1330
+
1331
+
1332
+ @dataclasses.dataclass(kw_only=True)
1333
+ class StreamNetworkPipelineEvent:
1334
+ """A change to a network instance pipeline."""
1335
+
1336
+ create: StreamNetworkPipelineCreateEvent | None = None
1337
+ """A pipeline was created."""
1338
+ update: StreamNetworkPipelineUpdateEvent | None = None
1339
+ """A pipeline was updated."""
1340
+ delete: StreamNetworkPipelineDeleteEvent | None = None
1341
+ """A pipeline was deleted."""
1342
+
1343
+
1344
+ @dataclasses.dataclass(kw_only=True)
1345
+ class StreamNetworkPipelineUpdateEvent:
1346
+ """Sent when a network instance pipeline is updated."""
1347
+
1348
+ network_pipeline: NetworkPipeline = dataclasses.field(default_factory=lambda: NetworkPipeline())
1349
+ """The pipeline after the update."""
1350
+
1351
+
1352
+ @dataclasses.dataclass(kw_only=True)
1353
+ class StreamNetworkPipelinesRequest:
1354
+ """Request to stream network instance pipeline changes on a node."""
1355
+
1356
+ node_id: str = ""
1357
+ """The ID of the node to stream network instance pipelines from."""
1358
+
1359
+
1360
+ @dataclasses.dataclass(kw_only=True)
1361
+ class StreamNetworksCreateEvent:
1362
+ """Sent when a network is created."""
1363
+
1364
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1365
+ """The created network."""
1366
+
1367
+
1368
+ @dataclasses.dataclass(kw_only=True)
1369
+ class StreamNetworksDeleteEvent:
1370
+ """Sent when a network is deleted."""
1371
+
1372
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1373
+ """The deleted network."""
1374
+
1375
+
1376
+ @dataclasses.dataclass(kw_only=True)
1377
+ class StreamNetworksEvent:
1378
+ """A change to a network."""
1379
+
1380
+ create: StreamNetworksCreateEvent | None = None
1381
+ """A network was created."""
1382
+ update: StreamNetworksUpdateEvent | None = None
1383
+ """A network was updated."""
1384
+ delete: StreamNetworksDeleteEvent | None = None
1385
+ """A network was deleted."""
1386
+
1387
+
1388
+ @dataclasses.dataclass(kw_only=True)
1389
+ class StreamNetworksRequest:
1390
+ """Request to stream network changes."""
1391
+
1392
+
1393
+ @dataclasses.dataclass(kw_only=True)
1394
+ class StreamNetworksUpdateEvent:
1395
+ """Sent when a network is updated."""
1396
+
1397
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1398
+ """The network after the update."""
1399
+
1400
+
1401
+ @dataclasses.dataclass(kw_only=True)
1402
+ class ToggleNetworkPipelineRequest:
1403
+ """Request to toggle a network instance pipeline. Set exactly one of
1404
+ `optional_pipeline_id` and `optional_instance_pipeline_id`.
1405
+ """
1406
+
1407
+ node_id: str = ""
1408
+ """The ID of the node the pipeline runs on."""
1409
+ optional_pipeline_id: str | None = None
1410
+ """The pipeline's `pipeline_id`."""
1411
+ optional_instance_pipeline_id: str | None = None
1412
+ """The pipeline's `id`."""
1413
+
1414
+
1415
+ @dataclasses.dataclass(kw_only=True)
1416
+ class ToggleNetworkPipelineResponse:
1417
+ """Empty response to a pipeline toggle."""
1418
+
1419
+
1420
+ @dataclasses.dataclass(kw_only=True)
1421
+ class UpdateBlueprintRequest:
1422
+ """Request to update a blueprint."""
1423
+
1424
+ id: str = ""
1425
+ """The ID of the blueprint to update."""
1426
+ blueprint: BlueprintWrite = dataclasses.field(default_factory=lambda: BlueprintWrite())
1427
+ """The new name and template. Required."""
1428
+
1429
+
1430
+ @dataclasses.dataclass(kw_only=True)
1431
+ class UpdateBlueprintResponse:
1432
+ """The updated blueprint."""
1433
+
1434
+ id: str = ""
1435
+ """The ID of the blueprint."""
1436
+ blueprint: Blueprint = dataclasses.field(default_factory=lambda: Blueprint())
1437
+ """The blueprint after the update."""
1438
+
1439
+
1440
+ @dataclasses.dataclass(kw_only=True)
1441
+ class UpdateNetworkRequest:
1442
+ """Request to update a network."""
1443
+
1444
+ id: str = ""
1445
+ """The ID of the network to update."""
1446
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1447
+ """The new settings of the network. Required. All fields replace the current values,
1448
+ except `nodes`: leave it empty to keep the nodes unchanged, or list every current
1449
+ node to edit their carriers and parameters.
1450
+ """
1451
+
1452
+
1453
+ @dataclasses.dataclass(kw_only=True)
1454
+ class UpdateNetworkResponse:
1455
+ """The updated network."""
1456
+
1457
+ id: str = ""
1458
+ """The ID of the network."""
1459
+ network: Network = dataclasses.field(default_factory=lambda: Network())
1460
+ """The network after the update."""
1461
+
1462
+
1463
+ @dataclasses.dataclass(kw_only=True)
1464
+ class CreatePipelineRequest:
1465
+ """Request to create a pipeline."""
1466
+
1467
+ node_id: str = ""
1468
+ """ID of the node to create the pipeline on."""
1469
+ name: str = ""
1470
+ """Name of the pipeline. Example: `UDP tunnel`"""
1471
+ json_config: str = ""
1472
+ """The pipeline configuration as a JSON string."""
1473
+ restart_policy: RestartPolicy = dataclasses.field(default_factory=lambda: RestartPolicy())
1474
+ """The restart policy of the pipeline. Leave unset to never restart."""
1475
+ startup_policy: StartupPolicy = dataclasses.field(default_factory=lambda: StartupPolicy())
1476
+ """The startup policy of the pipeline. Leave unset to start it manually only."""
1477
+ default_logging_level: Level | None = None
1478
+ """The default logging level."""
1479
+ node_reference_id: str | None = None
1480
+ """ID of the related node."""
1481
+ instructions_timeout: int | None = None
1482
+ """The timeout in seconds. Must be greater than 0. Example: `30`"""
1483
+ cpu_pin: int | None = None
1484
+ """Zero indexed CPU thread number. Must be lower than the node's thread count."""
1485
+ performance_mode: bool | None = None
1486
+ """True to run the pinned thread in performance mode."""
1487
+
1488
+
1489
+ @dataclasses.dataclass(kw_only=True)
1490
+ class CreatePipelineResponse:
1491
+ """The created pipeline."""
1492
+
1493
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1494
+ """The new pipeline, including its generated `id`."""
1495
+
1496
+
1497
+ @dataclasses.dataclass(kw_only=True)
1498
+ class DeletePipelineRequest:
1499
+ """Request to delete a pipeline."""
1500
+
1501
+ node_id: str = ""
1502
+ """ID of the node that hosts the pipeline."""
1503
+ id: str = ""
1504
+ """ID of the pipeline to delete."""
1505
+
1506
+
1507
+ @dataclasses.dataclass(kw_only=True)
1508
+ class DeletePipelineResponse:
1509
+ """Empty response, returned when the pipeline is deleted."""
1510
+
1511
+
1512
+ @dataclasses.dataclass(kw_only=True)
1513
+ class GetPipelineByIdRequest:
1514
+ """Request to get a pipeline by its ID."""
1515
+
1516
+ node_id: str = ""
1517
+ """ID of the node that hosts the pipeline."""
1518
+ id: str = ""
1519
+ """ID of the pipeline."""
1520
+
1521
+
1522
+ @dataclasses.dataclass(kw_only=True)
1523
+ class GetPipelineByIdResponse:
1524
+ """The requested pipeline."""
1525
+
1526
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1527
+ """The pipeline with the given ID."""
1528
+
1529
+
1530
+ @dataclasses.dataclass(kw_only=True)
1531
+ class GetPipelineByNameRequest:
1532
+ """Request to get a pipeline by its name."""
1533
+
1534
+ node_id: str = ""
1535
+ """ID of the node that hosts the pipeline."""
1536
+ name: str = ""
1537
+ """Exact name of the pipeline. Example: `UDP tunnel`"""
1538
+
1539
+
1540
+ @dataclasses.dataclass(kw_only=True)
1541
+ class GetPipelineByNameResponse:
1542
+ """The requested pipeline."""
1543
+
1544
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1545
+ """The pipeline with the given name."""
1546
+
1547
+
1548
+ @dataclasses.dataclass(kw_only=True)
1549
+ class GetPipelineByRunIdRequest:
1550
+ """Request to get the pipeline that a run belongs to."""
1551
+
1552
+ node_id: str = ""
1553
+ """ID of the node that hosts the pipeline."""
1554
+ id: str = ""
1555
+ """ID of the run."""
1556
+
1557
+
1558
+ @dataclasses.dataclass(kw_only=True)
1559
+ class GetPipelineByRunIdResponse:
1560
+ """The pipeline that the run belongs to."""
1561
+
1562
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1563
+ """The pipeline of the given run."""
1564
+
1565
+
1566
+ @dataclasses.dataclass(kw_only=True)
1567
+ class GetPipelinesRequest:
1568
+ """Request to list all pipelines."""
1569
+
1570
+ node_id: str = ""
1571
+ """ID of the node to list the pipelines of."""
1572
+
1573
+
1574
+ @dataclasses.dataclass(kw_only=True)
1575
+ class GetPipelinesResponse:
1576
+ """All pipelines on the node."""
1577
+
1578
+ pipelines: list[Pipeline] = dataclasses.field(default_factory=list)
1579
+ """The pipelines, in no particular order."""
1580
+
1581
+
1582
+ @dataclasses.dataclass(kw_only=True)
1583
+ class Kpi:
1584
+ """The value of one KPI defined in the pipeline configuration."""
1585
+
1586
+ id: str = ""
1587
+ """ID of the KPI."""
1588
+ field: str = ""
1589
+ """Path of the KPI field this value was evaluated for, such as `value`."""
1590
+ error: str | None = None
1591
+ """The KPI could not be evaluated. Holds the error message."""
1592
+ none_value: bool | None = None
1593
+ """The KPI expression evaluated to no value."""
1594
+ unresolved: str | None = None
1595
+ """A metric the KPI uses could not be resolved. Holds the reason."""
1596
+ string_value: str | None = None
1597
+ """A text value."""
1598
+ uint64_value: int | None = None
1599
+ """An unsigned 64-bit integer value."""
1600
+ int64_value: int | None = None
1601
+ """A signed 64-bit integer value."""
1602
+ uint32_value: int | None = None
1603
+ """An unsigned 32-bit integer value."""
1604
+ int32_value: int | None = None
1605
+ """A signed 32-bit integer value."""
1606
+ float64_value: float | None = None
1607
+ """A 64-bit floating point value."""
1608
+ float32_value: float | None = None
1609
+ """A 32-bit floating point value."""
1610
+ bool_value: bool | None = None
1611
+ """A boolean value."""
1612
+ enum8_value: int | None = None
1613
+ """An 8-bit enum value, as its number."""
1614
+
1615
+
1616
+ @dataclasses.dataclass(kw_only=True)
1617
+ class LogStreamMessages:
1618
+ """A batch of log messages from a pipeline run."""
1619
+
1620
+ messages: list[Message] = dataclasses.field(default_factory=list)
1621
+ """The log messages."""
1622
+
1623
+
1624
+ @dataclasses.dataclass(kw_only=True)
1625
+ class PipelineOpenLogStreamRequest:
1626
+ """Request to stream the logs of a pipeline run."""
1627
+
1628
+ node_id: str = ""
1629
+ """ID of the node that hosts the run."""
1630
+ run_id: str = ""
1631
+ """ID of the run to stream logs from."""
1632
+ options: Options = dataclasses.field(default_factory=lambda: Options())
1633
+ """Stream options, such as how many past lines to send first. Leave unset to receive
1634
+ only new messages.
1635
+ """
1636
+
1637
+
1638
+ @dataclasses.dataclass(kw_only=True)
1639
+ class OpenTelemetryStreamRequest:
1640
+ """Request to stream the telemetry of a pipeline run."""
1641
+
1642
+ node_id: str = ""
1643
+ """ID of the node that hosts the run."""
1644
+ run_id: str = ""
1645
+ """ID of the run to stream telemetry from."""
1646
+
1647
+
1648
+ @dataclasses.dataclass(kw_only=True)
1649
+ class Pipeline:
1650
+ """A pipeline is an executable composition of network components."""
1651
+
1652
+ id: str = ""
1653
+ """ID of the pipeline."""
1654
+ name: str = ""
1655
+ """Name of the pipeline."""
1656
+ started: bool = False
1657
+ """Whether the pipeline is started."""
1658
+ current_run: str | None = None
1659
+ """ID of the current run."""
1660
+ json_config: str = ""
1661
+ """The pipeline configuration as a pretty-printed JSON string."""
1662
+ config_compatability: ConfigCompatability = ConfigCompatability.COMPATIBLE
1663
+ """Whether the node can run the configuration. Read-only."""
1664
+ restart_policy: RestartPolicy = dataclasses.field(default_factory=lambda: RestartPolicy())
1665
+ """The restart policy of the pipeline."""
1666
+ startup_policy: StartupPolicy = dataclasses.field(default_factory=lambda: StartupPolicy())
1667
+ """The startup policy of the pipeline."""
1668
+ default_logging_level: Level = Level.STATE
1669
+ """The default logging level of the pipeline."""
1670
+ node_reference_id: str | None = None
1671
+ """ID of the related node."""
1672
+ instructions_timeout: int = 0
1673
+ """Time in seconds before a pipeline instruction is considered timed out."""
1674
+ cpu_pin: int | None = None
1675
+ """Zero indexed CPU thread number."""
1676
+ performance_mode: bool = False
1677
+ """Whether the pinned CPU thread runs in performance mode."""
1678
+
1679
+
1680
+ @dataclasses.dataclass(kw_only=True)
1681
+ class RestartPolicy:
1682
+ """Decides whether a pipeline is restarted when its run ends. Unset means never."""
1683
+
1684
+ never: RestartPolicyNever | None = None
1685
+ """Never restart the pipeline."""
1686
+ always: RestartPolicyAlways | None = None
1687
+ """Restart the pipeline each time its run ends."""
1688
+ on_failure: RestartPolicyOnFailure | None = None
1689
+ """Restart the pipeline only when its run fails."""
1690
+
1691
+
1692
+ @dataclasses.dataclass(kw_only=True)
1693
+ class RestartPolicyAlways:
1694
+ """Restart the pipeline each time its run ends."""
1695
+
1696
+ max_restarts: int = 0
1697
+ """Maximum number of restarts. 0 means restart without limit."""
1698
+
1699
+
1700
+ @dataclasses.dataclass(kw_only=True)
1701
+ class RestartPolicyNever:
1702
+ """Never restart the pipeline when its run ends."""
1703
+
1704
+
1705
+ @dataclasses.dataclass(kw_only=True)
1706
+ class RestartPolicyOnFailure:
1707
+ """Restart the pipeline only when its run fails unexpectedly with a non-zero exit
1708
+ code.
1709
+ """
1710
+
1711
+ max_restarts: int = 0
1712
+ """Maximum number of restarts. 0 means restart without limit."""
1713
+
1714
+
1715
+ @dataclasses.dataclass(kw_only=True)
1716
+ class StartPipelineRequest:
1717
+ """Request to start a pipeline."""
1718
+
1719
+ node_id: str = ""
1720
+ """ID of the node that hosts the pipeline."""
1721
+ id: str | None = None
1722
+ """ID of the pipeline."""
1723
+ name: str | None = None
1724
+ """Exact name of the pipeline. Fails if more than one pipeline has this name.
1725
+ Example: `UDP tunnel`
1726
+ """
1727
+
1728
+
1729
+ @dataclasses.dataclass(kw_only=True)
1730
+ class StartPipelineResponse:
1731
+ """The run created by starting the pipeline."""
1732
+
1733
+ run_id: str = ""
1734
+ """ID of the new run."""
1735
+
1736
+
1737
+ @dataclasses.dataclass(kw_only=True)
1738
+ class StartupPolicy:
1739
+ """Decides whether a pipeline starts by itself when the node's application starts.
1740
+ Unset means manual.
1741
+ """
1742
+
1743
+ manual: StartupPolicyManual | None = None
1744
+ """Only start the pipeline when asked to."""
1745
+ auto: StartupPolicyAuto | None = None
1746
+ """Start the pipeline automatically when the application starts."""
1747
+
1748
+
1749
+ @dataclasses.dataclass(kw_only=True)
1750
+ class StartupPolicyAuto:
1751
+ """Start the pipeline automatically when the application starts."""
1752
+
1753
+
1754
+ @dataclasses.dataclass(kw_only=True)
1755
+ class StartupPolicyManual:
1756
+ """Do not start the pipeline automatically when the application starts."""
1757
+
1758
+
1759
+ @dataclasses.dataclass(kw_only=True)
1760
+ class StopPipelineRequest:
1761
+ """Request to stop a pipeline."""
1762
+
1763
+ node_id: str = ""
1764
+ """ID of the node that hosts the pipeline."""
1765
+ id: str | None = None
1766
+ """ID of the pipeline."""
1767
+ name: str | None = None
1768
+ """Exact name of the pipeline. Fails if more than one pipeline has this name.
1769
+ Example: `UDP tunnel`
1770
+ """
1771
+ run_id: str | None = None
1772
+ """ID of the pipeline's current run."""
1773
+
1774
+
1775
+ @dataclasses.dataclass(kw_only=True)
1776
+ class StopPipelineResponse:
1777
+ """Empty response, returned when the stop is requested."""
1778
+
1779
+
1780
+ @dataclasses.dataclass(kw_only=True)
1781
+ class StreamPipelinesCreateEvent:
1782
+ """A pipeline was created."""
1783
+
1784
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1785
+ """The created pipeline."""
1786
+
1787
+
1788
+ @dataclasses.dataclass(kw_only=True)
1789
+ class StreamPipelinesDeleteEvent:
1790
+ """A pipeline was deleted."""
1791
+
1792
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1793
+ """The deleted pipeline, as it was before deletion."""
1794
+
1795
+
1796
+ @dataclasses.dataclass(kw_only=True)
1797
+ class StreamPipelinesEvent:
1798
+ """A single change to a pipeline."""
1799
+
1800
+ create: StreamPipelinesCreateEvent | None = None
1801
+ """Sent when a pipeline is created."""
1802
+ update: StreamPipelinesUpdateEvent | None = None
1803
+ """Sent when a pipeline is changed, started or stopped."""
1804
+ delete: StreamPipelinesDeleteEvent | None = None
1805
+ """Sent when a pipeline is deleted."""
1806
+
1807
+
1808
+ @dataclasses.dataclass(kw_only=True)
1809
+ class StreamPipelinesRequest:
1810
+ """Request to stream pipeline changes."""
1811
+
1812
+ node_id: str = ""
1813
+ """ID of the node to stream pipeline changes from."""
1814
+
1815
+
1816
+ @dataclasses.dataclass(kw_only=True)
1817
+ class StreamPipelinesUpdateEvent:
1818
+ """A pipeline was changed, started or stopped."""
1819
+
1820
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1821
+ """The pipeline after the change."""
1822
+
1823
+
1824
+ @dataclasses.dataclass(kw_only=True)
1825
+ class TelemetrySample:
1826
+ """One telemetry sample of a pipeline run."""
1827
+
1828
+ metric_collections: list[Collection] = dataclasses.field(default_factory=list)
1829
+ """The metrics of the run."""
1830
+ kpis: list[Kpi] = dataclasses.field(default_factory=list)
1831
+ """The KPI values of the run."""
1832
+ timestamp: datetime.datetime | None = None
1833
+ """When the sample was taken."""
1834
+
1835
+
1836
+ @dataclasses.dataclass(kw_only=True)
1837
+ class UpdatePipelineRequest:
1838
+ """Request to update a pipeline. All settings are replaced, so send the full set of
1839
+ values you want to keep.
1840
+ """
1841
+
1842
+ node_id: str = ""
1843
+ """ID of the node that hosts the pipeline."""
1844
+ id: str = ""
1845
+ """ID of the pipeline to update."""
1846
+ name: str = ""
1847
+ """New name of the pipeline. Example: `UDP tunnel`"""
1848
+ json_config: str = ""
1849
+ """New pipeline configuration as a JSON string."""
1850
+ restart_policy: RestartPolicy = dataclasses.field(default_factory=lambda: RestartPolicy())
1851
+ """New restart policy of the pipeline. Unset means never restart."""
1852
+ startup_policy: StartupPolicy = dataclasses.field(default_factory=lambda: StartupPolicy())
1853
+ """New startup policy of the pipeline. Unset means start manually only."""
1854
+ default_logging_level: Level = Level.STATE
1855
+ """New default logging level of the pipeline. Unset means `STATE`, not the `INFO`
1856
+ default used on create.
1857
+ """
1858
+ instructions_timeout: int = 0
1859
+ """New time in seconds before a pipeline instruction is considered timed out. Must
1860
+ be greater than 0. Example: `30`
1861
+ """
1862
+ cpu_pin: int | None = None
1863
+ """Zero indexed CPU thread number. Must be lower than the node's thread count."""
1864
+ performance_mode: bool | None = None
1865
+ """True to run the pinned thread in performance mode."""
1866
+ node_reference_id: str | None = None
1867
+ """ID of the related node."""
1868
+ force_restart: bool = False
1869
+ """If true and the pipeline is running, the pipeline is restarted when the new
1870
+ configuration cannot be applied to the current run. The call then returns once
1871
+ the new run is running.
1872
+ """
1873
+
1874
+
1875
+ @dataclasses.dataclass(kw_only=True)
1876
+ class UpdatePipelineResponse:
1877
+ """The updated pipeline."""
1878
+
1879
+ pipeline: Pipeline = dataclasses.field(default_factory=lambda: Pipeline())
1880
+ """The pipeline after the update."""
1881
+
1882
+
1883
+ @dataclasses.dataclass(kw_only=True)
1884
+ class Flow:
1885
+ """Traffic between two endpoints on one interface, tracked in both directions. A
1886
+ flow is dropped once it closes or has been idle for a while.
1887
+ """
1888
+
1889
+ interface: str = ""
1890
+ """Name of the interface the flow was captured on."""
1891
+ protocol: str = ""
1892
+ """`TCP`, `UDP`, `ICMP`, or the IP protocol number for any other protocol."""
1893
+ source_ip: str = ""
1894
+ """IP address of the side that opened the flow, as far as the node can tell."""
1895
+ source_port: int = 0
1896
+ """Port on the source side. Zero for protocols without ports."""
1897
+ destination_ip: str = ""
1898
+ """IP address of the side the flow was opened towards."""
1899
+ destination_port: int = 0
1900
+ """Port on the destination side. Zero for protocols without ports."""
1901
+ sent_bytes: int = 0
1902
+ """Total bytes sent from source to destination."""
1903
+ sent_packets: int = 0
1904
+ """Total packets sent from source to destination."""
1905
+ received_bytes: int = 0
1906
+ """Total bytes sent from destination to source."""
1907
+ received_packets: int = 0
1908
+ """Total packets sent from destination to source."""
1909
+ bits_per_second: int = 0
1910
+ """Current throughput over both directions, in bits per second."""
1911
+ first_seen: datetime.datetime | None = None
1912
+ """When the first packet of the flow was captured."""
1913
+ last_seen: datetime.datetime | None = None
1914
+ """When the latest packet of the flow was captured."""
1915
+
1916
+
1917
+ @dataclasses.dataclass(kw_only=True)
1918
+ class FlowsSample:
1919
+ """The network flows of a node at one point in time."""
1920
+
1921
+ timestamp: datetime.datetime | None = None
1922
+ """When the snapshot was taken."""
1923
+ flows: list[Flow] = dataclasses.field(default_factory=list)
1924
+ """Every flow the node currently tracks. Empty when none have been captured."""
1925
+
1926
+
1927
+ @dataclasses.dataclass(kw_only=True)
1928
+ class MetricsSample:
1929
+ """The resource metrics of a node at one point in time."""
1930
+
1931
+ timestamp: datetime.datetime | None = None
1932
+ """When the sample was taken."""
1933
+ collections: list[Collection] = dataclasses.field(default_factory=list)
1934
+ """The metrics, grouped into collections such as `/system/memory` and
1935
+ `/system/disk`.
1936
+ """
1937
+
1938
+
1939
+ @dataclasses.dataclass(kw_only=True)
1940
+ class OpenFlowsStreamRequest:
1941
+ """Opens a stream of network flow snapshots."""
1942
+
1943
+ node_id: str = ""
1944
+ """ID of the node to read flows from."""
1945
+
1946
+
1947
+ @dataclasses.dataclass(kw_only=True)
1948
+ class OpenMetricsStreamRequest:
1949
+ """Opens a stream of resource metrics."""
1950
+
1951
+ node_id: str = ""
1952
+ """ID of the node to read metrics from."""
1953
+
1954
+
1955
+ class BlueprintsClient:
1956
+ """A blueprint is a template that generates the pipeline configuration a node runs
1957
+ in a network. It uses [Go template syntax](https://pkg.go.dev/text/template), and
1958
+ placeholders such as the node's IP address and carriers are filled in for each
1959
+ node. Every network uses three blueprints: one for the relay node, one the relay
1960
+ runs for every client, and one for every client node. The built-in blueprints are
1961
+ read-only; create your own to change how networks carry traffic. Blueprints are
1962
+ stored on the connected node that has networks enabled, and calls wait until that
1963
+ node is connected.
1964
+ """
1965
+
1966
+ def __init__(self, transport: Transport) -> None:
1967
+ self._transport = transport
1968
+
1969
+ def get_blueprint(
1970
+ self,
1971
+ *,
1972
+ id: str = "",
1973
+ ) -> GetBlueprintResponse:
1974
+ """Get a single blueprint.
1975
+
1976
+ Args:
1977
+ id: The ID of the blueprint to fetch.
1978
+ """
1979
+ return self._transport.unary(
1980
+ [Route("GET", "/v1/blueprints/{id}", "")],
1981
+ GetBlueprintRequest(id=id),
1982
+ GetBlueprintResponse,
1983
+ )
1984
+
1985
+ def get_blueprints(self) -> GetBlueprintsResponse:
1986
+ """Get all blueprints, including the built-in read-only ones."""
1987
+ return self._transport.unary(
1988
+ [Route("GET", "/v1/blueprints", "")],
1989
+ GetBlueprintsRequest(),
1990
+ GetBlueprintsResponse,
1991
+ )
1992
+
1993
+ def create_blueprint(
1994
+ self,
1995
+ *,
1996
+ blueprint: BlueprintWrite | None = None,
1997
+ ) -> CreateBlueprintResponse:
1998
+ """Create a blueprint and return it.
1999
+
2000
+ Args:
2001
+ blueprint: The blueprint to create. Required.
2002
+ """
2003
+ return self._transport.unary(
2004
+ [Route("POST", "/v1/blueprints", "blueprint")],
2005
+ CreateBlueprintRequest(blueprint=blueprint or BlueprintWrite()),
2006
+ CreateBlueprintResponse,
2007
+ )
2008
+
2009
+ def update_blueprint(
2010
+ self,
2011
+ *,
2012
+ id: str = "",
2013
+ blueprint: BlueprintWrite | None = None,
2014
+ ) -> UpdateBlueprintResponse:
2015
+ """Replace a blueprint and return the updated blueprint. Networks using the
2016
+ blueprint have their pipelines regenerated. Fails with a permission error for
2017
+ read-only blueprints.
2018
+
2019
+ Args:
2020
+ id: The ID of the blueprint to update.
2021
+ blueprint: The new name and template. Required.
2022
+ """
2023
+ return self._transport.unary(
2024
+ [Route("PUT", "/v1/blueprints/{id}", "blueprint")],
2025
+ UpdateBlueprintRequest(id=id, blueprint=blueprint or BlueprintWrite()),
2026
+ UpdateBlueprintResponse,
2027
+ )
2028
+
2029
+ def delete_blueprint(
2030
+ self,
2031
+ *,
2032
+ id: str = "",
2033
+ ) -> DeleteBlueprintResponse:
2034
+ """Delete a blueprint. Fails with a permission error for read-only blueprints.
2035
+
2036
+ Args:
2037
+ id: The ID of the blueprint to delete.
2038
+ """
2039
+ return self._transport.unary(
2040
+ [Route("DELETE", "/v1/blueprints/{id}", "")],
2041
+ DeleteBlueprintRequest(id=id),
2042
+ DeleteBlueprintResponse,
2043
+ )
2044
+
2045
+
2046
+ class ConfigServiceClient:
2047
+ """Settings stored in the configuration of a node. Use this service to read and
2048
+ change them on any node, such as the carriers a node uses by default when it
2049
+ joins a network.
2050
+ """
2051
+
2052
+ def __init__(self, transport: Transport) -> None:
2053
+ self._transport = transport
2054
+
2055
+ def get_default_network_carriers(
2056
+ self,
2057
+ *,
2058
+ node_id: str = "",
2059
+ ) -> GetDefaultNetworkCarriersResponse:
2060
+ """Get the default network carriers of a node. These are the carriers the node
2061
+ receives every time it joins a new network. Returns an empty list when none
2062
+ are configured.
2063
+
2064
+ Args:
2065
+ node_id: Id of the node to read the default network carriers from.
2066
+ """
2067
+ return self._transport.unary(
2068
+ [Route("GET", "/v1/nodes/{node_id}/default-network-carriers", "")],
2069
+ GetDefaultNetworkCarriersRequest(node_id=node_id),
2070
+ GetDefaultNetworkCarriersResponse,
2071
+ )
2072
+
2073
+ def set_default_network_carriers(
2074
+ self,
2075
+ *,
2076
+ node_id: str = "",
2077
+ carriers: DefaultNetworkCarriers | None = None,
2078
+ ) -> SetDefaultNetworkCarriersResponse:
2079
+ """Replace the default network carriers of a node. The new carriers apply to
2080
+ networks the node joins afterwards.
2081
+
2082
+ Args:
2083
+ node_id: Id of the node to set the default network carriers on.
2084
+ carriers: The new default network carriers, replacing the current ones.
2085
+ Leave unset to remove all default carriers.
2086
+ """
2087
+ return self._transport.unary(
2088
+ [Route("PUT", "/v1/nodes/{node_id}/default-network-carriers", "carriers")],
2089
+ SetDefaultNetworkCarriersRequest(node_id=node_id, carriers=carriers),
2090
+ SetDefaultNetworkCarriersResponse,
2091
+ )
2092
+
2093
+
2094
+ class HubClientServiceClient:
2095
+ """The hub client is the part of every node that connects it to a hub server, the
2096
+ control plane that lets connected nodes find and manage each other. Use this
2097
+ service to sign the node hosting the API in to a hub server, disconnect it,
2098
+ follow its connection state, and read or change the details of nodes.
2099
+ """
2100
+
2101
+ def __init__(self, transport: Transport) -> None:
2102
+ self._transport = transport
2103
+
2104
+ def get_local_node_id(self) -> GetLocalNodeIdResponse:
2105
+ """Get the ID of the node hosting the API, and whether it is authenticated with
2106
+ a hub server.
2107
+ """
2108
+ return self._transport.unary(
2109
+ [Route("GET", "/v1/hub-client/local-node-id", "")],
2110
+ GetLocalNodeIdRequest(),
2111
+ GetLocalNodeIdResponse,
2112
+ )
2113
+
2114
+ def get_node(
2115
+ self,
2116
+ *,
2117
+ node_id: str = "",
2118
+ ) -> GetNodeResponse:
2119
+ """Get the details of a node. Fails with Unavailable when the node cannot be
2120
+ reached.
2121
+
2122
+ Args:
2123
+ node_id: Id of the node to get information about, for example the id
2124
+ returned by getLocalNodeId.
2125
+ """
2126
+ return self._transport.unary(
2127
+ [Route("GET", "/v1/nodes/{node_id}", "")],
2128
+ GetNodeRequest(node_id=node_id),
2129
+ GetNodeResponse,
2130
+ )
2131
+
2132
+ def set_node(
2133
+ self,
2134
+ *,
2135
+ node_id: str = "",
2136
+ name: str = "",
2137
+ metadata: NodeMetadata | None = None,
2138
+ ) -> SetNodeResponse:
2139
+ """Change the details of a node, replacing the current values. Fails with
2140
+ PermissionDenied when the node's configuration comes from a config file.
2141
+
2142
+ Args:
2143
+ node_id: Id of the node to change.
2144
+ name: New name of the node. Example: `edge-node-1`
2145
+ metadata: New metadata of the node. Replaces all existing metadata, so
2146
+ leaving it empty removes the metadata.
2147
+ """
2148
+ return self._transport.unary(
2149
+ [Route("PUT", "/v1/nodes/{node_id}", "*")],
2150
+ SetNodeRequest(
2151
+ node_id=node_id,
2152
+ name=name,
2153
+ metadata=metadata or NodeMetadata(),
2154
+ ),
2155
+ SetNodeResponse,
2156
+ )
2157
+
2158
+ def authenticate_by_request(
2159
+ self,
2160
+ *,
2161
+ hub_server_address: str = "",
2162
+ ) -> AuthenticateByRequestResponse:
2163
+ """Ask a hub server to authenticate the node hosting the API, and wait for the
2164
+ hub server to accept or reject the request. On success the node stays
2165
+ authenticated, also after a restart. Fails with AlreadyExists if the node is
2166
+ already authenticated, Unauthenticated if the request was rejected,
2167
+ DeadlineExceeded if the hub server did not answer in time, Unavailable if the
2168
+ hub server could not be reached, and NotFound if the hub server does not
2169
+ accept authentication by request.
2170
+
2171
+ Args:
2172
+ hub_server_address: HTTP or HTTPS address of the hub server. Example:
2173
+ `http://127.0.0.1:8769`
2174
+ """
2175
+ return self._transport.unary(
2176
+ [Route("POST", "/v1/hub-client/authenticate-by-request", "*")],
2177
+ AuthenticateByRequestRequest(hub_server_address=hub_server_address),
2178
+ AuthenticateByRequestResponse,
2179
+ )
2180
+
2181
+ def disconnect(self) -> DisconnectResponse:
2182
+ """Disconnect the node hosting the API from its hub server. The node always
2183
+ leaves, even if the hub server could not remove it from its list of nodes.
2184
+ """
2185
+ return self._transport.unary(
2186
+ [Route("POST", "/v1/hub-client/disconnect", "*")],
2187
+ DisconnectRequest(),
2188
+ DisconnectResponse,
2189
+ )
2190
+
2191
+ def stream_connection_state(self) -> ServerStream[StreamConnectionStateResponse]:
2192
+ """Stream the connection state between the node hosting the API and its hub
2193
+ server. The current state is sent first, then a new message every time the
2194
+ state changes. The stream stays open until the caller closes it.
2195
+ """
2196
+ return self._transport.server_stream(
2197
+ [Route("GET", "/v1/streams/hub-client/connection-state", "")],
2198
+ StreamConnectionStateRequest(),
2199
+ StreamConnectionStateResponse,
2200
+ )
2201
+
2202
+
2203
+ class HubServerServiceClient:
2204
+ """A hub server is the control plane of a NanoPing setup: nodes authenticate with
2205
+ it, and every node on the same hub can find and manage the others. Use this
2206
+ service to list the nodes on the hub, follow them as they come and go, remove
2207
+ nodes, and approve or reject nodes that ask to join. The node hosting the API
2208
+ must host the hub server or be authenticated with one, otherwise calls fail with
2209
+ FailedPrecondition.
2210
+ """
2211
+
2212
+ def __init__(self, transport: Transport) -> None:
2213
+ self._transport = transport
2214
+
2215
+ def get_nodes(
2216
+ self,
2217
+ *,
2218
+ metadata_filters: Mapping[str, NodeMetadataItem] | None = None,
2219
+ service_filters: Sequence[NodeService] = (),
2220
+ ) -> GetNodesResponse:
2221
+ """Get the nodes authenticated with the hub server, optionally filtered.
2222
+
2223
+ Args:
2224
+ metadata_filters: Metadata filters keyed by metadata key. A node is
2225
+ included only if it has every key with an equal value of the same type.
2226
+ Leave empty to not filter by metadata.
2227
+ service_filters: Service filters. A node is included only if it offers
2228
+ every listed service. Leave empty to not filter by service.
2229
+ """
2230
+ return self._transport.unary(
2231
+ [Route("GET", "/v1/nodes", ""), Route("POST", "/v1/nodes/search", "*")],
2232
+ GetNodesRequest(
2233
+ metadata_filters=dict(metadata_filters or {}),
2234
+ service_filters=list(service_filters),
2235
+ ),
2236
+ GetNodesResponse,
2237
+ )
2238
+
2239
+ def remove_node(
2240
+ self,
2241
+ *,
2242
+ node_id: str = "",
2243
+ ) -> RemoveNodeResponse:
2244
+ """Remove a node from the hub server. This disconnects the node from the hub
2245
+ server and removes it from its networks.
2246
+
2247
+ Args:
2248
+ node_id: Id of the node to remove.
2249
+ """
2250
+ return self._transport.unary(
2251
+ [Route("DELETE", "/v1/nodes/{node_id}", "")],
2252
+ RemoveNodeRequest(node_id=node_id),
2253
+ RemoveNodeResponse,
2254
+ )
2255
+
2256
+ def stream_nodes(
2257
+ self,
2258
+ *,
2259
+ metadata_filters: Mapping[str, NodeMetadataItem] | None = None,
2260
+ service_filters: Sequence[NodeService] = (),
2261
+ ) -> ServerStream[StreamNodesResponse]:
2262
+ """Stream the nodes authenticated with the hub server. The matching nodes are
2263
+ sent first, followed by an update every time a node is authenticated,
2264
+ deauthenticated, connects, disconnects or changes its details. Updates are
2265
+ not filtered. The stream stays open until the caller closes it.
2266
+
2267
+ Args:
2268
+ metadata_filters: Metadata filters keyed by metadata key. A node is
2269
+ included only if it has every key with an equal value of the same type.
2270
+ Leave empty to not filter by metadata.
2271
+ service_filters: Service filters. A node is included only if it offers
2272
+ every listed service. Leave empty to not filter by service.
2273
+ """
2274
+ return self._transport.server_stream(
2275
+ [
2276
+ Route("GET", "/v1/streams/nodes", ""),
2277
+ Route("POST", "/v1/streams/nodes", "*"),
2278
+ ],
2279
+ GetNodesRequest(
2280
+ metadata_filters=dict(metadata_filters or {}),
2281
+ service_filters=list(service_filters),
2282
+ ),
2283
+ StreamNodesResponse,
2284
+ )
2285
+
2286
+ def authentication_by_requests(
2287
+ self,
2288
+ ) -> BidiStream[AuthenticationByRequestAnswer, AuthenticationByRequestRequest]:
2289
+ """Receive the authentication requests sent to the hub server on the node
2290
+ hosting the API, and accept or reject each one. Nothing is sent when the
2291
+ stream opens. A request is sent each time a node asks to authenticate, and
2292
+ the caller answers it by sending an answer for that request.
2293
+ """
2294
+ return self._transport.bidi_stream(
2295
+ Route("POST", "/v1/streams/hub-server/authentication-requests", "*"),
2296
+ AuthenticationByRequestRequest,
2297
+ )
2298
+
2299
+
2300
+ class LoggingServiceClient:
2301
+ """Every node keeps logs: its application log, and a log for each pipeline run,
2302
+ network and network instance. Use this service to follow a log live or to
2303
+ download a complete log file, from any node.
2304
+ """
2305
+
2306
+ def __init__(self, transport: Transport) -> None:
2307
+ self._transport = transport
2308
+
2309
+ def open_log_stream(
2310
+ self,
2311
+ *,
2312
+ node_id: str = "",
2313
+ options: Options | None = None,
2314
+ app_log_stream_request: OpenAppLogStreamRequest | None = None,
2315
+ pipeline_run_log_stream_request: OpenPipelineRunLogStreamRequest | None = None,
2316
+ network_log_stream_request: LoggingOpenNetworkLogStreamRequest | None = None,
2317
+ network_instance_log_stream_request: LoggingOpenNetworkInstanceLogStreamRequest | None = None,
2318
+ ) -> ServerStream[Messages]:
2319
+ """Stream the log messages of one log on a node. The requested number of past
2320
+ entries is sent first, then new entries as they are written. Fails with an
2321
+ invalid argument error when the node is invalid or no log is chosen, and ends
2322
+ with an error when the log cannot be read or the node loses its connection.
2323
+
2324
+ Args:
2325
+ node_id: ID of the node whose log to stream.
2326
+ options: Stream options. When unset, only new entries are sent.
2327
+ app_log_stream_request: Stream the node's application log.
2328
+ pipeline_run_log_stream_request: Stream the log of a pipeline run.
2329
+ network_log_stream_request: Stream the log of a network.
2330
+ network_instance_log_stream_request: Stream the log of a network
2331
+ instance.
2332
+ """
2333
+ return self._transport.server_stream(
2334
+ [Route("POST", "/v1/streams/nodes/{node_id}/logs", "*")],
2335
+ LoggingOpenLogStreamRequest(
2336
+ node_id=node_id,
2337
+ options=options or Options(),
2338
+ app_log_stream_request=app_log_stream_request,
2339
+ pipeline_run_log_stream_request=pipeline_run_log_stream_request,
2340
+ network_log_stream_request=network_log_stream_request,
2341
+ network_instance_log_stream_request=network_instance_log_stream_request,
2342
+ ),
2343
+ Messages,
2344
+ )
2345
+
2346
+ def download_log_file(
2347
+ self,
2348
+ *,
2349
+ node_id: str = "",
2350
+ app_log_file_request: DownloadAppLogFileRequest | None = None,
2351
+ pipeline_run_log_file_request: DownloadPipelineRunLogFileRequest | None = None,
2352
+ network_log_file_request: DownloadNetworkLogFileRequest | None = None,
2353
+ network_instance_log_file_request: DownloadNetworkInstanceLogFileRequest | None = None,
2354
+ ) -> str:
2355
+ """Download one complete log file from a node as a series of chunks. Join the
2356
+ chunks in order to get the file. The stream ends when the whole file has been
2357
+ sent, or after an error chunk when the file could not be read.
2358
+
2359
+ Returns the whole file as text.
2360
+
2361
+ Args:
2362
+ node_id: ID of the node that holds the log file.
2363
+ app_log_file_request: Download the node's application log.
2364
+ pipeline_run_log_file_request: Download the log of a pipeline run.
2365
+ network_log_file_request: Download the log of a network.
2366
+ network_instance_log_file_request: Download the log of a network
2367
+ instance.
2368
+ """
2369
+ return self._transport.text(
2370
+ [Route("GET", "/v1/nodes/{node_id}/log-file", "")],
2371
+ DownloadLogFileRequest(
2372
+ node_id=node_id,
2373
+ app_log_file_request=app_log_file_request,
2374
+ pipeline_run_log_file_request=pipeline_run_log_file_request,
2375
+ network_log_file_request=network_log_file_request,
2376
+ network_instance_log_file_request=network_instance_log_file_request,
2377
+ ),
2378
+ )
2379
+
2380
+
2381
+ class NetworkInstancesClient:
2382
+ """A network instance is a network's presence on one node: the pipelines generated
2383
+ for that node from the network's blueprints. Instances are created, updated and
2384
+ removed automatically when their network changes, so they cannot be managed
2385
+ directly. Use this service to see which networks a node takes part in, follow its
2386
+ network pipelines, turn them on or off, and read their logs. The node needs
2387
+ pipelines enabled.
2388
+ """
2389
+
2390
+ def __init__(self, transport: Transport) -> None:
2391
+ self._transport = transport
2392
+
2393
+ def get_network_instances(
2394
+ self,
2395
+ *,
2396
+ node_id: str = "",
2397
+ ) -> GetNetworkInstancesResponse:
2398
+ """Get all network instances on a node, each with its pipelines.
2399
+
2400
+ Args:
2401
+ node_id: The ID of the node to fetch network instances from.
2402
+ """
2403
+ return self._transport.unary(
2404
+ [Route("GET", "/v1/nodes/{node_id}/network-instances", "")],
2405
+ GetNetworkInstancesRequest(node_id=node_id),
2406
+ GetNetworkInstancesResponse,
2407
+ )
2408
+
2409
+ def stream_network_instances(
2410
+ self,
2411
+ *,
2412
+ node_id: str = "",
2413
+ ) -> ServerStream[StreamNetworkInstanceEvent]:
2414
+ """Stream changes to the network instances on a node. Nothing is sent when the
2415
+ stream opens; an event is sent each time an instance is created, updated or
2416
+ deleted, and an update is also sent when one of its pipelines changes. The
2417
+ stream ends if the connection to the node is lost.
2418
+
2419
+ Args:
2420
+ node_id: The ID of the node to stream network instances from.
2421
+ """
2422
+ return self._transport.server_stream(
2423
+ [Route("GET", "/v1/streams/nodes/{node_id}/network-instances", "")],
2424
+ StreamNetworkInstancesRequest(node_id=node_id),
2425
+ StreamNetworkInstanceEvent,
2426
+ )
2427
+
2428
+ def get_network_pipelines(
2429
+ self,
2430
+ *,
2431
+ node_id: str = "",
2432
+ optional_network_id: str | None = None,
2433
+ optional_instance_id: str | None = None,
2434
+ optional_blueprint_id: str | None = None,
2435
+ ) -> GetNetworkPipelinesResponse:
2436
+ """Get the network instance pipelines on a node, optionally filtered. A pipeline
2437
+ must match every filter that is set.
2438
+
2439
+ Args:
2440
+ node_id: The ID of the node to fetch network instance pipelines from.
2441
+ optional_network_id: Only return pipelines belonging to this network ID.
2442
+ optional_instance_id: Only return pipelines belonging to this network
2443
+ instance ID.
2444
+ optional_blueprint_id: Only return pipelines generated from this
2445
+ blueprint ID.
2446
+ """
2447
+ return self._transport.unary(
2448
+ [Route("GET", "/v1/nodes/{node_id}/network-pipelines", "")],
2449
+ GetNetworkPipelinesRequest(
2450
+ node_id=node_id,
2451
+ optional_network_id=optional_network_id,
2452
+ optional_instance_id=optional_instance_id,
2453
+ optional_blueprint_id=optional_blueprint_id,
2454
+ ),
2455
+ GetNetworkPipelinesResponse,
2456
+ )
2457
+
2458
+ def stream_network_pipelines(
2459
+ self,
2460
+ *,
2461
+ node_id: str = "",
2462
+ ) -> ServerStream[StreamNetworkPipelineEvent]:
2463
+ """Stream changes to the network instance pipelines on a node. Nothing is sent
2464
+ when the stream opens; an event is sent each time a pipeline is created,
2465
+ updated or deleted. The stream ends if the connection to the node is lost.
2466
+
2467
+ Args:
2468
+ node_id: The ID of the node to stream network instance pipelines from.
2469
+ """
2470
+ return self._transport.server_stream(
2471
+ [Route("GET", "/v1/streams/nodes/{node_id}/network-pipelines", "")],
2472
+ StreamNetworkPipelinesRequest(node_id=node_id),
2473
+ StreamNetworkPipelineEvent,
2474
+ )
2475
+
2476
+ def toggle_network_pipeline(
2477
+ self,
2478
+ *,
2479
+ node_id: str = "",
2480
+ optional_pipeline_id: str | None = None,
2481
+ optional_instance_pipeline_id: str | None = None,
2482
+ ) -> ToggleNetworkPipelineResponse:
2483
+ """Enable or disable a network instance pipeline on a node, which starts or
2484
+ stops the pipeline. Each call flips the current state. Fails with a not found
2485
+ error if no matching pipeline exists.
2486
+
2487
+ Args:
2488
+ node_id: The ID of the node the pipeline runs on.
2489
+ optional_pipeline_id: The pipeline's `pipeline_id`.
2490
+ optional_instance_pipeline_id: The pipeline's `id`.
2491
+ """
2492
+ return self._transport.unary(
2493
+ [Route("POST", "/v1/nodes/{node_id}/network-pipelines/toggle", "*")],
2494
+ ToggleNetworkPipelineRequest(
2495
+ node_id=node_id,
2496
+ optional_pipeline_id=optional_pipeline_id,
2497
+ optional_instance_pipeline_id=optional_instance_pipeline_id,
2498
+ ),
2499
+ ToggleNetworkPipelineResponse,
2500
+ )
2501
+
2502
+ def open_log_stream(
2503
+ self,
2504
+ *,
2505
+ node_id: str = "",
2506
+ network_instance_id: str = "",
2507
+ options: Options | None = None,
2508
+ ) -> ServerStream[NetworkInstanceLogStreamMessages]:
2509
+ """Stream the log messages of a network instance on a node. The requested number
2510
+ of past lines is sent first, then new messages as they are logged, until the
2511
+ connection to the node is lost.
2512
+
2513
+ Args:
2514
+ node_id: The ID of the node the network instance runs on.
2515
+ network_instance_id: The ID of the network instance whose log to stream.
2516
+ options: Log stream options, such as how many past lines to send first.
2517
+ """
2518
+ return self._transport.server_stream(
2519
+ [
2520
+ Route("GET", "/v1/streams/nodes/{node_id}/network-instances/{network_instance_id}/logs", ""),
2521
+ ],
2522
+ NetworksOpenNetworkInstanceLogStreamRequest(
2523
+ node_id=node_id,
2524
+ network_instance_id=network_instance_id,
2525
+ options=options or Options(),
2526
+ ),
2527
+ NetworkInstanceLogStreamMessages,
2528
+ )
2529
+
2530
+
2531
+ class NetworksClient:
2532
+ """A network is a virtual network that connects nodes as if they shared a local
2533
+ network, giving each node its own IP address. All traffic flows through a central
2534
+ relay node. When a network is created or changed, the pipelines each node needs
2535
+ are generated from the network's blueprints and deployed automatically. Use this
2536
+ service to create and change networks and to follow their changes and logs.
2537
+ Networks are stored on the connected node that has networks enabled, and calls
2538
+ wait until that node is connected.
2539
+ """
2540
+
2541
+ def __init__(self, transport: Transport) -> None:
2542
+ self._transport = transport
2543
+
2544
+ def get_network(
2545
+ self,
2546
+ *,
2547
+ id: str = "",
2548
+ ) -> GetNetworkResponse:
2549
+ """Get a single network.
2550
+
2551
+ Args:
2552
+ id: The ID of the network to fetch.
2553
+ """
2554
+ return self._transport.unary(
2555
+ [Route("GET", "/v1/networks/{id}", "")],
2556
+ GetNetworkRequest(id=id),
2557
+ GetNetworkResponse,
2558
+ )
2559
+
2560
+ def get_networks(self) -> GetNetworksResponse:
2561
+ """Get all networks."""
2562
+ return self._transport.unary(
2563
+ [Route("GET", "/v1/networks", "")],
2564
+ GetNetworksRequest(),
2565
+ GetNetworksResponse,
2566
+ )
2567
+
2568
+ def create_network(
2569
+ self,
2570
+ *,
2571
+ network: Network | None = None,
2572
+ ) -> CreateNetworkResponse:
2573
+ """Create a network and return it. Every connected node is added to the network
2574
+ automatically and assigned the first free IP address in its subnet, so nodes
2575
+ given in the request are ignored.
2576
+
2577
+ Args:
2578
+ network: The network to create. Required.
2579
+ """
2580
+ return self._transport.unary(
2581
+ [Route("POST", "/v1/networks", "network")],
2582
+ CreateNetworkRequest(network=network or Network()),
2583
+ CreateNetworkResponse,
2584
+ )
2585
+
2586
+ def update_network(
2587
+ self,
2588
+ *,
2589
+ id: str = "",
2590
+ network: Network | None = None,
2591
+ ) -> UpdateNetworkResponse:
2592
+ """Replace the settings of an existing network and return the updated network.
2593
+ Nodes cannot be added or removed, and their IP address and role cannot be
2594
+ changed.
2595
+
2596
+ Args:
2597
+ id: The ID of the network to update.
2598
+ network: The new settings of the network. Required. All fields replace
2599
+ the current values, except `nodes`: leave it empty to keep the nodes
2600
+ unchanged, or list every current node to edit their carriers and
2601
+ parameters.
2602
+ """
2603
+ return self._transport.unary(
2604
+ [Route("PUT", "/v1/networks/{id}", "network")],
2605
+ UpdateNetworkRequest(id=id, network=network or Network()),
2606
+ UpdateNetworkResponse,
2607
+ )
2608
+
2609
+ def delete_network(
2610
+ self,
2611
+ *,
2612
+ id: str = "",
2613
+ ) -> DeleteNetworkResponse:
2614
+ """Delete a network.
2615
+
2616
+ Args:
2617
+ id: The ID of the network to delete.
2618
+ """
2619
+ return self._transport.unary(
2620
+ [Route("DELETE", "/v1/networks/{id}", "")],
2621
+ DeleteNetworkRequest(id=id),
2622
+ DeleteNetworkResponse,
2623
+ )
2624
+
2625
+ def stream_networks(self) -> ServerStream[StreamNetworksEvent]:
2626
+ """Stream changes to networks. Nothing is sent when the stream opens; an event
2627
+ is sent each time a network is created, updated or deleted. The stream ends
2628
+ if the connection to the networks node is lost.
2629
+ """
2630
+ return self._transport.server_stream(
2631
+ [Route("GET", "/v1/streams/networks", "")],
2632
+ StreamNetworksRequest(),
2633
+ StreamNetworksEvent,
2634
+ )
2635
+
2636
+ def open_log_stream(
2637
+ self,
2638
+ *,
2639
+ network_id: str = "",
2640
+ options: Options | None = None,
2641
+ ) -> ServerStream[NetworkLogStreamMessages]:
2642
+ """Stream the log messages of a network. The requested number of past lines is
2643
+ sent first, then new messages as they are logged, until the connection to the
2644
+ networks node is lost.
2645
+
2646
+ Args:
2647
+ network_id: The ID of the network whose log to stream.
2648
+ options: Log stream options, such as how many past lines to send first.
2649
+ """
2650
+ return self._transport.server_stream(
2651
+ [Route("GET", "/v1/streams/networks/{network_id}/logs", "")],
2652
+ NetworksOpenNetworkLogStreamRequest(
2653
+ network_id=network_id,
2654
+ options=options or Options(),
2655
+ ),
2656
+ NetworkLogStreamMessages,
2657
+ )
2658
+
2659
+
2660
+ class PipelinesServiceClient:
2661
+ """A pipeline is the configuration a node runs to move traffic, connecting
2662
+ components such as UDP sockets, TUN interfaces and error correction encoders into
2663
+ a data flow. Each start of a pipeline creates a new run, with its own logs and
2664
+ telemetry. Use this service to create, change, start and stop pipelines on any
2665
+ node, and to follow their changes, logs and telemetry.
2666
+ """
2667
+
2668
+ def __init__(self, transport: Transport) -> None:
2669
+ self._transport = transport
2670
+
2671
+ def get_pipelines(
2672
+ self,
2673
+ *,
2674
+ node_id: str = "",
2675
+ ) -> GetPipelinesResponse:
2676
+ """Lists all pipelines on the node.
2677
+
2678
+ Args:
2679
+ node_id: ID of the node to list the pipelines of.
2680
+ """
2681
+ return self._transport.unary(
2682
+ [Route("GET", "/v1/nodes/{node_id}/pipelines", "")],
2683
+ GetPipelinesRequest(node_id=node_id),
2684
+ GetPipelinesResponse,
2685
+ )
2686
+
2687
+ def get_pipeline_by_id(
2688
+ self,
2689
+ *,
2690
+ node_id: str = "",
2691
+ id: str = "",
2692
+ ) -> GetPipelineByIdResponse:
2693
+ """Get one pipeline. Fails with a not found error if it does not exist.
2694
+
2695
+ Args:
2696
+ node_id: ID of the node that hosts the pipeline.
2697
+ id: ID of the pipeline.
2698
+ """
2699
+ return self._transport.unary(
2700
+ [Route("GET", "/v1/nodes/{node_id}/pipelines/{id}", "")],
2701
+ GetPipelineByIdRequest(node_id=node_id, id=id),
2702
+ GetPipelineByIdResponse,
2703
+ )
2704
+
2705
+ def get_pipeline_by_name(
2706
+ self,
2707
+ *,
2708
+ node_id: str = "",
2709
+ name: str = "",
2710
+ ) -> GetPipelineByNameResponse:
2711
+ """Get one pipeline by name. Fails with a not found error if no pipeline, or
2712
+ more than one, has that name.
2713
+
2714
+ Args:
2715
+ node_id: ID of the node that hosts the pipeline.
2716
+ name: Exact name of the pipeline. Example: `UDP tunnel`
2717
+ """
2718
+ return self._transport.unary(
2719
+ [Route("GET", "/v1/nodes/{node_id}/pipelines-by-name/{name}", "")],
2720
+ GetPipelineByNameRequest(node_id=node_id, name=name),
2721
+ GetPipelineByNameResponse,
2722
+ )
2723
+
2724
+ def get_pipeline_by_run_id(
2725
+ self,
2726
+ *,
2727
+ node_id: str = "",
2728
+ id: str = "",
2729
+ ) -> GetPipelineByRunIdResponse:
2730
+ """Get the pipeline that a run belongs to. An unknown run fails with a timeout
2731
+ error.
2732
+
2733
+ Args:
2734
+ node_id: ID of the node that hosts the pipeline.
2735
+ id: ID of the run.
2736
+ """
2737
+ return self._transport.unary(
2738
+ [Route("GET", "/v1/nodes/{node_id}/pipeline-runs/{id}", "")],
2739
+ GetPipelineByRunIdRequest(node_id=node_id, id=id),
2740
+ GetPipelineByRunIdResponse,
2741
+ )
2742
+
2743
+ def create_pipeline(
2744
+ self,
2745
+ *,
2746
+ node_id: str = "",
2747
+ name: str = "",
2748
+ json_config: str = "",
2749
+ restart_policy: RestartPolicy | None = None,
2750
+ startup_policy: StartupPolicy | None = None,
2751
+ default_logging_level: Level | None = None,
2752
+ node_reference_id: str | None = None,
2753
+ instructions_timeout: int | None = None,
2754
+ cpu_pin: int | None = None,
2755
+ performance_mode: bool | None = None,
2756
+ ) -> CreatePipelineResponse:
2757
+ """Create a pipeline from a JSON configuration and return it. The pipeline is
2758
+ not started. Fails with an invalid argument error if the configuration is
2759
+ invalid or the CPU pin is not a thread of the node.
2760
+
2761
+ Args:
2762
+ node_id: ID of the node to create the pipeline on.
2763
+ name: Name of the pipeline. Example: `UDP tunnel`
2764
+ json_config: The pipeline configuration as a JSON string.
2765
+ restart_policy: The restart policy of the pipeline. Leave unset to never
2766
+ restart.
2767
+ startup_policy: The startup policy of the pipeline. Leave unset to start
2768
+ it manually only.
2769
+ default_logging_level: The default logging level.
2770
+ node_reference_id: ID of the related node.
2771
+ instructions_timeout: The timeout in seconds. Must be greater than 0.
2772
+ Example: `30`
2773
+ cpu_pin: Zero indexed CPU thread number. Must be lower than the node's
2774
+ thread count.
2775
+ performance_mode: True to run the pinned thread in performance mode.
2776
+ """
2777
+ return self._transport.unary(
2778
+ [Route("POST", "/v1/nodes/{node_id}/pipelines", "*")],
2779
+ CreatePipelineRequest(
2780
+ node_id=node_id,
2781
+ name=name,
2782
+ json_config=json_config,
2783
+ restart_policy=restart_policy or RestartPolicy(),
2784
+ startup_policy=startup_policy or StartupPolicy(),
2785
+ default_logging_level=default_logging_level,
2786
+ node_reference_id=node_reference_id,
2787
+ instructions_timeout=instructions_timeout,
2788
+ cpu_pin=cpu_pin,
2789
+ performance_mode=performance_mode,
2790
+ ),
2791
+ CreatePipelineResponse,
2792
+ )
2793
+
2794
+ def update_pipeline(
2795
+ self,
2796
+ *,
2797
+ node_id: str = "",
2798
+ id: str = "",
2799
+ name: str = "",
2800
+ json_config: str = "",
2801
+ restart_policy: RestartPolicy | None = None,
2802
+ startup_policy: StartupPolicy | None = None,
2803
+ default_logging_level: Level = Level.STATE,
2804
+ instructions_timeout: int = 0,
2805
+ cpu_pin: int | None = None,
2806
+ performance_mode: bool | None = None,
2807
+ node_reference_id: str | None = None,
2808
+ force_restart: bool = False,
2809
+ ) -> UpdatePipelineResponse:
2810
+ """Replace the settings of a pipeline and return the updated pipeline. If the
2811
+ pipeline is running and its configuration changed, the new configuration is
2812
+ applied to the current run. If that is not possible, the call fails because
2813
+ the pipeline is running, unless a restart is forced.
2814
+
2815
+ Args:
2816
+ node_id: ID of the node that hosts the pipeline.
2817
+ id: ID of the pipeline to update.
2818
+ name: New name of the pipeline. Example: `UDP tunnel`
2819
+ json_config: New pipeline configuration as a JSON string.
2820
+ restart_policy: New restart policy of the pipeline. Unset means never
2821
+ restart.
2822
+ startup_policy: New startup policy of the pipeline. Unset means start
2823
+ manually only.
2824
+ default_logging_level: New default logging level of the pipeline. Unset
2825
+ means `STATE`, not the `INFO` default used on create.
2826
+ instructions_timeout: New time in seconds before a pipeline instruction
2827
+ is considered timed out. Must be greater than 0. Example: `30`
2828
+ cpu_pin: Zero indexed CPU thread number. Must be lower than the node's
2829
+ thread count.
2830
+ performance_mode: True to run the pinned thread in performance mode.
2831
+ node_reference_id: ID of the related node.
2832
+ force_restart: If true and the pipeline is running, the pipeline is
2833
+ restarted when the new configuration cannot be applied to the current
2834
+ run. The call then returns once the new run is running.
2835
+ """
2836
+ return self._transport.unary(
2837
+ [Route("PUT", "/v1/nodes/{node_id}/pipelines/{id}", "*")],
2838
+ UpdatePipelineRequest(
2839
+ node_id=node_id,
2840
+ id=id,
2841
+ name=name,
2842
+ json_config=json_config,
2843
+ restart_policy=restart_policy or RestartPolicy(),
2844
+ startup_policy=startup_policy or StartupPolicy(),
2845
+ default_logging_level=default_logging_level,
2846
+ instructions_timeout=instructions_timeout,
2847
+ cpu_pin=cpu_pin,
2848
+ performance_mode=performance_mode,
2849
+ node_reference_id=node_reference_id,
2850
+ force_restart=force_restart,
2851
+ ),
2852
+ UpdatePipelineResponse,
2853
+ )
2854
+
2855
+ def delete_pipeline(
2856
+ self,
2857
+ *,
2858
+ node_id: str = "",
2859
+ id: str = "",
2860
+ ) -> DeletePipelineResponse:
2861
+ """Delete a pipeline. Fails with a not found error if it does not exist.
2862
+
2863
+ Args:
2864
+ node_id: ID of the node that hosts the pipeline.
2865
+ id: ID of the pipeline to delete.
2866
+ """
2867
+ return self._transport.unary(
2868
+ [Route("DELETE", "/v1/nodes/{node_id}/pipelines/{id}", "")],
2869
+ DeletePipelineRequest(node_id=node_id, id=id),
2870
+ DeletePipelineResponse,
2871
+ )
2872
+
2873
+ def start_pipeline(
2874
+ self,
2875
+ *,
2876
+ node_id: str = "",
2877
+ id: str | None = None,
2878
+ name: str | None = None,
2879
+ ) -> StartPipelineResponse:
2880
+ """Start a pipeline and return its new run once it is running. Fails if the
2881
+ pipeline is unknown, already started, or does not reach the running state
2882
+ within 10 seconds.
2883
+
2884
+ Args:
2885
+ node_id: ID of the node that hosts the pipeline.
2886
+ id: ID of the pipeline.
2887
+ name: Exact name of the pipeline. Fails if more than one pipeline has
2888
+ this name. Example: `UDP tunnel`
2889
+ """
2890
+ return self._transport.unary(
2891
+ [
2892
+ Route("POST", "/v1/nodes/{node_id}/pipelines/{id}/start", ""),
2893
+ Route("POST", "/v1/nodes/{node_id}/pipelines-by-name/{name}/start", ""),
2894
+ ],
2895
+ StartPipelineRequest(node_id=node_id, id=id, name=name),
2896
+ StartPipelineResponse,
2897
+ )
2898
+
2899
+ def stop_pipeline(
2900
+ self,
2901
+ *,
2902
+ node_id: str = "",
2903
+ id: str | None = None,
2904
+ name: str | None = None,
2905
+ run_id: str | None = None,
2906
+ ) -> StopPipelineResponse:
2907
+ """Stop a pipeline, found by its ID, its name or its current run. Returns once
2908
+ the stop is requested, without waiting for the run to end. Fails if the
2909
+ pipeline is unknown or already stopped.
2910
+
2911
+ Args:
2912
+ node_id: ID of the node that hosts the pipeline.
2913
+ id: ID of the pipeline.
2914
+ name: Exact name of the pipeline. Fails if more than one pipeline has
2915
+ this name. Example: `UDP tunnel`
2916
+ run_id: ID of the pipeline's current run.
2917
+ """
2918
+ return self._transport.unary(
2919
+ [
2920
+ Route("POST", "/v1/nodes/{node_id}/pipelines/{id}/stop", ""),
2921
+ Route("POST", "/v1/nodes/{node_id}/pipelines-by-name/{name}/stop", ""),
2922
+ Route("POST", "/v1/nodes/{node_id}/pipeline-runs/{run_id}/stop", ""),
2923
+ ],
2924
+ StopPipelineRequest(node_id=node_id, id=id, name=name, run_id=run_id),
2925
+ StopPipelineResponse,
2926
+ )
2927
+
2928
+ def stream_pipelines(
2929
+ self,
2930
+ *,
2931
+ node_id: str = "",
2932
+ ) -> ServerStream[StreamPipelinesEvent]:
2933
+ """Stream changes to the pipelines of a node. Nothing is sent when the stream
2934
+ opens, so get the pipelines first for the current list. An event is sent each
2935
+ time a pipeline is created, updated or deleted, and when a pipeline starts or
2936
+ stops.
2937
+
2938
+ Args:
2939
+ node_id: ID of the node to stream pipeline changes from.
2940
+ """
2941
+ return self._transport.server_stream(
2942
+ [Route("GET", "/v1/streams/nodes/{node_id}/pipelines", "")],
2943
+ StreamPipelinesRequest(node_id=node_id),
2944
+ StreamPipelinesEvent,
2945
+ )
2946
+
2947
+ def open_log_stream(
2948
+ self,
2949
+ *,
2950
+ node_id: str = "",
2951
+ run_id: str = "",
2952
+ options: Options | None = None,
2953
+ ) -> ServerStream[LogStreamMessages]:
2954
+ """Stream the log messages of a pipeline run. The requested number of past lines
2955
+ is sent first, then new messages as they are logged.
2956
+
2957
+ Args:
2958
+ node_id: ID of the node that hosts the run.
2959
+ run_id: ID of the run to stream logs from.
2960
+ options: Stream options, such as how many past lines to send first.
2961
+ Leave unset to receive only new messages.
2962
+ """
2963
+ return self._transport.server_stream(
2964
+ [
2965
+ Route("GET", "/v1/streams/nodes/{node_id}/pipeline-runs/{run_id}/logs", ""),
2966
+ ],
2967
+ PipelineOpenLogStreamRequest(
2968
+ node_id=node_id,
2969
+ run_id=run_id,
2970
+ options=options or Options(),
2971
+ ),
2972
+ LogStreamMessages,
2973
+ )
2974
+
2975
+ def open_telemetry_stream(
2976
+ self,
2977
+ *,
2978
+ node_id: str = "",
2979
+ run_id: str = "",
2980
+ ) -> ServerStream[TelemetrySample]:
2981
+ """Streams telemetry samples (metrics and KPI values) of a pipeline run at
2982
+ regular intervals while the run is active. The stream ends with an error when
2983
+ the run stops, when the run is unknown, or when the node disconnects.
2984
+
2985
+ Args:
2986
+ node_id: ID of the node that hosts the run.
2987
+ run_id: ID of the run to stream telemetry from.
2988
+ """
2989
+ return self._transport.server_stream(
2990
+ [
2991
+ Route("GET", "/v1/streams/nodes/{node_id}/pipeline-runs/{run_id}/telemetry", ""),
2992
+ ],
2993
+ OpenTelemetryStreamRequest(node_id=node_id, run_id=run_id),
2994
+ TelemetrySample,
2995
+ )
2996
+
2997
+
2998
+ class ResourcesServiceClient:
2999
+ """Live system information of a node: resource metrics such as CPU, memory, storage
3000
+ and network interface usage, and the network flows crossing its interfaces. Use
3001
+ this service to monitor the health and traffic of any node.
3002
+ """
3003
+
3004
+ def __init__(self, transport: Transport) -> None:
3005
+ self._transport = transport
3006
+
3007
+ def open_metrics_stream(
3008
+ self,
3009
+ *,
3010
+ node_id: str = "",
3011
+ ) -> ServerStream[MetricsSample]:
3012
+ """Stream the resource metrics of a node, such as CPU, memory, disk and network
3013
+ interface usage. A sample of the current metrics is sent when the stream
3014
+ opens. The stream stays open until the client closes it, and ends with an
3015
+ error if the node loses its connection.
3016
+
3017
+ Args:
3018
+ node_id: ID of the node to read metrics from.
3019
+ """
3020
+ return self._transport.server_stream(
3021
+ [Route("GET", "/v1/streams/nodes/{node_id}/metrics", "")],
3022
+ OpenMetricsStreamRequest(node_id=node_id),
3023
+ MetricsSample,
3024
+ )
3025
+
3026
+ def open_flows_stream(
3027
+ self,
3028
+ *,
3029
+ node_id: str = "",
3030
+ ) -> ServerStream[FlowsSample]:
3031
+ """Stream a snapshot of the network flows crossing the interfaces of a node,
3032
+ about once a second, starting right away. The node only captures packets
3033
+ while someone watches its flows, so the first samples may be empty or
3034
+ incomplete.
3035
+
3036
+ Args:
3037
+ node_id: ID of the node to read flows from.
3038
+ """
3039
+ return self._transport.server_stream(
3040
+ [Route("GET", "/v1/streams/nodes/{node_id}/flows", "")],
3041
+ OpenFlowsStreamRequest(node_id=node_id),
3042
+ FlowsSample,
3043
+ )
3044
+
3045
+
3046
+ class AsyncBlueprintsClient:
3047
+ """A blueprint is a template that generates the pipeline configuration a node runs
3048
+ in a network. It uses [Go template syntax](https://pkg.go.dev/text/template), and
3049
+ placeholders such as the node's IP address and carriers are filled in for each
3050
+ node. Every network uses three blueprints: one for the relay node, one the relay
3051
+ runs for every client, and one for every client node. The built-in blueprints are
3052
+ read-only; create your own to change how networks carry traffic. Blueprints are
3053
+ stored on the connected node that has networks enabled, and calls wait until that
3054
+ node is connected.
3055
+ """
3056
+
3057
+ def __init__(self, transport: AsyncTransport) -> None:
3058
+ self._transport = transport
3059
+
3060
+ async def get_blueprint(
3061
+ self,
3062
+ *,
3063
+ id: str = "",
3064
+ ) -> GetBlueprintResponse:
3065
+ """Get a single blueprint.
3066
+
3067
+ Args:
3068
+ id: The ID of the blueprint to fetch.
3069
+ """
3070
+ return await self._transport.unary(
3071
+ [Route("GET", "/v1/blueprints/{id}", "")],
3072
+ GetBlueprintRequest(id=id),
3073
+ GetBlueprintResponse,
3074
+ )
3075
+
3076
+ async def get_blueprints(self) -> GetBlueprintsResponse:
3077
+ """Get all blueprints, including the built-in read-only ones."""
3078
+ return await self._transport.unary(
3079
+ [Route("GET", "/v1/blueprints", "")],
3080
+ GetBlueprintsRequest(),
3081
+ GetBlueprintsResponse,
3082
+ )
3083
+
3084
+ async def create_blueprint(
3085
+ self,
3086
+ *,
3087
+ blueprint: BlueprintWrite | None = None,
3088
+ ) -> CreateBlueprintResponse:
3089
+ """Create a blueprint and return it.
3090
+
3091
+ Args:
3092
+ blueprint: The blueprint to create. Required.
3093
+ """
3094
+ return await self._transport.unary(
3095
+ [Route("POST", "/v1/blueprints", "blueprint")],
3096
+ CreateBlueprintRequest(blueprint=blueprint or BlueprintWrite()),
3097
+ CreateBlueprintResponse,
3098
+ )
3099
+
3100
+ async def update_blueprint(
3101
+ self,
3102
+ *,
3103
+ id: str = "",
3104
+ blueprint: BlueprintWrite | None = None,
3105
+ ) -> UpdateBlueprintResponse:
3106
+ """Replace a blueprint and return the updated blueprint. Networks using the
3107
+ blueprint have their pipelines regenerated. Fails with a permission error for
3108
+ read-only blueprints.
3109
+
3110
+ Args:
3111
+ id: The ID of the blueprint to update.
3112
+ blueprint: The new name and template. Required.
3113
+ """
3114
+ return await self._transport.unary(
3115
+ [Route("PUT", "/v1/blueprints/{id}", "blueprint")],
3116
+ UpdateBlueprintRequest(id=id, blueprint=blueprint or BlueprintWrite()),
3117
+ UpdateBlueprintResponse,
3118
+ )
3119
+
3120
+ async def delete_blueprint(
3121
+ self,
3122
+ *,
3123
+ id: str = "",
3124
+ ) -> DeleteBlueprintResponse:
3125
+ """Delete a blueprint. Fails with a permission error for read-only blueprints.
3126
+
3127
+ Args:
3128
+ id: The ID of the blueprint to delete.
3129
+ """
3130
+ return await self._transport.unary(
3131
+ [Route("DELETE", "/v1/blueprints/{id}", "")],
3132
+ DeleteBlueprintRequest(id=id),
3133
+ DeleteBlueprintResponse,
3134
+ )
3135
+
3136
+
3137
+ class AsyncConfigServiceClient:
3138
+ """Settings stored in the configuration of a node. Use this service to read and
3139
+ change them on any node, such as the carriers a node uses by default when it
3140
+ joins a network.
3141
+ """
3142
+
3143
+ def __init__(self, transport: AsyncTransport) -> None:
3144
+ self._transport = transport
3145
+
3146
+ async def get_default_network_carriers(
3147
+ self,
3148
+ *,
3149
+ node_id: str = "",
3150
+ ) -> GetDefaultNetworkCarriersResponse:
3151
+ """Get the default network carriers of a node. These are the carriers the node
3152
+ receives every time it joins a new network. Returns an empty list when none
3153
+ are configured.
3154
+
3155
+ Args:
3156
+ node_id: Id of the node to read the default network carriers from.
3157
+ """
3158
+ return await self._transport.unary(
3159
+ [Route("GET", "/v1/nodes/{node_id}/default-network-carriers", "")],
3160
+ GetDefaultNetworkCarriersRequest(node_id=node_id),
3161
+ GetDefaultNetworkCarriersResponse,
3162
+ )
3163
+
3164
+ async def set_default_network_carriers(
3165
+ self,
3166
+ *,
3167
+ node_id: str = "",
3168
+ carriers: DefaultNetworkCarriers | None = None,
3169
+ ) -> SetDefaultNetworkCarriersResponse:
3170
+ """Replace the default network carriers of a node. The new carriers apply to
3171
+ networks the node joins afterwards.
3172
+
3173
+ Args:
3174
+ node_id: Id of the node to set the default network carriers on.
3175
+ carriers: The new default network carriers, replacing the current ones.
3176
+ Leave unset to remove all default carriers.
3177
+ """
3178
+ return await self._transport.unary(
3179
+ [Route("PUT", "/v1/nodes/{node_id}/default-network-carriers", "carriers")],
3180
+ SetDefaultNetworkCarriersRequest(node_id=node_id, carriers=carriers),
3181
+ SetDefaultNetworkCarriersResponse,
3182
+ )
3183
+
3184
+
3185
+ class AsyncHubClientServiceClient:
3186
+ """The hub client is the part of every node that connects it to a hub server, the
3187
+ control plane that lets connected nodes find and manage each other. Use this
3188
+ service to sign the node hosting the API in to a hub server, disconnect it,
3189
+ follow its connection state, and read or change the details of nodes.
3190
+ """
3191
+
3192
+ def __init__(self, transport: AsyncTransport) -> None:
3193
+ self._transport = transport
3194
+
3195
+ async def get_local_node_id(self) -> GetLocalNodeIdResponse:
3196
+ """Get the ID of the node hosting the API, and whether it is authenticated with
3197
+ a hub server.
3198
+ """
3199
+ return await self._transport.unary(
3200
+ [Route("GET", "/v1/hub-client/local-node-id", "")],
3201
+ GetLocalNodeIdRequest(),
3202
+ GetLocalNodeIdResponse,
3203
+ )
3204
+
3205
+ async def get_node(
3206
+ self,
3207
+ *,
3208
+ node_id: str = "",
3209
+ ) -> GetNodeResponse:
3210
+ """Get the details of a node. Fails with Unavailable when the node cannot be
3211
+ reached.
3212
+
3213
+ Args:
3214
+ node_id: Id of the node to get information about, for example the id
3215
+ returned by getLocalNodeId.
3216
+ """
3217
+ return await self._transport.unary(
3218
+ [Route("GET", "/v1/nodes/{node_id}", "")],
3219
+ GetNodeRequest(node_id=node_id),
3220
+ GetNodeResponse,
3221
+ )
3222
+
3223
+ async def set_node(
3224
+ self,
3225
+ *,
3226
+ node_id: str = "",
3227
+ name: str = "",
3228
+ metadata: NodeMetadata | None = None,
3229
+ ) -> SetNodeResponse:
3230
+ """Change the details of a node, replacing the current values. Fails with
3231
+ PermissionDenied when the node's configuration comes from a config file.
3232
+
3233
+ Args:
3234
+ node_id: Id of the node to change.
3235
+ name: New name of the node. Example: `edge-node-1`
3236
+ metadata: New metadata of the node. Replaces all existing metadata, so
3237
+ leaving it empty removes the metadata.
3238
+ """
3239
+ return await self._transport.unary(
3240
+ [Route("PUT", "/v1/nodes/{node_id}", "*")],
3241
+ SetNodeRequest(
3242
+ node_id=node_id,
3243
+ name=name,
3244
+ metadata=metadata or NodeMetadata(),
3245
+ ),
3246
+ SetNodeResponse,
3247
+ )
3248
+
3249
+ async def authenticate_by_request(
3250
+ self,
3251
+ *,
3252
+ hub_server_address: str = "",
3253
+ ) -> AuthenticateByRequestResponse:
3254
+ """Ask a hub server to authenticate the node hosting the API, and wait for the
3255
+ hub server to accept or reject the request. On success the node stays
3256
+ authenticated, also after a restart. Fails with AlreadyExists if the node is
3257
+ already authenticated, Unauthenticated if the request was rejected,
3258
+ DeadlineExceeded if the hub server did not answer in time, Unavailable if the
3259
+ hub server could not be reached, and NotFound if the hub server does not
3260
+ accept authentication by request.
3261
+
3262
+ Args:
3263
+ hub_server_address: HTTP or HTTPS address of the hub server. Example:
3264
+ `http://127.0.0.1:8769`
3265
+ """
3266
+ return await self._transport.unary(
3267
+ [Route("POST", "/v1/hub-client/authenticate-by-request", "*")],
3268
+ AuthenticateByRequestRequest(hub_server_address=hub_server_address),
3269
+ AuthenticateByRequestResponse,
3270
+ )
3271
+
3272
+ async def disconnect(self) -> DisconnectResponse:
3273
+ """Disconnect the node hosting the API from its hub server. The node always
3274
+ leaves, even if the hub server could not remove it from its list of nodes.
3275
+ """
3276
+ return await self._transport.unary(
3277
+ [Route("POST", "/v1/hub-client/disconnect", "*")],
3278
+ DisconnectRequest(),
3279
+ DisconnectResponse,
3280
+ )
3281
+
3282
+ def stream_connection_state(
3283
+ self,
3284
+ ) -> AsyncServerStream[StreamConnectionStateResponse]:
3285
+ """Stream the connection state between the node hosting the API and its hub
3286
+ server. The current state is sent first, then a new message every time the
3287
+ state changes. The stream stays open until the caller closes it.
3288
+ """
3289
+ return self._transport.server_stream(
3290
+ [Route("GET", "/v1/streams/hub-client/connection-state", "")],
3291
+ StreamConnectionStateRequest(),
3292
+ StreamConnectionStateResponse,
3293
+ )
3294
+
3295
+
3296
+ class AsyncHubServerServiceClient:
3297
+ """A hub server is the control plane of a NanoPing setup: nodes authenticate with
3298
+ it, and every node on the same hub can find and manage the others. Use this
3299
+ service to list the nodes on the hub, follow them as they come and go, remove
3300
+ nodes, and approve or reject nodes that ask to join. The node hosting the API
3301
+ must host the hub server or be authenticated with one, otherwise calls fail with
3302
+ FailedPrecondition.
3303
+ """
3304
+
3305
+ def __init__(self, transport: AsyncTransport) -> None:
3306
+ self._transport = transport
3307
+
3308
+ async def get_nodes(
3309
+ self,
3310
+ *,
3311
+ metadata_filters: Mapping[str, NodeMetadataItem] | None = None,
3312
+ service_filters: Sequence[NodeService] = (),
3313
+ ) -> GetNodesResponse:
3314
+ """Get the nodes authenticated with the hub server, optionally filtered.
3315
+
3316
+ Args:
3317
+ metadata_filters: Metadata filters keyed by metadata key. A node is
3318
+ included only if it has every key with an equal value of the same type.
3319
+ Leave empty to not filter by metadata.
3320
+ service_filters: Service filters. A node is included only if it offers
3321
+ every listed service. Leave empty to not filter by service.
3322
+ """
3323
+ return await self._transport.unary(
3324
+ [Route("GET", "/v1/nodes", ""), Route("POST", "/v1/nodes/search", "*")],
3325
+ GetNodesRequest(
3326
+ metadata_filters=dict(metadata_filters or {}),
3327
+ service_filters=list(service_filters),
3328
+ ),
3329
+ GetNodesResponse,
3330
+ )
3331
+
3332
+ async def remove_node(
3333
+ self,
3334
+ *,
3335
+ node_id: str = "",
3336
+ ) -> RemoveNodeResponse:
3337
+ """Remove a node from the hub server. This disconnects the node from the hub
3338
+ server and removes it from its networks.
3339
+
3340
+ Args:
3341
+ node_id: Id of the node to remove.
3342
+ """
3343
+ return await self._transport.unary(
3344
+ [Route("DELETE", "/v1/nodes/{node_id}", "")],
3345
+ RemoveNodeRequest(node_id=node_id),
3346
+ RemoveNodeResponse,
3347
+ )
3348
+
3349
+ def stream_nodes(
3350
+ self,
3351
+ *,
3352
+ metadata_filters: Mapping[str, NodeMetadataItem] | None = None,
3353
+ service_filters: Sequence[NodeService] = (),
3354
+ ) -> AsyncServerStream[StreamNodesResponse]:
3355
+ """Stream the nodes authenticated with the hub server. The matching nodes are
3356
+ sent first, followed by an update every time a node is authenticated,
3357
+ deauthenticated, connects, disconnects or changes its details. Updates are
3358
+ not filtered. The stream stays open until the caller closes it.
3359
+
3360
+ Args:
3361
+ metadata_filters: Metadata filters keyed by metadata key. A node is
3362
+ included only if it has every key with an equal value of the same type.
3363
+ Leave empty to not filter by metadata.
3364
+ service_filters: Service filters. A node is included only if it offers
3365
+ every listed service. Leave empty to not filter by service.
3366
+ """
3367
+ return self._transport.server_stream(
3368
+ [
3369
+ Route("GET", "/v1/streams/nodes", ""),
3370
+ Route("POST", "/v1/streams/nodes", "*"),
3371
+ ],
3372
+ GetNodesRequest(
3373
+ metadata_filters=dict(metadata_filters or {}),
3374
+ service_filters=list(service_filters),
3375
+ ),
3376
+ StreamNodesResponse,
3377
+ )
3378
+
3379
+ def authentication_by_requests(
3380
+ self,
3381
+ ) -> AsyncBidiStream[AuthenticationByRequestAnswer, AuthenticationByRequestRequest]:
3382
+ """Receive the authentication requests sent to the hub server on the node
3383
+ hosting the API, and accept or reject each one. Nothing is sent when the
3384
+ stream opens. A request is sent each time a node asks to authenticate, and
3385
+ the caller answers it by sending an answer for that request.
3386
+ """
3387
+ return self._transport.bidi_stream(
3388
+ Route("POST", "/v1/streams/hub-server/authentication-requests", "*"),
3389
+ AuthenticationByRequestRequest,
3390
+ )
3391
+
3392
+
3393
+ class AsyncLoggingServiceClient:
3394
+ """Every node keeps logs: its application log, and a log for each pipeline run,
3395
+ network and network instance. Use this service to follow a log live or to
3396
+ download a complete log file, from any node.
3397
+ """
3398
+
3399
+ def __init__(self, transport: AsyncTransport) -> None:
3400
+ self._transport = transport
3401
+
3402
+ def open_log_stream(
3403
+ self,
3404
+ *,
3405
+ node_id: str = "",
3406
+ options: Options | None = None,
3407
+ app_log_stream_request: OpenAppLogStreamRequest | None = None,
3408
+ pipeline_run_log_stream_request: OpenPipelineRunLogStreamRequest | None = None,
3409
+ network_log_stream_request: LoggingOpenNetworkLogStreamRequest | None = None,
3410
+ network_instance_log_stream_request: LoggingOpenNetworkInstanceLogStreamRequest | None = None,
3411
+ ) -> AsyncServerStream[Messages]:
3412
+ """Stream the log messages of one log on a node. The requested number of past
3413
+ entries is sent first, then new entries as they are written. Fails with an
3414
+ invalid argument error when the node is invalid or no log is chosen, and ends
3415
+ with an error when the log cannot be read or the node loses its connection.
3416
+
3417
+ Args:
3418
+ node_id: ID of the node whose log to stream.
3419
+ options: Stream options. When unset, only new entries are sent.
3420
+ app_log_stream_request: Stream the node's application log.
3421
+ pipeline_run_log_stream_request: Stream the log of a pipeline run.
3422
+ network_log_stream_request: Stream the log of a network.
3423
+ network_instance_log_stream_request: Stream the log of a network
3424
+ instance.
3425
+ """
3426
+ return self._transport.server_stream(
3427
+ [Route("POST", "/v1/streams/nodes/{node_id}/logs", "*")],
3428
+ LoggingOpenLogStreamRequest(
3429
+ node_id=node_id,
3430
+ options=options or Options(),
3431
+ app_log_stream_request=app_log_stream_request,
3432
+ pipeline_run_log_stream_request=pipeline_run_log_stream_request,
3433
+ network_log_stream_request=network_log_stream_request,
3434
+ network_instance_log_stream_request=network_instance_log_stream_request,
3435
+ ),
3436
+ Messages,
3437
+ )
3438
+
3439
+ async def download_log_file(
3440
+ self,
3441
+ *,
3442
+ node_id: str = "",
3443
+ app_log_file_request: DownloadAppLogFileRequest | None = None,
3444
+ pipeline_run_log_file_request: DownloadPipelineRunLogFileRequest | None = None,
3445
+ network_log_file_request: DownloadNetworkLogFileRequest | None = None,
3446
+ network_instance_log_file_request: DownloadNetworkInstanceLogFileRequest | None = None,
3447
+ ) -> str:
3448
+ """Download one complete log file from a node as a series of chunks. Join the
3449
+ chunks in order to get the file. The stream ends when the whole file has been
3450
+ sent, or after an error chunk when the file could not be read.
3451
+
3452
+ Returns the whole file as text.
3453
+
3454
+ Args:
3455
+ node_id: ID of the node that holds the log file.
3456
+ app_log_file_request: Download the node's application log.
3457
+ pipeline_run_log_file_request: Download the log of a pipeline run.
3458
+ network_log_file_request: Download the log of a network.
3459
+ network_instance_log_file_request: Download the log of a network
3460
+ instance.
3461
+ """
3462
+ return await self._transport.text(
3463
+ [Route("GET", "/v1/nodes/{node_id}/log-file", "")],
3464
+ DownloadLogFileRequest(
3465
+ node_id=node_id,
3466
+ app_log_file_request=app_log_file_request,
3467
+ pipeline_run_log_file_request=pipeline_run_log_file_request,
3468
+ network_log_file_request=network_log_file_request,
3469
+ network_instance_log_file_request=network_instance_log_file_request,
3470
+ ),
3471
+ )
3472
+
3473
+
3474
+ class AsyncNetworkInstancesClient:
3475
+ """A network instance is a network's presence on one node: the pipelines generated
3476
+ for that node from the network's blueprints. Instances are created, updated and
3477
+ removed automatically when their network changes, so they cannot be managed
3478
+ directly. Use this service to see which networks a node takes part in, follow its
3479
+ network pipelines, turn them on or off, and read their logs. The node needs
3480
+ pipelines enabled.
3481
+ """
3482
+
3483
+ def __init__(self, transport: AsyncTransport) -> None:
3484
+ self._transport = transport
3485
+
3486
+ async def get_network_instances(
3487
+ self,
3488
+ *,
3489
+ node_id: str = "",
3490
+ ) -> GetNetworkInstancesResponse:
3491
+ """Get all network instances on a node, each with its pipelines.
3492
+
3493
+ Args:
3494
+ node_id: The ID of the node to fetch network instances from.
3495
+ """
3496
+ return await self._transport.unary(
3497
+ [Route("GET", "/v1/nodes/{node_id}/network-instances", "")],
3498
+ GetNetworkInstancesRequest(node_id=node_id),
3499
+ GetNetworkInstancesResponse,
3500
+ )
3501
+
3502
+ def stream_network_instances(
3503
+ self,
3504
+ *,
3505
+ node_id: str = "",
3506
+ ) -> AsyncServerStream[StreamNetworkInstanceEvent]:
3507
+ """Stream changes to the network instances on a node. Nothing is sent when the
3508
+ stream opens; an event is sent each time an instance is created, updated or
3509
+ deleted, and an update is also sent when one of its pipelines changes. The
3510
+ stream ends if the connection to the node is lost.
3511
+
3512
+ Args:
3513
+ node_id: The ID of the node to stream network instances from.
3514
+ """
3515
+ return self._transport.server_stream(
3516
+ [Route("GET", "/v1/streams/nodes/{node_id}/network-instances", "")],
3517
+ StreamNetworkInstancesRequest(node_id=node_id),
3518
+ StreamNetworkInstanceEvent,
3519
+ )
3520
+
3521
+ async def get_network_pipelines(
3522
+ self,
3523
+ *,
3524
+ node_id: str = "",
3525
+ optional_network_id: str | None = None,
3526
+ optional_instance_id: str | None = None,
3527
+ optional_blueprint_id: str | None = None,
3528
+ ) -> GetNetworkPipelinesResponse:
3529
+ """Get the network instance pipelines on a node, optionally filtered. A pipeline
3530
+ must match every filter that is set.
3531
+
3532
+ Args:
3533
+ node_id: The ID of the node to fetch network instance pipelines from.
3534
+ optional_network_id: Only return pipelines belonging to this network ID.
3535
+ optional_instance_id: Only return pipelines belonging to this network
3536
+ instance ID.
3537
+ optional_blueprint_id: Only return pipelines generated from this
3538
+ blueprint ID.
3539
+ """
3540
+ return await self._transport.unary(
3541
+ [Route("GET", "/v1/nodes/{node_id}/network-pipelines", "")],
3542
+ GetNetworkPipelinesRequest(
3543
+ node_id=node_id,
3544
+ optional_network_id=optional_network_id,
3545
+ optional_instance_id=optional_instance_id,
3546
+ optional_blueprint_id=optional_blueprint_id,
3547
+ ),
3548
+ GetNetworkPipelinesResponse,
3549
+ )
3550
+
3551
+ def stream_network_pipelines(
3552
+ self,
3553
+ *,
3554
+ node_id: str = "",
3555
+ ) -> AsyncServerStream[StreamNetworkPipelineEvent]:
3556
+ """Stream changes to the network instance pipelines on a node. Nothing is sent
3557
+ when the stream opens; an event is sent each time a pipeline is created,
3558
+ updated or deleted. The stream ends if the connection to the node is lost.
3559
+
3560
+ Args:
3561
+ node_id: The ID of the node to stream network instance pipelines from.
3562
+ """
3563
+ return self._transport.server_stream(
3564
+ [Route("GET", "/v1/streams/nodes/{node_id}/network-pipelines", "")],
3565
+ StreamNetworkPipelinesRequest(node_id=node_id),
3566
+ StreamNetworkPipelineEvent,
3567
+ )
3568
+
3569
+ async def toggle_network_pipeline(
3570
+ self,
3571
+ *,
3572
+ node_id: str = "",
3573
+ optional_pipeline_id: str | None = None,
3574
+ optional_instance_pipeline_id: str | None = None,
3575
+ ) -> ToggleNetworkPipelineResponse:
3576
+ """Enable or disable a network instance pipeline on a node, which starts or
3577
+ stops the pipeline. Each call flips the current state. Fails with a not found
3578
+ error if no matching pipeline exists.
3579
+
3580
+ Args:
3581
+ node_id: The ID of the node the pipeline runs on.
3582
+ optional_pipeline_id: The pipeline's `pipeline_id`.
3583
+ optional_instance_pipeline_id: The pipeline's `id`.
3584
+ """
3585
+ return await self._transport.unary(
3586
+ [Route("POST", "/v1/nodes/{node_id}/network-pipelines/toggle", "*")],
3587
+ ToggleNetworkPipelineRequest(
3588
+ node_id=node_id,
3589
+ optional_pipeline_id=optional_pipeline_id,
3590
+ optional_instance_pipeline_id=optional_instance_pipeline_id,
3591
+ ),
3592
+ ToggleNetworkPipelineResponse,
3593
+ )
3594
+
3595
+ def open_log_stream(
3596
+ self,
3597
+ *,
3598
+ node_id: str = "",
3599
+ network_instance_id: str = "",
3600
+ options: Options | None = None,
3601
+ ) -> AsyncServerStream[NetworkInstanceLogStreamMessages]:
3602
+ """Stream the log messages of a network instance on a node. The requested number
3603
+ of past lines is sent first, then new messages as they are logged, until the
3604
+ connection to the node is lost.
3605
+
3606
+ Args:
3607
+ node_id: The ID of the node the network instance runs on.
3608
+ network_instance_id: The ID of the network instance whose log to stream.
3609
+ options: Log stream options, such as how many past lines to send first.
3610
+ """
3611
+ return self._transport.server_stream(
3612
+ [
3613
+ Route("GET", "/v1/streams/nodes/{node_id}/network-instances/{network_instance_id}/logs", ""),
3614
+ ],
3615
+ NetworksOpenNetworkInstanceLogStreamRequest(
3616
+ node_id=node_id,
3617
+ network_instance_id=network_instance_id,
3618
+ options=options or Options(),
3619
+ ),
3620
+ NetworkInstanceLogStreamMessages,
3621
+ )
3622
+
3623
+
3624
+ class AsyncNetworksClient:
3625
+ """A network is a virtual network that connects nodes as if they shared a local
3626
+ network, giving each node its own IP address. All traffic flows through a central
3627
+ relay node. When a network is created or changed, the pipelines each node needs
3628
+ are generated from the network's blueprints and deployed automatically. Use this
3629
+ service to create and change networks and to follow their changes and logs.
3630
+ Networks are stored on the connected node that has networks enabled, and calls
3631
+ wait until that node is connected.
3632
+ """
3633
+
3634
+ def __init__(self, transport: AsyncTransport) -> None:
3635
+ self._transport = transport
3636
+
3637
+ async def get_network(
3638
+ self,
3639
+ *,
3640
+ id: str = "",
3641
+ ) -> GetNetworkResponse:
3642
+ """Get a single network.
3643
+
3644
+ Args:
3645
+ id: The ID of the network to fetch.
3646
+ """
3647
+ return await self._transport.unary(
3648
+ [Route("GET", "/v1/networks/{id}", "")],
3649
+ GetNetworkRequest(id=id),
3650
+ GetNetworkResponse,
3651
+ )
3652
+
3653
+ async def get_networks(self) -> GetNetworksResponse:
3654
+ """Get all networks."""
3655
+ return await self._transport.unary(
3656
+ [Route("GET", "/v1/networks", "")],
3657
+ GetNetworksRequest(),
3658
+ GetNetworksResponse,
3659
+ )
3660
+
3661
+ async def create_network(
3662
+ self,
3663
+ *,
3664
+ network: Network | None = None,
3665
+ ) -> CreateNetworkResponse:
3666
+ """Create a network and return it. Every connected node is added to the network
3667
+ automatically and assigned the first free IP address in its subnet, so nodes
3668
+ given in the request are ignored.
3669
+
3670
+ Args:
3671
+ network: The network to create. Required.
3672
+ """
3673
+ return await self._transport.unary(
3674
+ [Route("POST", "/v1/networks", "network")],
3675
+ CreateNetworkRequest(network=network or Network()),
3676
+ CreateNetworkResponse,
3677
+ )
3678
+
3679
+ async def update_network(
3680
+ self,
3681
+ *,
3682
+ id: str = "",
3683
+ network: Network | None = None,
3684
+ ) -> UpdateNetworkResponse:
3685
+ """Replace the settings of an existing network and return the updated network.
3686
+ Nodes cannot be added or removed, and their IP address and role cannot be
3687
+ changed.
3688
+
3689
+ Args:
3690
+ id: The ID of the network to update.
3691
+ network: The new settings of the network. Required. All fields replace
3692
+ the current values, except `nodes`: leave it empty to keep the nodes
3693
+ unchanged, or list every current node to edit their carriers and
3694
+ parameters.
3695
+ """
3696
+ return await self._transport.unary(
3697
+ [Route("PUT", "/v1/networks/{id}", "network")],
3698
+ UpdateNetworkRequest(id=id, network=network or Network()),
3699
+ UpdateNetworkResponse,
3700
+ )
3701
+
3702
+ async def delete_network(
3703
+ self,
3704
+ *,
3705
+ id: str = "",
3706
+ ) -> DeleteNetworkResponse:
3707
+ """Delete a network.
3708
+
3709
+ Args:
3710
+ id: The ID of the network to delete.
3711
+ """
3712
+ return await self._transport.unary(
3713
+ [Route("DELETE", "/v1/networks/{id}", "")],
3714
+ DeleteNetworkRequest(id=id),
3715
+ DeleteNetworkResponse,
3716
+ )
3717
+
3718
+ def stream_networks(self) -> AsyncServerStream[StreamNetworksEvent]:
3719
+ """Stream changes to networks. Nothing is sent when the stream opens; an event
3720
+ is sent each time a network is created, updated or deleted. The stream ends
3721
+ if the connection to the networks node is lost.
3722
+ """
3723
+ return self._transport.server_stream(
3724
+ [Route("GET", "/v1/streams/networks", "")],
3725
+ StreamNetworksRequest(),
3726
+ StreamNetworksEvent,
3727
+ )
3728
+
3729
+ def open_log_stream(
3730
+ self,
3731
+ *,
3732
+ network_id: str = "",
3733
+ options: Options | None = None,
3734
+ ) -> AsyncServerStream[NetworkLogStreamMessages]:
3735
+ """Stream the log messages of a network. The requested number of past lines is
3736
+ sent first, then new messages as they are logged, until the connection to the
3737
+ networks node is lost.
3738
+
3739
+ Args:
3740
+ network_id: The ID of the network whose log to stream.
3741
+ options: Log stream options, such as how many past lines to send first.
3742
+ """
3743
+ return self._transport.server_stream(
3744
+ [Route("GET", "/v1/streams/networks/{network_id}/logs", "")],
3745
+ NetworksOpenNetworkLogStreamRequest(
3746
+ network_id=network_id,
3747
+ options=options or Options(),
3748
+ ),
3749
+ NetworkLogStreamMessages,
3750
+ )
3751
+
3752
+
3753
+ class AsyncPipelinesServiceClient:
3754
+ """A pipeline is the configuration a node runs to move traffic, connecting
3755
+ components such as UDP sockets, TUN interfaces and error correction encoders into
3756
+ a data flow. Each start of a pipeline creates a new run, with its own logs and
3757
+ telemetry. Use this service to create, change, start and stop pipelines on any
3758
+ node, and to follow their changes, logs and telemetry.
3759
+ """
3760
+
3761
+ def __init__(self, transport: AsyncTransport) -> None:
3762
+ self._transport = transport
3763
+
3764
+ async def get_pipelines(
3765
+ self,
3766
+ *,
3767
+ node_id: str = "",
3768
+ ) -> GetPipelinesResponse:
3769
+ """Lists all pipelines on the node.
3770
+
3771
+ Args:
3772
+ node_id: ID of the node to list the pipelines of.
3773
+ """
3774
+ return await self._transport.unary(
3775
+ [Route("GET", "/v1/nodes/{node_id}/pipelines", "")],
3776
+ GetPipelinesRequest(node_id=node_id),
3777
+ GetPipelinesResponse,
3778
+ )
3779
+
3780
+ async def get_pipeline_by_id(
3781
+ self,
3782
+ *,
3783
+ node_id: str = "",
3784
+ id: str = "",
3785
+ ) -> GetPipelineByIdResponse:
3786
+ """Get one pipeline. Fails with a not found error if it does not exist.
3787
+
3788
+ Args:
3789
+ node_id: ID of the node that hosts the pipeline.
3790
+ id: ID of the pipeline.
3791
+ """
3792
+ return await self._transport.unary(
3793
+ [Route("GET", "/v1/nodes/{node_id}/pipelines/{id}", "")],
3794
+ GetPipelineByIdRequest(node_id=node_id, id=id),
3795
+ GetPipelineByIdResponse,
3796
+ )
3797
+
3798
+ async def get_pipeline_by_name(
3799
+ self,
3800
+ *,
3801
+ node_id: str = "",
3802
+ name: str = "",
3803
+ ) -> GetPipelineByNameResponse:
3804
+ """Get one pipeline by name. Fails with a not found error if no pipeline, or
3805
+ more than one, has that name.
3806
+
3807
+ Args:
3808
+ node_id: ID of the node that hosts the pipeline.
3809
+ name: Exact name of the pipeline. Example: `UDP tunnel`
3810
+ """
3811
+ return await self._transport.unary(
3812
+ [Route("GET", "/v1/nodes/{node_id}/pipelines-by-name/{name}", "")],
3813
+ GetPipelineByNameRequest(node_id=node_id, name=name),
3814
+ GetPipelineByNameResponse,
3815
+ )
3816
+
3817
+ async def get_pipeline_by_run_id(
3818
+ self,
3819
+ *,
3820
+ node_id: str = "",
3821
+ id: str = "",
3822
+ ) -> GetPipelineByRunIdResponse:
3823
+ """Get the pipeline that a run belongs to. An unknown run fails with a timeout
3824
+ error.
3825
+
3826
+ Args:
3827
+ node_id: ID of the node that hosts the pipeline.
3828
+ id: ID of the run.
3829
+ """
3830
+ return await self._transport.unary(
3831
+ [Route("GET", "/v1/nodes/{node_id}/pipeline-runs/{id}", "")],
3832
+ GetPipelineByRunIdRequest(node_id=node_id, id=id),
3833
+ GetPipelineByRunIdResponse,
3834
+ )
3835
+
3836
+ async def create_pipeline(
3837
+ self,
3838
+ *,
3839
+ node_id: str = "",
3840
+ name: str = "",
3841
+ json_config: str = "",
3842
+ restart_policy: RestartPolicy | None = None,
3843
+ startup_policy: StartupPolicy | None = None,
3844
+ default_logging_level: Level | None = None,
3845
+ node_reference_id: str | None = None,
3846
+ instructions_timeout: int | None = None,
3847
+ cpu_pin: int | None = None,
3848
+ performance_mode: bool | None = None,
3849
+ ) -> CreatePipelineResponse:
3850
+ """Create a pipeline from a JSON configuration and return it. The pipeline is
3851
+ not started. Fails with an invalid argument error if the configuration is
3852
+ invalid or the CPU pin is not a thread of the node.
3853
+
3854
+ Args:
3855
+ node_id: ID of the node to create the pipeline on.
3856
+ name: Name of the pipeline. Example: `UDP tunnel`
3857
+ json_config: The pipeline configuration as a JSON string.
3858
+ restart_policy: The restart policy of the pipeline. Leave unset to never
3859
+ restart.
3860
+ startup_policy: The startup policy of the pipeline. Leave unset to start
3861
+ it manually only.
3862
+ default_logging_level: The default logging level.
3863
+ node_reference_id: ID of the related node.
3864
+ instructions_timeout: The timeout in seconds. Must be greater than 0.
3865
+ Example: `30`
3866
+ cpu_pin: Zero indexed CPU thread number. Must be lower than the node's
3867
+ thread count.
3868
+ performance_mode: True to run the pinned thread in performance mode.
3869
+ """
3870
+ return await self._transport.unary(
3871
+ [Route("POST", "/v1/nodes/{node_id}/pipelines", "*")],
3872
+ CreatePipelineRequest(
3873
+ node_id=node_id,
3874
+ name=name,
3875
+ json_config=json_config,
3876
+ restart_policy=restart_policy or RestartPolicy(),
3877
+ startup_policy=startup_policy or StartupPolicy(),
3878
+ default_logging_level=default_logging_level,
3879
+ node_reference_id=node_reference_id,
3880
+ instructions_timeout=instructions_timeout,
3881
+ cpu_pin=cpu_pin,
3882
+ performance_mode=performance_mode,
3883
+ ),
3884
+ CreatePipelineResponse,
3885
+ )
3886
+
3887
+ async def update_pipeline(
3888
+ self,
3889
+ *,
3890
+ node_id: str = "",
3891
+ id: str = "",
3892
+ name: str = "",
3893
+ json_config: str = "",
3894
+ restart_policy: RestartPolicy | None = None,
3895
+ startup_policy: StartupPolicy | None = None,
3896
+ default_logging_level: Level = Level.STATE,
3897
+ instructions_timeout: int = 0,
3898
+ cpu_pin: int | None = None,
3899
+ performance_mode: bool | None = None,
3900
+ node_reference_id: str | None = None,
3901
+ force_restart: bool = False,
3902
+ ) -> UpdatePipelineResponse:
3903
+ """Replace the settings of a pipeline and return the updated pipeline. If the
3904
+ pipeline is running and its configuration changed, the new configuration is
3905
+ applied to the current run. If that is not possible, the call fails because
3906
+ the pipeline is running, unless a restart is forced.
3907
+
3908
+ Args:
3909
+ node_id: ID of the node that hosts the pipeline.
3910
+ id: ID of the pipeline to update.
3911
+ name: New name of the pipeline. Example: `UDP tunnel`
3912
+ json_config: New pipeline configuration as a JSON string.
3913
+ restart_policy: New restart policy of the pipeline. Unset means never
3914
+ restart.
3915
+ startup_policy: New startup policy of the pipeline. Unset means start
3916
+ manually only.
3917
+ default_logging_level: New default logging level of the pipeline. Unset
3918
+ means `STATE`, not the `INFO` default used on create.
3919
+ instructions_timeout: New time in seconds before a pipeline instruction
3920
+ is considered timed out. Must be greater than 0. Example: `30`
3921
+ cpu_pin: Zero indexed CPU thread number. Must be lower than the node's
3922
+ thread count.
3923
+ performance_mode: True to run the pinned thread in performance mode.
3924
+ node_reference_id: ID of the related node.
3925
+ force_restart: If true and the pipeline is running, the pipeline is
3926
+ restarted when the new configuration cannot be applied to the current
3927
+ run. The call then returns once the new run is running.
3928
+ """
3929
+ return await self._transport.unary(
3930
+ [Route("PUT", "/v1/nodes/{node_id}/pipelines/{id}", "*")],
3931
+ UpdatePipelineRequest(
3932
+ node_id=node_id,
3933
+ id=id,
3934
+ name=name,
3935
+ json_config=json_config,
3936
+ restart_policy=restart_policy or RestartPolicy(),
3937
+ startup_policy=startup_policy or StartupPolicy(),
3938
+ default_logging_level=default_logging_level,
3939
+ instructions_timeout=instructions_timeout,
3940
+ cpu_pin=cpu_pin,
3941
+ performance_mode=performance_mode,
3942
+ node_reference_id=node_reference_id,
3943
+ force_restart=force_restart,
3944
+ ),
3945
+ UpdatePipelineResponse,
3946
+ )
3947
+
3948
+ async def delete_pipeline(
3949
+ self,
3950
+ *,
3951
+ node_id: str = "",
3952
+ id: str = "",
3953
+ ) -> DeletePipelineResponse:
3954
+ """Delete a pipeline. Fails with a not found error if it does not exist.
3955
+
3956
+ Args:
3957
+ node_id: ID of the node that hosts the pipeline.
3958
+ id: ID of the pipeline to delete.
3959
+ """
3960
+ return await self._transport.unary(
3961
+ [Route("DELETE", "/v1/nodes/{node_id}/pipelines/{id}", "")],
3962
+ DeletePipelineRequest(node_id=node_id, id=id),
3963
+ DeletePipelineResponse,
3964
+ )
3965
+
3966
+ async def start_pipeline(
3967
+ self,
3968
+ *,
3969
+ node_id: str = "",
3970
+ id: str | None = None,
3971
+ name: str | None = None,
3972
+ ) -> StartPipelineResponse:
3973
+ """Start a pipeline and return its new run once it is running. Fails if the
3974
+ pipeline is unknown, already started, or does not reach the running state
3975
+ within 10 seconds.
3976
+
3977
+ Args:
3978
+ node_id: ID of the node that hosts the pipeline.
3979
+ id: ID of the pipeline.
3980
+ name: Exact name of the pipeline. Fails if more than one pipeline has
3981
+ this name. Example: `UDP tunnel`
3982
+ """
3983
+ return await self._transport.unary(
3984
+ [
3985
+ Route("POST", "/v1/nodes/{node_id}/pipelines/{id}/start", ""),
3986
+ Route("POST", "/v1/nodes/{node_id}/pipelines-by-name/{name}/start", ""),
3987
+ ],
3988
+ StartPipelineRequest(node_id=node_id, id=id, name=name),
3989
+ StartPipelineResponse,
3990
+ )
3991
+
3992
+ async def stop_pipeline(
3993
+ self,
3994
+ *,
3995
+ node_id: str = "",
3996
+ id: str | None = None,
3997
+ name: str | None = None,
3998
+ run_id: str | None = None,
3999
+ ) -> StopPipelineResponse:
4000
+ """Stop a pipeline, found by its ID, its name or its current run. Returns once
4001
+ the stop is requested, without waiting for the run to end. Fails if the
4002
+ pipeline is unknown or already stopped.
4003
+
4004
+ Args:
4005
+ node_id: ID of the node that hosts the pipeline.
4006
+ id: ID of the pipeline.
4007
+ name: Exact name of the pipeline. Fails if more than one pipeline has
4008
+ this name. Example: `UDP tunnel`
4009
+ run_id: ID of the pipeline's current run.
4010
+ """
4011
+ return await self._transport.unary(
4012
+ [
4013
+ Route("POST", "/v1/nodes/{node_id}/pipelines/{id}/stop", ""),
4014
+ Route("POST", "/v1/nodes/{node_id}/pipelines-by-name/{name}/stop", ""),
4015
+ Route("POST", "/v1/nodes/{node_id}/pipeline-runs/{run_id}/stop", ""),
4016
+ ],
4017
+ StopPipelineRequest(node_id=node_id, id=id, name=name, run_id=run_id),
4018
+ StopPipelineResponse,
4019
+ )
4020
+
4021
+ def stream_pipelines(
4022
+ self,
4023
+ *,
4024
+ node_id: str = "",
4025
+ ) -> AsyncServerStream[StreamPipelinesEvent]:
4026
+ """Stream changes to the pipelines of a node. Nothing is sent when the stream
4027
+ opens, so get the pipelines first for the current list. An event is sent each
4028
+ time a pipeline is created, updated or deleted, and when a pipeline starts or
4029
+ stops.
4030
+
4031
+ Args:
4032
+ node_id: ID of the node to stream pipeline changes from.
4033
+ """
4034
+ return self._transport.server_stream(
4035
+ [Route("GET", "/v1/streams/nodes/{node_id}/pipelines", "")],
4036
+ StreamPipelinesRequest(node_id=node_id),
4037
+ StreamPipelinesEvent,
4038
+ )
4039
+
4040
+ def open_log_stream(
4041
+ self,
4042
+ *,
4043
+ node_id: str = "",
4044
+ run_id: str = "",
4045
+ options: Options | None = None,
4046
+ ) -> AsyncServerStream[LogStreamMessages]:
4047
+ """Stream the log messages of a pipeline run. The requested number of past lines
4048
+ is sent first, then new messages as they are logged.
4049
+
4050
+ Args:
4051
+ node_id: ID of the node that hosts the run.
4052
+ run_id: ID of the run to stream logs from.
4053
+ options: Stream options, such as how many past lines to send first.
4054
+ Leave unset to receive only new messages.
4055
+ """
4056
+ return self._transport.server_stream(
4057
+ [
4058
+ Route("GET", "/v1/streams/nodes/{node_id}/pipeline-runs/{run_id}/logs", ""),
4059
+ ],
4060
+ PipelineOpenLogStreamRequest(
4061
+ node_id=node_id,
4062
+ run_id=run_id,
4063
+ options=options or Options(),
4064
+ ),
4065
+ LogStreamMessages,
4066
+ )
4067
+
4068
+ def open_telemetry_stream(
4069
+ self,
4070
+ *,
4071
+ node_id: str = "",
4072
+ run_id: str = "",
4073
+ ) -> AsyncServerStream[TelemetrySample]:
4074
+ """Streams telemetry samples (metrics and KPI values) of a pipeline run at
4075
+ regular intervals while the run is active. The stream ends with an error when
4076
+ the run stops, when the run is unknown, or when the node disconnects.
4077
+
4078
+ Args:
4079
+ node_id: ID of the node that hosts the run.
4080
+ run_id: ID of the run to stream telemetry from.
4081
+ """
4082
+ return self._transport.server_stream(
4083
+ [
4084
+ Route("GET", "/v1/streams/nodes/{node_id}/pipeline-runs/{run_id}/telemetry", ""),
4085
+ ],
4086
+ OpenTelemetryStreamRequest(node_id=node_id, run_id=run_id),
4087
+ TelemetrySample,
4088
+ )
4089
+
4090
+
4091
+ class AsyncResourcesServiceClient:
4092
+ """Live system information of a node: resource metrics such as CPU, memory, storage
4093
+ and network interface usage, and the network flows crossing its interfaces. Use
4094
+ this service to monitor the health and traffic of any node.
4095
+ """
4096
+
4097
+ def __init__(self, transport: AsyncTransport) -> None:
4098
+ self._transport = transport
4099
+
4100
+ def open_metrics_stream(
4101
+ self,
4102
+ *,
4103
+ node_id: str = "",
4104
+ ) -> AsyncServerStream[MetricsSample]:
4105
+ """Stream the resource metrics of a node, such as CPU, memory, disk and network
4106
+ interface usage. A sample of the current metrics is sent when the stream
4107
+ opens. The stream stays open until the client closes it, and ends with an
4108
+ error if the node loses its connection.
4109
+
4110
+ Args:
4111
+ node_id: ID of the node to read metrics from.
4112
+ """
4113
+ return self._transport.server_stream(
4114
+ [Route("GET", "/v1/streams/nodes/{node_id}/metrics", "")],
4115
+ OpenMetricsStreamRequest(node_id=node_id),
4116
+ MetricsSample,
4117
+ )
4118
+
4119
+ def open_flows_stream(
4120
+ self,
4121
+ *,
4122
+ node_id: str = "",
4123
+ ) -> AsyncServerStream[FlowsSample]:
4124
+ """Stream a snapshot of the network flows crossing the interfaces of a node,
4125
+ about once a second, starting right away. The node only captures packets
4126
+ while someone watches its flows, so the first samples may be empty or
4127
+ incomplete.
4128
+
4129
+ Args:
4130
+ node_id: ID of the node to read flows from.
4131
+ """
4132
+ return self._transport.server_stream(
4133
+ [Route("GET", "/v1/streams/nodes/{node_id}/flows", "")],
4134
+ OpenFlowsStreamRequest(node_id=node_id),
4135
+ FlowsSample,
4136
+ )
4137
+
4138
+
4139
+ class _Services:
4140
+ blueprints: BlueprintsClient
4141
+ config: ConfigServiceClient
4142
+ hub_client: HubClientServiceClient
4143
+ hub_server: HubServerServiceClient
4144
+ logging: LoggingServiceClient
4145
+ network_instances: NetworkInstancesClient
4146
+ networks: NetworksClient
4147
+ pipelines: PipelinesServiceClient
4148
+ resources: ResourcesServiceClient
4149
+
4150
+ def __init__(self, transport: Transport) -> None:
4151
+ self.blueprints = BlueprintsClient(transport)
4152
+ self.config = ConfigServiceClient(transport)
4153
+ self.hub_client = HubClientServiceClient(transport)
4154
+ self.hub_server = HubServerServiceClient(transport)
4155
+ self.logging = LoggingServiceClient(transport)
4156
+ self.network_instances = NetworkInstancesClient(transport)
4157
+ self.networks = NetworksClient(transport)
4158
+ self.pipelines = PipelinesServiceClient(transport)
4159
+ self.resources = ResourcesServiceClient(transport)
4160
+
4161
+
4162
+ class _AsyncServices:
4163
+ blueprints: AsyncBlueprintsClient
4164
+ config: AsyncConfigServiceClient
4165
+ hub_client: AsyncHubClientServiceClient
4166
+ hub_server: AsyncHubServerServiceClient
4167
+ logging: AsyncLoggingServiceClient
4168
+ network_instances: AsyncNetworkInstancesClient
4169
+ networks: AsyncNetworksClient
4170
+ pipelines: AsyncPipelinesServiceClient
4171
+ resources: AsyncResourcesServiceClient
4172
+
4173
+ def __init__(self, transport: AsyncTransport) -> None:
4174
+ self.blueprints = AsyncBlueprintsClient(transport)
4175
+ self.config = AsyncConfigServiceClient(transport)
4176
+ self.hub_client = AsyncHubClientServiceClient(transport)
4177
+ self.hub_server = AsyncHubServerServiceClient(transport)
4178
+ self.logging = AsyncLoggingServiceClient(transport)
4179
+ self.network_instances = AsyncNetworkInstancesClient(transport)
4180
+ self.networks = AsyncNetworksClient(transport)
4181
+ self.pipelines = AsyncPipelinesServiceClient(transport)
4182
+ self.resources = AsyncResourcesServiceClient(transport)