-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
protocol.md
1362 lines (1020 loc) · 50.4 KB
/
protocol.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Protocol Documentation
======================
The protocol is a simple transport for other APIs. It's a simple wrapper over
some other protocols, like DBus, REST, and so on. At the present time this
is unstable, but will need to become stable in the near future.
Channels
--------
Each message is part of a channel, which has a id. This channel id
identifies the type of data in the message payload, the host where it is
headed to/from and things like the service or user credentials.
An empty/missing channel id represents a special channel called the control
channel. It contains command messages. These are described below. Initially
only the control channel exists. Additional channels are opened and closed
via command messages.
Channels operate across all participants, and they help a forwarding layer
like cockpit-ws to know where to send messages.
Framing
-------
The channel id is a UTF-8 valid string. The channel id string comes first
in the message, then a new line, then payload.
For example if you had a payload of the string 'abc', and it was being
sent through the channel 'a5', that might look like:
a5\nabc
When a message is sent over a stream transport that does not have distinct
messages (such as SSH or stdio), the message is also prefixed with a base 10
integer and new line, which represents the length of the following message.
The length must be a positive number in canonical form (ie: strictly greater
than zero, with no leading zeros).
An example. When going over a stream transport with a payload of the 3 byte
string 'abc', and a channel of 'a5', would have a message length of 6: 3 bytes of
payload, 2 bytes for the channel number, 1 for the new line. It would look like
this in a stream:
6\na5\nabc
Control Messages
----------------
Control messages let the various components such as cockpit-web, cockpit-ws and
cockpit-bridge communicate about what's going on.
Control messages are always sent in the control channel. They always have an
empty channel. The payload of a control message is always a json
object. There is always a "command" field:
{
"command": <command>,
"channel": <channel>,
...
}
If a control message pertains to a specific channel it has a "channel" field
containing the id of the channel. It is invalid to have a present but empty
"channel" field.
Unknown control messages are ignored. Control messages that have a channel are
forwarded to the correct endpoint. Control messages without a channel are not
forwarded, but only travel a single hop.
Command: init
-------------
The "init" command is the first message sent over a new transport. It is
an error if any other message is received first. The transport is not considered
open until the "init" message has been received.
The following fields are defined:
* "version": The version of the protocol. Currently 1, and stable.
* "capabilities": Optional array of strings advertizing capabilities.
* "channel-seed": A seed to be used when generating new channel ids.
* "host": The host being communicated with.
* "problem": A problem occurred during init.
* "csrf-token": The web service will send a csrf-token for external channels.
* "os-release": The bridge sends fields from /etc/os-release which identify the system.
* "packages": The bridge sends a list of package names on the system.
* "superuser": Instructs a bridge about whether and how to start a superuser bridge.
If a problem occurs that requires shutdown of a transport, then the "problem"
field can be set to indicate why the shutdown will be shortly occurring.
The "init" command message may be sent multiple times across an already open
transport, if certain parameters need to be renegotiated.
Command: open
-------------
The "open" command opens a new channel for payload.
The following fields are defined:
* "binary": If present set to "raw"
* "channel": A uniquely chosen channel id
* "payload": A payload type, see below
* "host": The destination host for the channel, defaults to "localhost"
* "user": Optional alternate user for authenticating with host
* "superuser": Optional. Use "require" to run as root, or "try" to attempt to run as root.
* "group": An optional channel group
* "capabilities": Optional, array of capability strings required from the bridge
* "session": Optional, set to "private" or "shared". Defaults to "shared"
* "flow-control": Optional boolean whether the channel should throttle itself via flow control.
* "send-acks": Set to "bytes" to send "ack" messages after processing each data frame
If "binary" is set to "raw" then this channel transfers binary messages.
After the command is sent, then the channel is assumed to be open. No response
is sent. If for some reason the channel shouldn't or cannot be opened, then
the recipient will respond with a "close" message.
The channel id must not already be in use by another channel.
An example of an open:
{
"command": "open",
"channel": "a4",
"payload": "stream",
"host": "localhost"
}
This message is sent to the cockpit-bridge.
The caller can control whether to open a new bridge session or not by setting
the "session" field to "private" or "shared". A "private" session will always
start another bridge just for this channel. If this option is not specified
then typically the channel will share an already existing session. There are
certain heuristics for compatibility, where it defaults to private.
The open fields are also used with external channels. External channels are
channels that have their payload sent via a separate HTTP request or another
WebSocket. In this case the "channel" field must not be present, and an
"external" field may be present with the following arguments:
* "content-disposition": a Content-Disposition header for GET responses
* "content-type": a Content-Type header for GET responses
* "protocols": an array of possible protocols for a WebSocket
Channel "group" fields can be used to group channels into groups. You should
prefix your groups with a reverse domain name so they don't conflict with
other or Cockpit's group names. Group names without any punctuation are
reserved.
One such special group name is "default", which contains all channels which
were opened without specifying a group.
Another one is the "fence" group. While any channels are open in the "fence"
group, any channels opened after that point will be blocked and wait until all
channels in the "fence" group are closed before resuming.
The "flow-control" option controls whether a channel should attempt to throttle
itself via flow control when sending or receiving large amounts of data. The
current default (when this option is not provided) is to not do flow control.
However, this default will likely change in the future. This only impacts data
sent by the bridge to the browser.
If "send-acks" is set to "bytes" then the bridge will send acknowledgement
messages detailing the number of payload bytes that it has received and
processed. This mechanism is provided for senders (ie: in the browser) who
wish to throttle the data that they're sending to the bridge.
**Host values**
Because the host parameter is how cockpit maps url requests to the correct bridge,
cockpit may need to additional information to route the message correctly.
For example you want to connect to a container ```my-container``` running
on "my.host".
To allow this the host parameter can encode a key/value pair that will
be expanded in the open command json. The format is host+key+value. For example
{
"command": "open",
"channel": "a4",
"payload": "stream",
"host": "my.host+container+my-container"
}
will be expanded to
{
"command": "open",
"channel": "a4",
"payload": "stream",
"host": "my.host",
"host-container": "my-container",
"host": "my.host"
}
Command: close
--------------
The "close" command closes a channel.
The following fields are defined:
* "channel": The id of the channel to close
* "problem": A short problem code for closure, or not present for a normal close
The channel id must be set. An example of a close:
{
"command": "close",
"channel" : "5x",
"problem": "access-denied"
}
Any protocol participant can send this message. The cockpit-bridge and cockpit-ws
backends will send this message when a channel closes whether because of an
error or a normal closure. The frontend cockpit-web will send this when it
wants to close a channel normally. Once either end has sent this message the
channel is considered closed.
See below for a list of problem codes.
When a channel closing is the result of a ssh transport closing cockpit-ws
reports on the authentication methods used while attempting to authenticate
by adding a "auth-method-results" object to the close object. This is mainly
useful to provide helpful error messages and suggestions to users.
The "auth-method-results" object contains a key for each method that cockpit-ws
is able to attempt authentication with as well as the result of the attempt.
For example:
{
"password": "denied"
}
This possible "result" values are:
* "no-server-support": The target server does not support this method.
* "not-provided": cockpit-ws doesn't have a credential to try so this method was skipped.
* "succeeded": Authentication with this method was successful.
* "denied": Authentication with this method was denied.
* "partial": The server wants more authentication.
* "error": Unexpected error occurred when using this method.
* "not-tried": This methods was not tried, usually due to an earlier method succeeding.
Other fields may be present in a close message.
Command: ready
--------------
The "ready" command indicates that the channel implementation (usually
the bridge) is in a ready and settled state. It is not normally necessary to
listen to this control message, since it is possible to start sending payload
over a channel immediately after the open message has been sent.
The following fields are defined:
* "channel": The id of the channel
Other fields may be present in a ready message.
Command: done
-------------
The "done" command indicates that no more messages will be sent on the channel
in the same direction as the "done" was sent.
The following fields are defined:
* "channel": The id of the channel
Either or both endpoints of a channel can send this message. It may only be
sent once.
After it is sent no more messages may be sent in that direction. It is an error
to send further messages, or send another "done" message.
Command: options
----------------
The "options" command sends further channel options on the fly. The contents of
the message depends on the channel payload.
The following fields are defined:
* "channel": The id of the channel
Command: ping
-------------
The "ping" command is simply a keep alive.
No additional fields are defined, but any are allowed. If a "channel"
is set this "ping" will be forwarded. Otherwise it be limited to a single hop.
An example of a ping:
{
"command": "ping",
}
Any protocol participant can send a "ping". It is responded to by sending
a "pong" with identical options as a reply. If a "ping" is sent with a
"channel" field set to a channel that is not currently open, the "ping"
will be ignored as expected, and no "pong" will be sent.
Command: authorize
------------------
The "authorize" command is for communication of authentication and
authorization challenges and responses between cockpit-bridge and
cockpit-ws. Despite the name this is also used for authentication.
For challenge/response authentication, the following fields are defined:
* "cookie": a unique string sent with a challenge that must be
present in the corresponding response.
* "challenge": a challenge string present in messages from a bridge
to cockpit-ws
* "response": a response string present in messages from cockpit-ws
to a bridge
Example authorize challenge and response messages:
{
"command": "authorize",
"cookie": "555",
"challenge": "crypt1:74657374:$6$2rcph,noe92ot..."
}
{
"command": "authorize",
"cookie": "555",
"response": "crypt1:$6$r0oetn2039ntoen..."
}
Authorize messages are used during authentication by authentication
commands (ei: cockpit-session, cockpit-ssh) to obtain the users credentials
from cockpit-ws. An authentication command can send a authorize message
with a response but no cookie. For example
{
"command": "authorize",
"response": "Basic ..."
}
In that case cockpit-ws will store the response and use it in a reply
to a subsequent challenge.
For credential cache authorization, the following fields are defined:
* "credential": Empty or "password"
When set to "password" then a "password" field should also be present
which represents a new password to cache, which replaces any current
passwords. If no password field is present then the passwords are cleared.
Command: kill
-------------
The "kill" command terminates a whole set of channels. It is sent by the frontend
and processed by cockpit-ws.
The following fields are defined:
* "host": optional string kills channels with the given host
* "group": optional string to select only channels opened with the given "group"
If no fields are specified then all channels are terminated.
Command: logout
---------------
The "logout" command is sent by the shell to cockpit-ws. It
disconnects the user.
In older versions, the "logout" command was broadcast to all bridges
and used to terminate privileged ones. Privileged bridges are now
terminated by closing their transport.
Command: hint
-------------
The "hint" command provides hints to other components about the state of things
or what's going to happen next. The remainder of the fields are extensible.
Payload: null
-------------
A channel opened with this payload type will never send data, and will
ignore all data it receives.
Payload: echo
-------------
A channel opened with this payload type will send back all data that
it receives. It sends an "done" when it receives one.
Payload: dbus-json3
-------------------
DBus messages are encoded in JSON payloads by cockpit-web, and decoded in
cockpit-bridge. The 'dbus-json1' and 'dbus-json2' protocols are no
longer supported.
Additional "open" command options are needed to open a channel of this
type:
* "bus": The DBus bus to connect to either "session", "system" or "none".
Defaults to "system" if not present. If set to "none" you must also
provide the address parameter.
* "name": A service name of the DBus service to communicate with by default.
Always omit this field if "bus" is "none". If omitted and "bus" is not
"none" then a "name" field must be specified explicitly on other messages.
* "address": A dbus supported address to connect to. This option is only
used when bus is set to "none". Accepts any valid DBus address or
"internal" to communicate with the internal bridge DBus connection.
The DBus bus name is started on the bus if it is not already running. If it
could not be started the channel is closed with a "not-found". If the DBus
connection closes, the channel closes with "disconnected".
DBus messages are encoded as JSON objects. If an unrecognized JSON object
is received, then the channel is closed with a "protocol-error".
Method calls are a JSON object with a "call" field, whose value is an array,
with parameters in this order: path, interface, method, in arguments.
{
"call": [ "/path", "org.Interface", "Method", [ "arg0", 1, "arg2" ] ],
"id": "cookie"
}
All the various parameters must be valid for their use. arguments may be
null if no DBus method call body is expected. If a "type" field is specified
then it is expected to be the DBus method type signature (no tuple). If a
"flags" field is a string, then this includes message flags. The default flags
option has the "i" flag set:
* "i": Allow interactive authentication.
If no "name" field was specified in the "open" call, indicating which DBus
service to talk to, then one must be specified here along with the "call".
If a DBus method call fails an "error" message will be sent back. An error
will also be sent back in parameters or arguments in the "call" message are
invalid.
An optional "id" field indicates that a response is desired, which will be
sent back in a "reply" or "error" message with the same "id" field.
If an interface has been exported, then the bridge will send "call" messages
in its direction for calls received for on that interface.
Method reply messages are JSON objects with a "reply" field whose value is
an array, the array contains another array of out arguments, or null if
the DBus reply had no body.
{
"reply": [ [ "arg0", 1, 2 ] ],
"id": "cookie"
}
If the call had a "type" field, then the reply will have one too containing
the DBus type signature of the arguments. If a "flags" field was present on
the call, then "flags" will also be present on the reply. Valid out flags
are:
* ">": Big endian message
* "<": Little endian message
An error message is JSON object with an "error" field whose value is an
array. The array contains: error name, error arguments
{
"error": [ "org.Error", [ "Usually a message" ] ]
"id": "cookie"
}
To receive signals you must subscribe to them. This is done by sending a
"add-match" message. It contains various fields to match on. If a field
is missing then it is treated as a wildcard.
"path" limits the signals to those sent by that DBus object path, it must
be a valid object path according to the specification. "path_namespace"
limits signals to the subtree of DBus object paths. It must be a valid
object path according to the specification, and may not be specified
together with "path".
"interface" limits the signals to those sent on the given DBus interface,
and must be a valid interface name. "member" limits the signal to those
of that signal name. "arg0" limits the signals to those that have the
given string as their first argument. If any of the values are not
valid according to the dbus specification, the channel will close with
a "protocol-error".
{
"add-match": {
"name": "org.the.Name",
"path": "/the/path",
"interface": "org.Interface",
"member": "SignalName",
"arg0": "first argument",
}
}
If the "name" field is omitted, it will be populated from the "open" message.
If no "name" was specified in the "open" message, then DBus messages from any
bus name will be matched.
To unsubscribe from DBus signals, use the "remove-match" message. If a
match was added more than once, it must be removed the same number of
times before the signals are actually unsubscribed.
The form of "remove-match" is identical to "add-match".
{
"remove-match": {
"name": "org.the.Name",
"path": "/the/path",
"interface": "org.Interface",
"member": "SignalName",
"arg0": "first argument",
}
}
Signals are sent in JSON objects that have a "signal" field, which is an
array of parameters: path, interface, signal name, and arguments. arguments
may be null if the DBus signal had no body.
{
"signal": [ "/the/path", "org.Interface", "SignalName", [ "arg0", 1, 2 ] ]
}
If a signal message is sent to the bridge, the signal will be emitted.
In addition a "destination" field may be present to indicate whether
the signal should be broadcast or not.
{
"signal": [ "/the/path", "org.Interface", "SignalName", [ "arg0", 1, 2 ] ]
}
If the bus name of the sender of the signal does not match the "name" field of
the "open" message, then a "name" field will be included with the "signal" message.
Properties can be watched with the "watch" request. Either a "path" or
"path_namespace" can be watched. Property changes are listened for with
DBus PropertiesChanged signals. If a "path_namespace" is watched and
path is a DBus ObjectManager, then it is used to watch for new DBus
interfaces, otherwise DBus introspection is used. The "id" field is
optional, if present a "reply" will be sent with this same "id" when
the watch has sent "notify" messages about the things being watched.
{
"watch": {
"name": "org.the.Name",
"path": "/the/path/to/watch",
"interface": org.Interface
}
"id": 5
}
To remove a watch, pass the identical parameters with an "unwatch"
request.
{
"unwatch": {
"path": "/the/path/to/watch"
}
}
If the "name" field is omitted, it will be populated from the "open" message.
Either a "name" field must be specified here or in the "open" message.
Property changes will be sent using a "notify" message. This includes
addition of interfaces without properties, which will be an empty
interface object, or interfaces removed, which will be null. Only the
changes since the last "notify" message will be sent.
{
"notify": {
"/a/path": {
"org.Interface1": {
"Prop1": x,
"Prop2": y
},
"org.Interface2": { }
},
"/another/path": {
"org.Removed": null
}
}
}
If the bus name of the sender of the signal does not match the "name" field of
the "open" message, then a "name" field will be included with the "notify" message.
Interface introspection data is sent using "meta" message. Before the
first time an interface is sent using a "notify" message, a "meta"
will be sent with that interface introspection info. Additional fields
will be defined here, but this is it for now.
{
"meta": {
"org.Interface": {
"methods": {
"Method1": { },
"Method2": { }
},
"properties": {
"Prop1": { "flags": "rw" },
"Prop2": { "flags": "r" }
}
}
}
}
If the bus name of the sender of the signal does not match the "name" field of
the "open" message, then a "name" field will be included with the "meta" message.
Such meta information can also be sent to the bridge, in order to populate the
cache of introspection data for the channel.
When the owner of the DBus "name" (specified in the open message) changes an "owner"
message is sent. The owner value will be the id of the owner or null if the name
is unowned.
{
"owner": "1:"
}
A "publish" message can be used to export DBus interfaces on the bus. The bridge
will then send "call" messages back to the frontend for each method invocation
on the published interface and object path. The interface must first be described
with DBus meta information. If a cookie is specified then a reply will be sent
when the interface is published. If the interface is already published at the given
path, it will be replaced.
{
"publish": [ "/a/path", "org.Interface" ],
"id": "cookie"
}
An "unpublish" message will unexport a DBus interface on the bus. It is not an
error if no such interface has been published.
{
"unpublish": [ "/a/path", "org.Interface" ],
}
DBus types are encoded in various places in these messages, such as the
arguments. These types are encoded as follows:
* byte, int16, uint16, int32, uint32, int64, uint64, double: encoded
as a JSON number
* boolean: encoded as a JSON boolean
* string, object-path, signature: encoded as JSON strings
* array of bytes: encoded as a base64 string
* other arrays, struct/tuple: encoded as JSON arrays
* dict: encoded as a JSON object, if the dict has string keys then those
are used as property names directly, otherwise the keys are JSON encoded and
the resulting string is used as a property name.
* variant: encoded as a JSON object with a "v" field containing a value
and a "t" field containing a DBus type signature.
{
"v": "value",
"t": "s"
}
Payload: http-stream2
---------------------
This channel represents a single HTTP request and response. The request
HTTP headers are sent in the "open" message, and response headers are
returned in a "response" control message.
The remaining messages make up the HTTP request and response bodies.
When the channel is in text mode, the response body is automatically
coerced to UTF-8.
The following HTTP methods are not permitted:
* 'CONNECT'
The following headers are not permitted on requests, some of these
are added automatically as appropriate, and others are stripped from
the response, in particular 'Content-Length':
* 'Accept-Charset'
* 'Accept-Ranges'
* 'Connection'
* 'Content-Length'
* 'Content-MD5'
* 'Content-Range'
* 'Range'
* 'TE'
* 'Trailer'
* 'Transfer-Encoding'
* 'Upgrade'
The following are not accepted on non-binary channels:
* 'Accept-Encoding'
* 'Content-Encoding'
Additional "open" command options are needed to open a channel of this
payload type:
* "unix": Open a channel with the given unix socket.
* "port": Open a channel with the given TCP port on localhost.
* "address": Open a channel that communicates with the given
address instead of localhost. This can be an IP address or a valid
host name. To use this option you must also specify a port.
This option should be used to communicate with external
apis and not as a synonym for the host parameter.
* "method": "GET", "POST", or other valid HTTP method
You may also specify these options:
* "connection": A stable identifier for connection sharing, i.e.
sending multiple requests to a single open connection.
* "headers": JSON object with additional request headers
* "tls": Set to a object to use an https connection.
The TLS object can have the following options:
* "certificate": The client certificate to use, represented as an
object described below.
* "key": The client key to use, described below.
* "authority": Certificate authority(s) to expect as signers of peer.
* "validate": Validate the peer's certificate.
The "certificate", "key" and "authority" are objects with either of
the following fields:
* "file": String with a file name
* "data": String with PEM encoded data
Any data to be sent should be sent via the channel, and then the channel
should be closed without a problem.
Payload: websocket-stream1
--------------------------
This channel payload implements a WebSocket client. The data in the
channel is the message frames.
Most of same options for http-stream2 apply here.
The response headers are send back in a "response" control message.
Payload: stream
---------------
Raw data is sent back and forth to a socket. See cockpitstream.c. The
boundaries of the messages are arbitrary, and depend on how the kernel
and socket buffer things.
If the channel is not binary, then non-UTF-8 data is forced into UTF-8
with a replacement character.
Additional "open" command options should be specified with a channel of
this payload type:
* "unix": Open a channel with the given unix socket.
* "port": Open a channel with the given TCP port on localhost.
* "address": Open a channel that communicates with the given
address instead of localhost. This can be an IP address or a valid
host name. To use this option you must also specify a port.
* "batch": Batches data coming from the stream in blocks of at least this
size. This is not a guarantee. After a short timeout the data will be
sent even if the data doesn't match the batch size. Defaults to zero.
* "latency": The timeout for flushing any cached data in milliseconds.
* "spawn": Spawn a process and connect standard input and standard output
to the channel. Should be an array of strings which is the process
file path and arguments.
You can't specify both "unix" and "spawn" together. When "spawn" is set the
following options can be specified:
* "directory": The directory to spawn the process in.
* "err": If "spawn" is set, and "err" is set to "out", then stderr
is included in the payload data. If "err" is set to "ignore" then, the
stderr output will be discarded. If "err" is set to "message" then it will
be included in the close message. If "pty" is set then stderr is always
included.
* "environ": This is a list of additional environment variables for the new
spawned process. The variables are in the form of "NAME=VALUE". The default
environment is inherited from cockpit-bridge.
* "pty": Execute the command as a terminal pty.
* "window": An object containing "rows" and "cols" properties, which set the
size of the terminal window. Values must be integers between 0 and 0xffff.
This option is only valid if "pty" is true.
If an "done" is sent to the bridge on this channel, then the socket and/or pipe
input is shutdown. The channel will send an "done" when the output of the socket
or pipe is done.
If "spawn" is set and the channel is closed with a "problem" code, then the
process will be sent a SIGTERM signal.
Additionally, a "options" control message may be sent in this channel
to change the "batch", "latency", and "window" options.
Payload: packet
---------------
Raw data is sent back and forth to as messages to a socket. The message
boundaries correspond exactly to the messages sent over the socket.
If the channel is not binary, then non-UTF-8 data is forced into UTF-8
with a replacement character.
Additional "open" command options should be specified with a channel of
this payload type:
* "unix": Open a channel with the given unix socket.
* "max-size": The maximum possible size of a message. Default is 64K
Supports up to 128K. Messages larger than this will be truncated.
If an "done" is sent to the bridge on this channel, then the socket
input is shutdown. The channel will send an "done" when the output of the socket
or pipe is done.
Additionally, a "options" control message may be sent in this channel
to change the "max-size" options.
Payload: fsinfo
----------------
This channel is used to report information about a given path, and the file or
a directory which may reside there, including the possibility of updates. In
the case of directories, information can also be reported about the (directly)
contained entries.
Additional "open" command options should be specified with a channel of
this payload type:
* `path` (mandatory): a string, an absolute path name. If this ends with `/`
then the path must refer to a directory.
* `attrs` (mandatory): a list of strings, the requested attributes to be
reported for the file at `path`, and (optionally) its sub-items. See below
for the possibilities.
* `fnmatch`: (optional, default ''): if non-empty, this is a [`fnmatch`-style
pattern](https://docs.python.org/3/library/fnmatch.html). In case `path`
refers to a readable directory, an `entries` attribute will be reported
(described below). Use `*` to report all files. Can also be used to
implement search (`searc*`) or hide temporary files (`[!.]*`).
* `watch` (optional, default: false): if the channel should watch for changes
* `follow` (default: true): if the trailing component of `path` is a symbolic
link, whether we should follow it. `follow: false` mode is not supported
for `watch` (but is also mostly unnecessary).
A channel is created with an associated absolute pathname (`path`). A path is
a string that you pass to the `open()` syscall. The object returned by that
call is described by the (JSON Document) value of the channel.
Strictly speaking, the path is specified to the channel as a unicode string,
but paths on the filesystem are binary strings. This mapping is handled using
the usual Python convention: filenames are stored in utf8 and encoded and
decoded with `errors='surrogateescape'`, which allows for handling of filenames
which are not utf8.
Conceptually, the channel represents the value of a JSON object describing what
is found at the path, or the reason for an error. Each message on the channel
is a JSON Merge Patch ([RFC
7396](https://datatracker.ietf.org/doc/html/rfc7396)) which updates or replaces
this object.
The top-level keys in the object are:
- `info`: the info about the reported path (described below)
- `error`: an object with information about why `info` can't be reported.
This is currently basically an errno formatted in several possible ways:
- `problem`: a Cockpit "problem" code type of string like `not-found` or
`not-directory`
- `message`: the result of strerror(). Currently English, hopefully
translated at some point
- `errno`: the symbolic `errno` name like `ENOENT` or `ENOTDIR`
- `partial`: `true` if the data is in a "partial" state. This is used when
sending updates in multiple pieces.
The value of the `info` attribute is a JSON object describing the attributes of
the file. Any attribute which cannot be read (eg: due to permissions problems)
is simply not reported.
* `type`: a string: `reg`, `dir`, `lnk`, `chr`, `blk`, `fifo`, or `sock`
* `mode`: an integer representing the "file permission" bits
(`S_IMODE(st_mode)`). As per JSON, this is transmitted as a decimal value,
but it is meant to be interpreted in octal, in the usual way.
* `uid`: an integer, the uid of the file owner (`st_uid`)
* `owner`: a string, or an integer if the lookup failed
* `gid`: an integer, the gid of the file group (`st_gid`)
* `group`: a string, or an integer if the lookup failed
* `size`: an integer, the (apparent) size of the file (`st_size`)
* `modified`: a float, the mtime of the file (`st_mtim`)
* `tag`: a value type: the current 'transaction tag' of the file, with the
same meaning as elsewhere in this document. Ideally: this changes if the
content of the file changes. This is the same as the tag used in `fsread1`
and `fsreplace1`.
* `entries`: for directories: the contents of the directory (see below)
* `target`: for symbolic links: the target of the link (a string)
* `targets`: for directories: extra information about symlink targets for
symlinks found in the directory (see below)
The `entries` attribute is reported iff `fnmatch` is non-empty, and `path`
refers to a readable directory. It is an object where each key is the name of
a file in the directory, and each value is an object describing that file,
using the same attributes as above. `entries` is not reported on entries (ie:
no recursive listing). Listing `entries` in `attrs` is equivalent to
`fnmatch='*'`.
The `targets` attribute is reported iff `targets` is listed in `attrs`. It
contains information that was true at some point in time about the targets of
symbolic links that were found in the current directory. An entry is added
here only in case the entry wouldn't be found in the main `entries` dictionary.
For example, if `path` is `/usr/lib` and `fnmatch` is `*.so` and the directory
contains the links `a.so → a-impl.so`, `b.so → b.so.0` and `c.so -> ../x/c.so`
then the `targets` dictionary would include `b.so.0` (which isn't reported in
entries because it doesn't match `fnmatch`) and `../x/c.so` (which isn't
reported because it's in a different directory). Monitoring these entries for
changes would be expensive, so it's simply not done. Clients are expected to
use this information to flesh out details about directory entries, answering
questions like "`/bin` links to `usr/bin`, but what type of file is that?".
`targets` is incompatible with `follow: false`.
If the provided `path` is a symbolic link, it is followed, unless
`follow: false` is specified. If symbolic links are present in the directory,
they are always reported directly (ie: not followed). `follow: false` is not
supported in combination with `watch: true` but you probably don't need it:
watch mode doesn't only watch the final path component, but all components
leading up to it, including any symlink that have been followed. That means
that you can watch `/etc/localtime` and find out about if the link changed, or
if the contents of the file itself changed, or was deleted or replaced, or also
if `/usr`, `/etc`, or any other directories or intermediate links were changed,
deleted, or moved out of the way.
The life-cycle of the channel works like this:
- When opening the channel, `ready` is always immediately sent.
- One or more patches are sent to modify the initial value of the channel
(`null`). The "initial state" is reached when the value is a object
which does not have the `partial` attribute set on it.
- If `watch` mode is false then `done` is sent immediately, and the channel is
closed.
- Otherwise (`watch: true`), the channel remains open. When any changes are
detected, they are sent as updates to the value of the channel. This may
involve transitions between reporting `info` and reporting `problem`.
- The channel will stay open until the client closes it.
Payload: fswatch1
-----------------
You will get a stream of change notifications for a file or a
directory.
The following options can be specified in the "open" control message:
* "path": The path name to watch. This should be an absolute path to
a file or directory.
Each message on the stream will be a JSON object with the following
fields:
* "event": A string describing the kind of change. One of "changed",
"deleted", "created", "attribute-changed", "moved", or "done-hint".
* "path": The absolute path name of the file that has changed.
* "other": The absolute path name of the other file in case of a "moved"
event.
* "type": If the event was created this contains the type of the new file.
Will be one of: file, directory, link, special or unknown.
In case of an error, the channel will be closed. In addition to the
usual "problem" field, the "close" control message sent by the server
might have the following additional fields:
* "message": A string in the current locale describing the error.
Payload: fslist1
---------------