@@ -30,6 +30,7 @@ import (
30
30
31
31
const (
32
32
workspaceIndex = "workspaceIndex"
33
+ ipAddressIndex = "ipAddressIndex"
33
34
)
34
35
35
36
// getPortStr extracts the port part from a given URL string. Returns "" if parsing fails or port is not specified.
@@ -77,6 +78,15 @@ func NewCRDWorkspaceInfoProvider(client client.Client, scheme *runtime.Scheme) (
77
78
78
79
return nil , xerrors .Errorf ("object is not a WorkspaceInfo" )
79
80
},
81
+ ipAddressIndex : func (obj interface {}) ([]string , error ) {
82
+ if workspaceInfo , ok := obj .(* common.WorkspaceInfo ); ok {
83
+ if workspaceInfo .IPAddress == "" {
84
+ return nil , nil
85
+ }
86
+ return []string {workspaceInfo .IPAddress }, nil
87
+ }
88
+ return nil , xerrors .Errorf ("object is not a WorkspaceInfo" )
89
+ },
80
90
}
81
91
contextIndexers := cache.Indexers {
82
92
workspaceIndex : func (obj interface {}) ([]string , error ) {
@@ -96,29 +106,73 @@ func NewCRDWorkspaceInfoProvider(client client.Client, scheme *runtime.Scheme) (
96
106
}, nil
97
107
}
98
108
99
- // WorkspaceInfo return the WorkspaceInfo available for the given workspaceID.
109
+ // WorkspaceInfo returns the WorkspaceInfo for the given workspaceID.
110
+ // It performs validation to ensure the workspace is unique and properly associated with its IP address.
100
111
func (r * CRDWorkspaceInfoProvider ) WorkspaceInfo (workspaceID string ) * common.WorkspaceInfo {
101
112
workspaces , err := r .store .ByIndex (workspaceIndex , workspaceID )
102
113
if err != nil {
103
114
return nil
104
115
}
105
116
106
- if len (workspaces ) >= 1 {
107
- if len (workspaces ) != 1 {
108
- log .Warnf ("multiple instances (%d) for workspace %s" , len (workspaces ), workspaceID )
109
- }
117
+ if len (workspaces ) == 0 {
118
+ return nil
119
+ }
110
120
111
- sort . Slice ( workspaces , func ( i , j int ) bool {
112
- a := workspaces [ i ].( * common. WorkspaceInfo )
113
- b := workspaces [ j ].( * common. WorkspaceInfo )
121
+ if len ( workspaces ) > 1 {
122
+ log . WithField ( "workspaceID" , workspaceID ). WithField ( "instanceCount" , len ( workspaces )). Warn ( "multiple workspace instances found" )
123
+ }
114
124
115
- return a .StartedAt .After (b .StartedAt )
116
- })
125
+ sort .Slice (workspaces , func (i , j int ) bool {
126
+ a := workspaces [i ].(* common.WorkspaceInfo )
127
+ b := workspaces [j ].(* common.WorkspaceInfo )
128
+ return a .StartedAt .After (b .StartedAt )
129
+ })
130
+
131
+ wsInfo := workspaces [0 ].(* common.WorkspaceInfo )
132
+
133
+ if wsInfo .IPAddress == "" {
134
+ return wsInfo
135
+ }
136
+
137
+ if conflict , err := r .validateIPAddressConflict (workspaceID , wsInfo .IPAddress ); conflict || err != nil {
138
+ return nil
139
+ }
117
140
118
- return workspaces [0 ].(* common.WorkspaceInfo )
141
+ return wsInfo
142
+ }
143
+
144
+ func (r * CRDWorkspaceInfoProvider ) validateIPAddressConflict (workspaceID , ipAddress string ) (bool , error ) {
145
+ wsInfos , err := r .workspacesInfoByIPAddress (ipAddress )
146
+ if err != nil {
147
+ log .WithError (err ).WithField ("workspaceID" , workspaceID ).WithField ("ipAddress" , ipAddress ).Error ("failed to get workspaces by IP address" )
148
+ return true , err
149
+ }
150
+
151
+ if len (wsInfos ) > 1 {
152
+ log .WithField ("workspaceID" , workspaceID ).WithField ("ipAddress" , ipAddress ).WithField ("workspaceCount" , len (wsInfos )).Warn ("multiple workspaces found for IP address" )
153
+ return true , nil
154
+ }
155
+
156
+ if len (wsInfos ) == 1 && wsInfos [0 ].WorkspaceID != workspaceID {
157
+ log .WithField ("workspaceID" , workspaceID ).WithField ("ipAddress" , ipAddress ).WithField ("foundWorkspaceID" , wsInfos [0 ].WorkspaceID ).Warn ("workspace IP address conflict detected" )
158
+ return true , nil
159
+ }
160
+
161
+ return false , nil
162
+ }
163
+
164
+ func (r * CRDWorkspaceInfoProvider ) workspacesInfoByIPAddress (ipAddress string ) ([]* common.WorkspaceInfo , error ) {
165
+ workspaces := make ([]* common.WorkspaceInfo , 0 )
166
+
167
+ objs , err := r .store .ByIndex (ipAddressIndex , ipAddress )
168
+ if err != nil {
169
+ return nil , err
170
+ }
171
+ for _ , w := range objs {
172
+ workspaces = append (workspaces , w .(* common.WorkspaceInfo ))
119
173
}
120
174
121
- return nil
175
+ return workspaces , nil
122
176
}
123
177
124
178
func (r * CRDWorkspaceInfoProvider ) AcquireContext (ctx context.Context , workspaceID string , port string ) (context.Context , string , error ) {
0 commit comments