8
8
from discovery_common .infrastructure import Infrastructure
9
9
from discovery_common .record_link import RecordLink
10
10
from discovery_common .user_service import UserService
11
+ from discovery_common .jobs import Jobs
11
12
from discovery_common .constants import (PAM_USER , PAM_DIRECTORY , PAM_MACHINE , PAM_DATABASE , VERTICES_SORT_MAP ,
12
- DIS_INFRA_GRAPH_ID , RECORD_LINK_GRAPH_ID , USER_SERVICE_GRAPH_ID )
13
+ DIS_INFRA_GRAPH_ID , RECORD_LINK_GRAPH_ID , USER_SERVICE_GRAPH_ID ,
14
+ DIS_JOBS_GRAPH_ID )
13
15
from discovery_common .types import (DiscoveryObject , DiscoveryUser , DiscoveryDirectory , DiscoveryMachine ,
14
- DiscoveryDatabase )
16
+ DiscoveryDatabase , JobContent )
15
17
from discovery_common .dag_sort import sort_infra_vertices
16
18
from keeper_dag import DAG
17
19
from keeper_dag .connection .commander import Connection as CommanderConnection
@@ -32,7 +34,7 @@ class PAMDebugGraphCommand(PAMGatewayActionDiscoverCommandBase):
32
34
# The record to base everything on.
33
35
parser .add_argument ('--gateway' , '-g' , required = True , dest = 'gateway' , action = 'store' ,
34
36
help = 'Gateway name or UID.' )
35
- parser .add_argument ('--type' , '-t' , required = True , choices = ['infra' , 'rl' , 'service' ],
37
+ parser .add_argument ('--type' , '-t' , required = True , choices = ['infra' , 'rl' , 'service' , 'jobs' ],
36
38
dest = 'graph_type' , action = 'store' , help = 'Graph type' , default = 'infra' )
37
39
parser .add_argument ('--raw' , required = False , dest = 'raw' , action = 'store_true' ,
38
40
help = 'Render raw graph. Will render corrupt graphs.' )
@@ -59,7 +61,8 @@ class PAMDebugGraphCommand(PAMGatewayActionDiscoverCommandBase):
59
61
graph_id_map = {
60
62
"infra" : DIS_INFRA_GRAPH_ID ,
61
63
"rl" : RECORD_LINK_GRAPH_ID ,
62
- "service" : USER_SERVICE_GRAPH_ID
64
+ "service" : USER_SERVICE_GRAPH_ID ,
65
+ "jobs" : DIS_JOBS_GRAPH_ID
63
66
}
64
67
65
68
def get_parser (self ):
@@ -283,6 +286,102 @@ def _handle(current_vertex: DAGVertex, parent_vertex: Optional[DAGVertex] = None
283
286
284
287
_handle (current_vertex = configuration , parent_vertex = None , indent = indent )
285
288
289
+ def _do_text_list_jobs (self , params : KeeperParams , gateway_context : GatewayContext , debug_level : int = 0 ,
290
+ indent : int = 0 ):
291
+
292
+ infra = Infrastructure (record = gateway_context .configuration , params = params , logger = logging ,
293
+ debug_level = debug_level , fail_on_corrupt = False )
294
+ infra .load (sync_point = 0 )
295
+
296
+ pad = ""
297
+ if indent > 0 :
298
+ pad = "" .ljust (2 * indent , ' ' ) + "* "
299
+
300
+ conn = get_connection (params )
301
+ graph_sync = DAG (conn = conn , record = gateway_context .configuration , logger = logging , debug_level = debug_level ,
302
+ graph_id = DIS_JOBS_GRAPH_ID )
303
+ graph_sync .load (0 )
304
+ configuration = graph_sync .get_root
305
+ vertices = configuration .has_vertices ()
306
+ if len (vertices ) == 0 :
307
+ print (self ._f (f"The jobs graph has not been initialized. Only has root vertex." ))
308
+ return
309
+
310
+ vertex = vertices [0 ]
311
+ if vertex .has_data is False :
312
+ print (self ._f (f"The job vertex does not contain any data" ))
313
+ return
314
+
315
+ current_json = vertex .content_as_str
316
+ if current_json is None :
317
+ print (self ._f (f"The current job vertex content is None" ))
318
+ return
319
+
320
+ content = JobContent .model_validate_json (current_json )
321
+ print (f"{ pad } { self ._b ('Active Job ID' )} : { content .active_job_id } " )
322
+ print ("" )
323
+ print (f"{ pad } { self ._h ('History' )} " )
324
+ print ("" )
325
+ for job in content .job_history :
326
+ print (f"{ pad } --------------------------------------" )
327
+ print (f"{ pad } Job Id: { job .job_id } " )
328
+ print (f"{ pad } Started: { job .start_ts_str } " )
329
+ print (f"{ pad } Ended: { job .end_ts_str } " )
330
+ print (f"{ pad } Duration: { job .duration_sec_str } " )
331
+ print (f"{ pad } Infra Sync Point: { job .sync_point } " )
332
+ if job .success is True :
333
+ print (f"{ pad } Status: { self ._gr ('Success' )} " )
334
+ else :
335
+ print (f"{ pad } Status: { self ._f ('Fail' )} " )
336
+ if job .error is not None :
337
+ print (f"{ pad } Error: { self ._gr (job .error )} " )
338
+
339
+ print ("" )
340
+
341
+ if job .delta is None :
342
+ print (f"{ pad } { self ._f ('The job is missing a delta, never finished discovery.' )} " )
343
+ else :
344
+ if len (job .delta .added ) > 0 :
345
+ print (f"{ pad } { self ._h ('Added' )} " )
346
+ for added in job .delta .added :
347
+ vertex = infra .dag .get_vertex (added .uid )
348
+ if vertex is None :
349
+ print (f"{ pad } * Vertex { added .uid } does not exists." )
350
+ else :
351
+ if vertex .active is False :
352
+ print (f"{ pad } * Vertex { added .uid } is inactive." )
353
+ elif vertex .corrupt is True :
354
+ print (f"{ pad } * Vertex { added .uid } is corrupt." )
355
+ else :
356
+ content = DiscoveryObject .get_discovery_object (vertex )
357
+ print (f"{ pad } * { content .description } ; Record UID: { content .record_uid } " )
358
+ print ("" )
359
+
360
+ if len (job .delta .changed ) > 0 :
361
+ print (f"{ pad } { self ._h ('Changed' )} " )
362
+ for changed in job .delta .changed :
363
+ vertex = infra .dag .get_vertex (changed .uid )
364
+ if vertex is None :
365
+ print (f"{ pad } * Vertex { changed .uid } does not exists." )
366
+ else :
367
+ if vertex .active is False :
368
+ print (f"{ pad } * Vertex { changed .uid } is inactive." )
369
+ elif vertex .corrupt is True :
370
+ print (f"{ pad } * Vertex { changed .uid } is corrupt." )
371
+ else :
372
+ content = DiscoveryObject .get_discovery_object (vertex )
373
+ print (f"{ pad } * { content .description } ; Record UID: { content .record_uid } " )
374
+ if changed .changes is not None :
375
+ for k , v in changed .changes .items ():
376
+ print (f"{ pad } { k } = { v } " )
377
+ print ("" )
378
+
379
+ if len (job .delta .deleted ) > 0 :
380
+ print (f"{ pad } { self ._h ('Deleted' )} " )
381
+ for deleted in job .delta .deleted :
382
+ print (f"{ pad } * Removed vertex { deleted .uid } ." )
383
+ print ("" )
384
+
286
385
def _do_render_infra (self , params : KeeperParams , gateway_context : GatewayContext , filepath : str , graph_format : str ,
287
386
debug_level : int = 0 ):
288
387
@@ -352,6 +451,24 @@ def _do_render_service(self, params: KeeperParams, gateway_context: GatewayConte
352
451
raise err
353
452
print ("" )
354
453
454
+ def _do_render_jobs (self , params : KeeperParams , gateway_context : GatewayContext , filepath : str ,
455
+ graph_format : str , debug_level : int = 0 ):
456
+
457
+ jobs = Jobs (record = gateway_context .configuration , params = params , logger = logging , debug_level = debug_level )
458
+
459
+ print ("" )
460
+ dot_instance = jobs .dag .to_dot ()
461
+ if graph_format == "raw" :
462
+ print (dot_instance )
463
+ else :
464
+ try :
465
+ dot_instance .render (filepath )
466
+ print (f"Job graph rendered to { self ._gr (filepath )} " )
467
+ except Exception as err :
468
+ print (self ._f (f"Could not generate graph: { err } " ))
469
+ raise err
470
+ print ("" )
471
+
355
472
def _do_raw_text_list (self , params : KeeperParams , gateway_context : GatewayContext , graph_id : int = 0 ,
356
473
debug_level : int = 0 ):
357
474
0 commit comments