@@ -8,17 +8,16 @@ import (
8
8
"path/filepath"
9
9
"strings"
10
10
"encoding/json"
11
- "time"
11
+
12
12
v1 "github.com/karmada-io/dashboard/cmd/api/app/types/api/v1"
13
13
"github.com/gin-gonic/gin"
14
14
"github.com/karmada-io/dashboard/cmd/api/app/router"
15
15
"github.com/karmada-io/dashboard/pkg/client"
16
16
"github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
17
17
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18
18
kubeclient "k8s.io/client-go/kubernetes"
19
- "k8s.io/client-go/tools/clientcmd"
19
+ "k8s.io/client-go/tools/clientcmd"
20
20
"sync"
21
- "log"
22
21
)
23
22
24
23
const (
@@ -31,7 +30,7 @@ const (
31
30
controllerManagerPort = "8080"
32
31
)
33
32
34
- func fetchMetrics (appName string , queryType string , requests chan saveRequest ) (map [string ]* v1.ParsedData , []string , error ) {
33
+ func fetchMetrics (appName string , requests chan saveRequest ) (map [string ]* v1.ParsedData , []string , error ) {
35
34
kubeClient := client .InClusterClient ()
36
35
podsMap , errors := getKarmadaPods (appName )
37
36
if len (podsMap ) == 0 && len (errors ) > 0 {
@@ -101,18 +100,133 @@ func fetchMetrics(appName string, queryType string, requests chan saveRequest) (
101
100
return allMetrics , errors , nil
102
101
}
103
102
104
-
105
-
106
103
func getMetrics (c * gin.Context ) {
107
104
appName := c .Param ("app_name" )
108
105
queryType := c .Query ("type" )
109
106
107
+ if queryType == "sync_on" || queryType == "sync_off" {
108
+ syncValue := 0
109
+ if queryType == "sync_on" {
110
+ syncValue = 1
111
+ }
112
+
113
+ if appName == "" {
114
+ // Stop all apps
115
+ _ , err := db .Exec ("UPDATE app_sync SET sync_trigger = ?" , syncValue )
116
+ if err != nil {
117
+ c .JSON (http .StatusInternalServerError , gin.H {"error" : fmt .Sprintf ("Failed to update sync_trigger for all apps: %v" , err )})
118
+ return
119
+ }
120
+
121
+ // Cancel all existing contexts and create new ones if turning on
122
+ contextMutex .Lock ()
123
+ for app := range appContexts {
124
+ currentSyncValue , _ := syncMap .Load (app )
125
+ if currentSyncValue == syncValue {
126
+ continue // Skip if already in the desired state
127
+ }
128
+
129
+ if cancel , exists := appCancelFuncs [app ]; exists {
130
+ cancel () // Cancel existing context
131
+ }
132
+
133
+ if syncValue == 1 {
134
+ // Create new context if turning on
135
+ ctx , cancel := context .WithCancel (context .Background ())
136
+ appContexts [app ] = ctx
137
+ appCancelFuncs [app ] = cancel
138
+ go startAppMetricsFetcher (app )
139
+ }
140
+
141
+ syncMap .Store (app , syncValue )
142
+ }
143
+ contextMutex .Unlock ()
144
+
145
+ message := "Sync trigger updated successfully for all apps"
146
+ if syncValue == 1 {
147
+ message = "Sync turned on successfully for all apps"
148
+ } else {
149
+ message = "Sync turned off successfully for all apps"
150
+ }
151
+ c .JSON (http .StatusOK , gin.H {"message" : message })
152
+ } else {
153
+ // Update specific app
154
+ currentSyncValue , _ := syncMap .Load (appName )
155
+ if currentSyncValue == syncValue {
156
+ message := fmt .Sprintf ("Sync is already %s for %s" , queryType , appName )
157
+ c .JSON (http .StatusOK , gin.H {"message" : message })
158
+ return
159
+ }
160
+
161
+ _ , err := db .Exec ("UPDATE app_sync SET sync_trigger = ? WHERE app_name = ?" , syncValue , appName )
162
+ if err != nil {
163
+ c .JSON (http .StatusInternalServerError , gin.H {"error" : fmt .Sprintf ("Failed to update sync_trigger: %v" , err )})
164
+ return
165
+ }
166
+
167
+ contextMutex .Lock ()
168
+ if cancel , exists := appCancelFuncs [appName ]; exists {
169
+ cancel () // Cancel existing context
170
+ }
171
+
172
+ if syncValue == 1 {
173
+ // Create new context if turning on
174
+ ctx , cancel := context .WithCancel (context .Background ())
175
+ appContexts [appName ] = ctx
176
+ appCancelFuncs [appName ] = cancel
177
+ go startAppMetricsFetcher (appName )
178
+ }
179
+
180
+ syncMap .Store (appName , syncValue )
181
+ contextMutex .Unlock ()
182
+
183
+ var message string
184
+ if syncValue == 1 {
185
+ message = fmt .Sprintf ("Sync turned on successfully for %s" , appName )
186
+ } else {
187
+ message = fmt .Sprintf ("Sync turned off successfully for %s" , appName )
188
+ }
189
+ c .JSON (http .StatusOK , gin.H {"message" : message })
190
+ }
191
+
192
+ return
193
+ }
194
+
110
195
if queryType == "metricsdetails" {
111
196
queryMetrics (c )
112
197
return
113
198
}
114
199
115
- allMetrics , errors , err := fetchMetrics (appName , queryType , requests )
200
+ if queryType == "sync_status" {
201
+ statusMap := make (map [string ]bool )
202
+
203
+ // Get status for all registered apps
204
+ for _ , app := range []string {
205
+ karmadaScheduler ,
206
+ karmadaControllerManager ,
207
+ karmadaAgent ,
208
+ karmadaSchedulerEstimator + "-member1" ,
209
+ karmadaSchedulerEstimator + "-member2" ,
210
+ karmadaSchedulerEstimator + "-member3" ,
211
+ } {
212
+ syncValue , exists := syncMap .Load (app )
213
+ if ! exists {
214
+ statusMap [app ] = false
215
+ continue
216
+ }
217
+
218
+ if value , ok := syncValue .(int ); ok {
219
+ statusMap [app ] = value == 1
220
+ } else {
221
+ statusMap [app ] = false
222
+ }
223
+ }
224
+
225
+ c .JSON (http .StatusOK , statusMap )
226
+ return
227
+ }
228
+
229
+ allMetrics , errors , err := fetchMetrics (appName , requests )
116
230
if err != nil {
117
231
c .JSON (http .StatusInternalServerError , gin.H {"errors" : errors , "error" : err .Error ()})
118
232
return
@@ -125,7 +239,6 @@ func getMetrics(c *gin.Context) {
125
239
}
126
240
127
241
128
-
129
242
func getKarmadaAgentMetrics (podName string , clusterName string , requests chan saveRequest ) (* v1.ParsedData , error ) {
130
243
kubeClient := client .InClusterKarmadaClient ()
131
244
clusters , err := kubeClient .ClusterV1alpha1 ().Clusters ().List (context .TODO (), metav1.ListOptions {})
@@ -201,16 +314,14 @@ func getKarmadaAgentMetrics(podName string, clusterName string, requests chan sa
201
314
data : parsedData ,
202
315
result : nil , // Not waiting for result
203
316
}
204
- // if err := <-resultChan; err != nil {
205
- // return nil, fmt.Errorf("failed to save metrics to DB: %v", err)
206
- // }
207
-
208
317
return parsedData , nil
209
318
}
319
+
210
320
func isJSON (data []byte ) bool {
211
321
var js json.RawMessage
212
322
return json .Unmarshal (data , & js ) == nil
213
323
}
324
+
214
325
func getClusterPods (cluster * v1alpha1.Cluster ) ([]v1.PodInfo , error ) {
215
326
fmt .Printf ("Getting pods for cluster: %s\n " , cluster .Name )
216
327
@@ -292,55 +403,23 @@ func getKarmadaPods(appName string) (map[string][]v1.PodInfo, []string) {
292
403
293
404
return podsMap , errors
294
405
}
295
- var (requests chan saveRequest )
296
406
297
- func startAppMetricsFetcher (appName string ) {
298
- ticker := time .NewTicker (1 * time .Second )
299
- defer ticker .Stop ()
300
- for range ticker .C {
301
- fmt .Printf ("Fetching metrics for %s at %s\n " , appName , time .Now ().Format (time .RFC3339 ))
302
- go func () {
303
- _ , errors , err := fetchMetrics (appName , "" , requests )
304
- if err != nil {
305
- log .Printf ("Error fetching metrics for %s: %v, errors: %v\n " , appName , err , errors )
306
- } else {
307
- log .Printf ("Successfully fetched metrics for %s\n " , appName )
308
- }
309
- }()
407
+ func init () {
408
+ goroutine ()
409
+ // Initialize the router with modified endpoints
410
+ r := router .V1 ()
411
+ r .GET ("/metrics" , getMetrics )
412
+ r .GET ("/metrics/:app_name" , getMetrics )
413
+ r .GET ("/metrics/:app_name/:pod_name" , queryMetrics )
310
414
}
311
- }
312
415
313
- func init () {
314
- // Initialize the application names
315
- appNames := []string {
316
- karmadaScheduler ,
317
- karmadaControllerManager ,
318
- karmadaAgent ,
319
- karmadaSchedulerEstimator + "-member1" ,
320
- karmadaSchedulerEstimator + "-member2" ,
321
- karmadaSchedulerEstimator + "-member3" ,
322
- }
323
416
324
- // Initialize the request channel
325
- requests = make (chan saveRequest , len (appNames )) // Buffered channel
326
-
327
- // Start the database worker
328
- go startDatabaseWorker (requests )
329
-
330
- // Start the per-app periodic metrics fetcher
331
- for _ , app := range appNames {
332
- go startAppMetricsFetcher (app )
333
- }
334
-
335
- // Initialize the router
336
- r := router .V1 ()
337
- r .GET ("/metrics/:app_name" , getMetrics )
338
- r .GET ("/metrics/:app_name/:pod_name" , queryMetrics )
339
417
// http://localhost:8000/api/v1/metrics/karmada-scheduler //from terminal
340
418
341
419
// http://localhost:8000/api/v1/metrics/karmada-scheduler?type=metricsdetails //from sqlite details bar
342
420
343
421
// http://localhost:8000/api/v1/metrics/karmada-scheduler/karmada-scheduler-7bd4659f9f-hh44f?type=details&mname=workqueue_queue_duration_seconds
344
422
345
- // all metrics details
346
- }
423
+ // http://localhost:8000/api/v1/metrics?type=sync_off // to skip all metrics
424
+
425
+ // http://localhost:8000/api/v1/metrics/karmada-scheduler?type=sync_off // to skip specific metrics
0 commit comments