@@ -114,7 +114,7 @@ type DNSHostsSetter interface {
114
114
115
115
// UpdatesHandler is anything that expects a stream of workspace update diffs.
116
116
type UpdatesHandler interface {
117
- Update (* proto. WorkspaceUpdate ) error
117
+ Update (WorkspaceUpdate ) error
118
118
}
119
119
120
120
// ControlProtocolClients represents an abstract interface to the tailnet control plane via a set
@@ -871,43 +871,51 @@ type TunnelAllWorkspaceUpdatesController struct {
871
871
updater * tunnelUpdater
872
872
}
873
873
874
- type workspace struct {
875
- id uuid.UUID
876
- name string
877
- agents map [uuid.UUID ]agent
874
+ type Workspace struct {
875
+ ID uuid.UUID
876
+ Name string
877
+ Status proto.Workspace_Status
878
+
879
+ ownerUsername string
880
+ agents map [uuid.UUID ]* Agent
878
881
}
879
882
880
- // addAllDNSNames adds names for all of its agents to the given map of names
881
- func (w workspace ) addAllDNSNames (names map [dnsname.FQDN ][]netip.Addr , owner string ) error {
882
- for _ , a := range w .agents {
883
+ // updateDNSNames updates the DNS names for all agents in the workspace.
884
+ func (w * Workspace ) updateDNSNames () error {
885
+ for id , a := range w .agents {
886
+ names := make (map [dnsname.FQDN ][]netip.Addr )
883
887
// TODO: technically, DNS labels cannot start with numbers, but the rules are often not
884
888
// strictly enforced.
885
- fqdn , err := dnsname .ToFQDN (fmt .Sprintf ("%s.%s.me.coder." , a .name , w .name ))
886
- if err != nil {
887
- return err
888
- }
889
- names [fqdn ] = []netip.Addr {CoderServicePrefix .AddrFromUUID (a .id )}
890
- fqdn , err = dnsname .ToFQDN (fmt .Sprintf ("%s.%s.%s.coder." , a .name , w .name , owner ))
889
+ fqdn , err := dnsname .ToFQDN (fmt .Sprintf ("%s.%s.me.coder." , a .Name , w .Name ))
891
890
if err != nil {
892
891
return err
893
892
}
894
- names [fqdn ] = []netip.Addr {CoderServicePrefix .AddrFromUUID (a .id )}
895
- }
896
- if len (w .agents ) == 1 {
897
- fqdn , err := dnsname .ToFQDN (fmt .Sprintf ("%s.coder." , w .name ))
893
+ names [fqdn ] = []netip.Addr {CoderServicePrefix .AddrFromUUID (a .ID )}
894
+ fqdn , err = dnsname .ToFQDN (fmt .Sprintf ("%s.%s.%s.coder." , a .Name , w .Name , w .ownerUsername ))
898
895
if err != nil {
899
896
return err
900
897
}
901
- for _ , a := range w .agents {
902
- names [fqdn ] = []netip.Addr {CoderServicePrefix .AddrFromUUID (a .id )}
898
+ names [fqdn ] = []netip.Addr {CoderServicePrefix .AddrFromUUID (a .ID )}
899
+ if len (w .agents ) == 1 {
900
+ fqdn , err := dnsname .ToFQDN (fmt .Sprintf ("%s.coder." , w .Name ))
901
+ if err != nil {
902
+ return err
903
+ }
904
+ for _ , a := range w .agents {
905
+ names [fqdn ] = []netip.Addr {CoderServicePrefix .AddrFromUUID (a .ID )}
906
+ }
903
907
}
908
+ a .Hosts = names
909
+ w .agents [id ] = a
904
910
}
905
911
return nil
906
912
}
907
913
908
- type agent struct {
909
- id uuid.UUID
910
- name string
914
+ type Agent struct {
915
+ ID uuid.UUID
916
+ Name string
917
+ WorkspaceID uuid.UUID
918
+ Hosts map [dnsname.FQDN ][]netip.Addr
911
919
}
912
920
913
921
func (t * TunnelAllWorkspaceUpdatesController ) New (client WorkspaceUpdatesClient ) CloserWaiter {
@@ -922,40 +930,43 @@ func (t *TunnelAllWorkspaceUpdatesController) New(client WorkspaceUpdatesClient)
922
930
updateHandler : t .updateHandler ,
923
931
ownerUsername : t .ownerUsername ,
924
932
recvLoopDone : make (chan struct {}),
925
- workspaces : make (map [uuid.UUID ]* workspace ),
933
+ workspaces : make (map [uuid.UUID ]* Workspace ),
926
934
}
927
935
t .updater = updater
928
936
go t .updater .recvLoop ()
929
937
return t .updater
930
938
}
931
939
932
- func (t * TunnelAllWorkspaceUpdatesController ) CurrentState () * proto. WorkspaceUpdate {
940
+ func (t * TunnelAllWorkspaceUpdatesController ) CurrentState () ( WorkspaceUpdate , error ) {
933
941
t .mu .Lock ()
934
942
defer t .mu .Unlock ()
935
943
if t .updater == nil {
936
- return nil
944
+ return WorkspaceUpdate {}, xerrors . New ( "no updater" )
937
945
}
938
946
t .updater .Lock ()
939
947
defer t .updater .Unlock ()
940
- out := & proto.WorkspaceUpdate {
941
- UpsertedWorkspaces : make ([]* proto.Workspace , 0 , len (t .updater .workspaces )),
942
- UpsertedAgents : make ([]* proto.Agent , 0 , len (t .updater .workspaces )),
948
+ out := WorkspaceUpdate {
949
+ UpsertedWorkspaces : make ([]* Workspace , 0 , len (t .updater .workspaces )),
950
+ UpsertedAgents : make ([]* Agent , 0 , len (t .updater .workspaces )),
951
+ DeletedWorkspaces : make ([]* Workspace , 0 ),
952
+ DeletedAgents : make ([]* Agent , 0 ),
943
953
}
944
954
for _ , w := range t .updater .workspaces {
945
- upw := & proto. Workspace {
946
- Id : UUIDToByteSlice ( w . id ) ,
947
- Name : w . name ,
948
- }
949
- out . UpsertedWorkspaces = append ( out . UpsertedWorkspaces , upw )
955
+ out . UpsertedWorkspaces = append ( out . UpsertedWorkspaces , & Workspace {
956
+ ID : w . ID ,
957
+ Name : w . Name ,
958
+ Status : w . Status ,
959
+ } )
950
960
for _ , a := range w .agents {
951
- out .UpsertedAgents = append (out .UpsertedAgents , & proto.Agent {
952
- Id : UUIDToByteSlice (a .id ),
953
- Name : a .name ,
954
- WorkspaceId : UUIDToByteSlice (w .id ),
961
+ out .UpsertedAgents = append (out .UpsertedAgents , & Agent {
962
+ ID : a .ID ,
963
+ Name : a .Name ,
964
+ WorkspaceID : a .WorkspaceID ,
965
+ Hosts : maps .Clone (a .Hosts ),
955
966
})
956
967
}
957
968
}
958
- return out
969
+ return out , nil
959
970
}
960
971
961
972
type tunnelUpdater struct {
@@ -969,7 +980,7 @@ type tunnelUpdater struct {
969
980
recvLoopDone chan struct {}
970
981
971
982
sync.Mutex
972
- workspaces map [uuid.UUID ]* workspace
983
+ workspaces map [uuid.UUID ]* Workspace
973
984
closed bool
974
985
}
975
986
@@ -1031,20 +1042,78 @@ func (t *tunnelUpdater) recvLoop() {
1031
1042
}
1032
1043
}
1033
1044
1045
+ type WorkspaceUpdate struct {
1046
+ UpsertedWorkspaces []* Workspace
1047
+ UpsertedAgents []* Agent
1048
+ DeletedWorkspaces []* Workspace
1049
+ DeletedAgents []* Agent
1050
+ }
1051
+
1052
+ func (w * WorkspaceUpdate ) Clone () WorkspaceUpdate {
1053
+ clone := WorkspaceUpdate {
1054
+ UpsertedWorkspaces : make ([]* Workspace , len (w .UpsertedWorkspaces )),
1055
+ UpsertedAgents : make ([]* Agent , len (w .UpsertedAgents )),
1056
+ DeletedWorkspaces : make ([]* Workspace , len (w .DeletedWorkspaces )),
1057
+ DeletedAgents : make ([]* Agent , len (w .DeletedAgents )),
1058
+ }
1059
+ for i , ws := range w .UpsertedWorkspaces {
1060
+ clone .UpsertedWorkspaces [i ] = & Workspace {
1061
+ ID : ws .ID ,
1062
+ Name : ws .Name ,
1063
+ Status : ws .Status ,
1064
+ }
1065
+ }
1066
+ for i , a := range w .UpsertedAgents {
1067
+ clone .UpsertedAgents [i ] = & Agent {
1068
+ ID : a .ID ,
1069
+ Name : a .Name ,
1070
+ WorkspaceID : a .WorkspaceID ,
1071
+ Hosts : maps .Clone (a .Hosts ),
1072
+ }
1073
+ }
1074
+ for i , ws := range w .DeletedWorkspaces {
1075
+ clone .DeletedWorkspaces [i ] = & Workspace {
1076
+ ID : ws .ID ,
1077
+ Name : ws .Name ,
1078
+ Status : ws .Status ,
1079
+ }
1080
+ }
1081
+ for i , a := range w .DeletedAgents {
1082
+ clone .DeletedAgents [i ] = & Agent {
1083
+ ID : a .ID ,
1084
+ Name : a .Name ,
1085
+ WorkspaceID : a .WorkspaceID ,
1086
+ Hosts : maps .Clone (a .Hosts ),
1087
+ }
1088
+ }
1089
+ return clone
1090
+ }
1091
+
1034
1092
func (t * tunnelUpdater ) handleUpdate (update * proto.WorkspaceUpdate ) error {
1035
1093
t .Lock ()
1036
1094
defer t .Unlock ()
1095
+
1096
+ currentUpdate := WorkspaceUpdate {
1097
+ UpsertedWorkspaces : []* Workspace {},
1098
+ UpsertedAgents : []* Agent {},
1099
+ DeletedWorkspaces : []* Workspace {},
1100
+ DeletedAgents : []* Agent {},
1101
+ }
1102
+
1037
1103
for _ , uw := range update .UpsertedWorkspaces {
1038
1104
workspaceID , err := uuid .FromBytes (uw .Id )
1039
1105
if err != nil {
1040
1106
return xerrors .Errorf ("failed to parse workspace ID: %w" , err )
1041
1107
}
1042
- w := workspace {
1043
- id : workspaceID ,
1044
- name : uw .Name ,
1045
- agents : make (map [uuid.UUID ]agent ),
1108
+ w := & Workspace {
1109
+ ID : workspaceID ,
1110
+ Name : uw .Name ,
1111
+ Status : uw .Status ,
1112
+ ownerUsername : t .ownerUsername ,
1113
+ agents : make (map [uuid.UUID ]* Agent ),
1046
1114
}
1047
1115
t .upsertWorkspace (w )
1116
+ currentUpdate .UpsertedWorkspaces = append (currentUpdate .UpsertedWorkspaces , w )
1048
1117
}
1049
1118
1050
1119
// delete agents before deleting workspaces, since the agents have workspace ID references
@@ -1057,17 +1126,22 @@ func (t *tunnelUpdater) handleUpdate(update *proto.WorkspaceUpdate) error {
1057
1126
if err != nil {
1058
1127
return xerrors .Errorf ("failed to parse workspace ID: %w" , err )
1059
1128
}
1060
- err = t .deleteAgent (workspaceID , agentID )
1129
+ deletedAgent , err : = t .deleteAgent (workspaceID , agentID )
1061
1130
if err != nil {
1062
1131
return xerrors .Errorf ("failed to delete agent: %w" , err )
1063
1132
}
1133
+ currentUpdate .DeletedAgents = append (currentUpdate .DeletedAgents , deletedAgent )
1064
1134
}
1065
1135
for _ , dw := range update .DeletedWorkspaces {
1066
1136
workspaceID , err := uuid .FromBytes (dw .Id )
1067
1137
if err != nil {
1068
1138
return xerrors .Errorf ("failed to parse workspace ID: %w" , err )
1069
1139
}
1070
- t .deleteWorkspace (workspaceID )
1140
+ deletedWorkspace , err := t .deleteWorkspace (workspaceID )
1141
+ if err != nil {
1142
+ return xerrors .Errorf ("failed to delete workspace: %w" , err )
1143
+ }
1144
+ currentUpdate .DeletedWorkspaces = append (currentUpdate .DeletedWorkspaces , deletedWorkspace )
1071
1145
}
1072
1146
1073
1147
// upsert agents last, after all workspaces have been added and deleted, since agents reference
@@ -1081,17 +1155,18 @@ func (t *tunnelUpdater) handleUpdate(update *proto.WorkspaceUpdate) error {
1081
1155
if err != nil {
1082
1156
return xerrors .Errorf ("failed to parse workspace ID: %w" , err )
1083
1157
}
1084
- a := agent { name : ua .Name , id : agentID }
1158
+ a := & Agent { Name : ua .Name , ID : agentID , WorkspaceID : workspaceID }
1085
1159
err = t .upsertAgent (workspaceID , a )
1086
1160
if err != nil {
1087
1161
return xerrors .Errorf ("failed to upsert agent: %w" , err )
1088
1162
}
1163
+ currentUpdate .UpsertedAgents = append (currentUpdate .UpsertedAgents , a )
1089
1164
}
1090
1165
allAgents := t .allAgentIDs ()
1091
1166
t .coordCtrl .SyncDestinations (allAgents )
1167
+ dnsNames := t .updateDNSNames ()
1092
1168
if t .dnsHostsSetter != nil {
1093
1169
t .logger .Debug (context .Background (), "updating dns hosts" )
1094
- dnsNames := t .allDNSNames ()
1095
1170
err := t .dnsHostsSetter .SetDNSHosts (dnsNames )
1096
1171
if err != nil {
1097
1172
return xerrors .Errorf ("failed to set DNS hosts: %w" , err )
@@ -1101,43 +1176,55 @@ func (t *tunnelUpdater) handleUpdate(update *proto.WorkspaceUpdate) error {
1101
1176
}
1102
1177
if t .updateHandler != nil {
1103
1178
t .logger .Debug (context .Background (), "calling update handler" )
1104
- err := t .updateHandler .Update (update )
1179
+ err := t .updateHandler .Update (currentUpdate . Clone () )
1105
1180
if err != nil {
1106
1181
t .logger .Error (context .Background (), "failed to call update handler" , slog .Error (err ))
1107
1182
}
1108
1183
}
1109
1184
return nil
1110
1185
}
1111
1186
1112
- func (t * tunnelUpdater ) upsertWorkspace (w workspace ) {
1113
- old , ok := t .workspaces [w .id ]
1187
+ func (t * tunnelUpdater ) upsertWorkspace (w * Workspace ) * Workspace {
1188
+ old , ok := t .workspaces [w .ID ]
1114
1189
if ! ok {
1115
- t .workspaces [w .id ] = & w
1116
- return
1190
+ t .workspaces [w .ID ] = w
1191
+ return w
1117
1192
}
1118
- old .name = w .name
1193
+ old .Name = w .Name
1194
+ old .Status = w .Status
1195
+ old .ownerUsername = w .ownerUsername
1196
+ return w
1119
1197
}
1120
1198
1121
- func (t * tunnelUpdater ) deleteWorkspace (id uuid.UUID ) {
1199
+ func (t * tunnelUpdater ) deleteWorkspace (id uuid.UUID ) (* Workspace , error ) {
1200
+ w , ok := t .workspaces [id ]
1201
+ if ! ok {
1202
+ return nil , xerrors .Errorf ("workspace %s not found" , id )
1203
+ }
1122
1204
delete (t .workspaces , id )
1205
+ return w , nil
1123
1206
}
1124
1207
1125
- func (t * tunnelUpdater ) upsertAgent (workspaceID uuid.UUID , a agent ) error {
1208
+ func (t * tunnelUpdater ) upsertAgent (workspaceID uuid.UUID , a * Agent ) error {
1126
1209
w , ok := t .workspaces [workspaceID ]
1127
1210
if ! ok {
1128
1211
return xerrors .Errorf ("workspace %s not found" , workspaceID )
1129
1212
}
1130
- w .agents [a .id ] = a
1213
+ w .agents [a .ID ] = a
1131
1214
return nil
1132
1215
}
1133
1216
1134
- func (t * tunnelUpdater ) deleteAgent (workspaceID , id uuid.UUID ) error {
1217
+ func (t * tunnelUpdater ) deleteAgent (workspaceID , id uuid.UUID ) ( * Agent , error ) {
1135
1218
w , ok := t .workspaces [workspaceID ]
1136
1219
if ! ok {
1137
- return xerrors .Errorf ("workspace %s not found" , workspaceID )
1220
+ return nil , xerrors .Errorf ("workspace %s not found" , workspaceID )
1221
+ }
1222
+ a , ok := w .agents [id ]
1223
+ if ! ok {
1224
+ return nil , xerrors .Errorf ("agent %s not found in workspace %s" , id , workspaceID )
1138
1225
}
1139
1226
delete (w .agents , id )
1140
- return nil
1227
+ return a , nil
1141
1228
}
1142
1229
1143
1230
func (t * tunnelUpdater ) allAgentIDs () []uuid.UUID {
@@ -1150,19 +1237,25 @@ func (t *tunnelUpdater) allAgentIDs() []uuid.UUID {
1150
1237
return out
1151
1238
}
1152
1239
1153
- func (t * tunnelUpdater ) allDNSNames () map [dnsname.FQDN ][]netip.Addr {
1240
+ // updateDNSNames updates the DNS names for all workspaces in the tunnelUpdater.
1241
+ func (t * tunnelUpdater ) updateDNSNames () map [dnsname.FQDN ][]netip.Addr {
1154
1242
names := make (map [dnsname.FQDN ][]netip.Addr )
1155
1243
for _ , w := range t .workspaces {
1156
- err := w .addAllDNSNames ( names , t . ownerUsername )
1244
+ err := w .updateDNSNames ( )
1157
1245
if err != nil {
1158
1246
// This should never happen in production, because converting the FQDN only fails
1159
1247
// if names are too long, and we put strict length limits on agent, workspace, and user
1160
1248
// names.
1161
1249
t .logger .Critical (context .Background (),
1162
1250
"failed to include DNS name(s)" ,
1163
- slog .F ("workspace_id" , w .id ),
1251
+ slog .F ("workspace_id" , w .ID ),
1164
1252
slog .Error (err ))
1165
1253
}
1254
+ for _ , a := range w .agents {
1255
+ for name , addrs := range a .Hosts {
1256
+ names [name ] = addrs
1257
+ }
1258
+ }
1166
1259
}
1167
1260
return names
1168
1261
}
0 commit comments