2
2
import json
3
3
import boto3
4
4
from typing import Optional
5
+ from tabulate import tabulate
5
6
6
7
from sagemaker .hyperpod .cli .inference_utils import generate_click_command
7
8
from jumpstart_inference_config_schemas .registry import SCHEMA_REGISTRY as JS_REG
@@ -104,8 +105,18 @@ def js_list(
104
105
"""
105
106
106
107
endpoints = HPJumpStartEndpoint .model_construct ().list (namespace )
107
- out = [ep .metadata .model_dump () for ep in endpoints ]
108
- click .echo (json .dumps (out , indent = 2 ))
108
+ data = [ep .metadata .model_dump () for ep in endpoints ]
109
+
110
+ if not data :
111
+ click .echo ("No endpoints found" )
112
+ return
113
+
114
+ headers = ["name" , "namespace" , "labels" ]
115
+ rows = [
116
+ [item .get ("name" , "" ), item .get ("namespace" , "" ), item .get ("labels" , "" )]
117
+ for item in data
118
+ ]
119
+ click .echo (tabulate (rows , headers = headers , tablefmt = "github" ))
109
120
110
121
111
122
@click .command ("hyp-custom-endpoint" )
@@ -124,8 +135,18 @@ def custom_list(
124
135
"""
125
136
126
137
endpoints = HPEndpoint .model_construct ().list (namespace )
127
- out = [ep .metadata .model_dump () for ep in endpoints ]
128
- click .echo (json .dumps (out , indent = 2 ))
138
+ data = [ep .metadata .model_dump () for ep in endpoints ]
139
+
140
+ if not data :
141
+ click .echo ("No endpoints found" )
142
+ return
143
+
144
+ headers = ["name" , "namespace" , "labels" ]
145
+ rows = [
146
+ [item .get ("name" , "" ), item .get ("namespace" , "" ), item .get ("labels" , "" )]
147
+ for item in data
148
+ ]
149
+ click .echo (tabulate (rows , headers = headers , tablefmt = "github" ))
129
150
130
151
131
152
@click .command ("hyp-jumpstart-endpoint" )
@@ -142,16 +163,86 @@ def custom_list(
142
163
default = "default" ,
143
164
help = "Optional. The namespace of the jumpstart model to describe. Default set to 'default'." ,
144
165
)
166
+ @click .option (
167
+ "--full" ,
168
+ type = click .BOOL ,
169
+ is_flag = True ,
170
+ default = False ,
171
+ required = False ,
172
+ help = "Optional. If set to `True`, the full json will be displayed" ,
173
+ )
145
174
def js_describe (
146
175
name : str ,
147
176
namespace : Optional [str ],
177
+ full : bool
148
178
):
149
179
"""
150
180
Describe a jumpstart model endpoint with provided name and namespace.
151
181
"""
152
182
153
183
my_endpoint = HPJumpStartEndpoint .model_construct ().get (name , namespace )
154
- click .echo (json .dumps (my_endpoint .model_dump (), indent = 2 ))
184
+ data = my_endpoint .model_dump ()
185
+
186
+ if full :
187
+ click .echo ("\n Full JSON:" )
188
+ click .echo (json .dumps (data , indent = 2 ))
189
+
190
+ else :
191
+ summary = [
192
+ ("Deployment State:" , data .get ("status" , {}).get ("deploymentStatus" , {}).get ("deploymentObjectOverallState" )),
193
+ ("Model ID:" , data .get ("model" , {}).get ("modelId" )),
194
+ ("Instance Type:" , data .get ("server" , {}).get ("instanceType" )),
195
+ ("Accept eula:" , data .get ("model" , {}).get ("acceptEula" )),
196
+ ("Model Version:" , data .get ("model" , {}).get ("modelVersion" )),
197
+ ("TLS Cert. Output S3 URI:" ,data .get ("tlsConfig" , {}).get ("tlsCertificateOutputS3Uri" )),
198
+ ]
199
+ click .echo (tabulate (summary , tablefmt = "plain" ))
200
+
201
+ click .echo ("\n SageMaker Endpoint:" )
202
+ ep_rows = [
203
+ ("State:" , data .get ("status" , {}).get ("endpoints" , {}).get ("sagemaker" , {}).get ("state" )),
204
+ ("Name:" , data .get ("sageMakerEndpoint" , {}).get ("name" )),
205
+ ("ARN:" , data .get ("status" , {}).get ("endpoints" , {}).get ("sagemaker" , {}).get ("endpointArn" )),
206
+ ]
207
+ click .echo (tabulate (ep_rows , tablefmt = "plain" ))
208
+
209
+ click .echo ("\n Conditions:" )
210
+ conds = data .get ("status" , {}).get ("conditions" , [])
211
+ if conds :
212
+ headers = ["TYPE" , "STATUS" , "LAST TRANSITION" , "LAST UPDATE" , "MESSAGE" ]
213
+ rows = [
214
+ [
215
+ c .get ("type" , "" ),
216
+ c .get ("status" , "" ),
217
+ c .get ("lastTransitionTime" , "" ),
218
+ c .get ("lastUpdateTime" , "" ),
219
+ c .get ("message" ) or ""
220
+ ]
221
+ for c in conds
222
+ ]
223
+ click .echo (tabulate (rows , headers = headers , tablefmt = "github" ))
224
+ else :
225
+ click .echo (" <none>" )
226
+
227
+ click .echo ("\n DeploymentStatus Conditions:" )
228
+ dep_status = data .get ("status" , {}).get ("deploymentStatus" , {})
229
+ dep_conds = dep_status .get ("status" , {}).get ("conditions" , [])
230
+ if dep_conds :
231
+ headers = ["TYPE" , "STATUS" , "LAST TRANSITION" , "LAST UPDATE" , "MESSAGE" ]
232
+ rows = [
233
+ [
234
+ c .get ("type" , "" ),
235
+ c .get ("status" , "" ),
236
+ c .get ("lastTransitionTime" , "" ),
237
+ c .get ("lastUpdateTime" , "" ),
238
+ c .get ("message" ) or ""
239
+ ]
240
+ for c in dep_conds
241
+ ]
242
+ click .echo (tabulate (rows , headers = headers , tablefmt = "github" ))
243
+ else :
244
+ click .echo (" <none>" )
245
+
155
246
156
247
157
248
@click .command ("hyp-custom-endpoint" )
@@ -168,16 +259,167 @@ def js_describe(
168
259
default = "default" ,
169
260
help = "Optional. The namespace of the custom model to describe. Default set to 'default'." ,
170
261
)
262
+ @click .option (
263
+ "--full" ,
264
+ type = click .BOOL ,
265
+ is_flag = True ,
266
+ default = False ,
267
+ required = False ,
268
+ help = "Optional. If set to `True`, the full json will be displayed" ,
269
+ )
171
270
def custom_describe (
172
271
name : str ,
173
272
namespace : Optional [str ],
273
+ full : bool
174
274
):
175
275
"""
176
276
Describe a custom model endpoint with provided name and namespace.
177
277
"""
178
278
179
279
my_endpoint = HPEndpoint .model_construct ().get (name , namespace )
180
- click .echo (json .dumps (my_endpoint .model_dump (), indent = 2 ))
280
+ data = my_endpoint .model_dump ()
281
+
282
+ if full :
283
+ click .echo ("\n Full JSON:" )
284
+ click .echo (json .dumps (data , indent = 2 ))
285
+
286
+ else :
287
+ summary = [
288
+ ("Deployment State:" , data .get ("status" , {}).get ("deploymentStatus" , {}).get ("deploymentObjectOverallState" )),
289
+ ("Invocation Endpoint" , data .get ("invocationEndpoint" )),
290
+ ("Instance Type" , data .get ("instanceType" )),
291
+ ("Metrics Enabled" , data .get ("metrics" , {}).get ("enabled" )),
292
+ ("Model Name" , data .get ("modelName" )),
293
+ ("Model Version" , data .get ("modelVersion" )),
294
+ ("Model Source Type" , data .get ("modelSourceConfig" , {}).get ("modelSourceType" )),
295
+ ("Model Location" , data .get ("modelSourceConfig" , {}).get ("modelLocation" )),
296
+ ("Prefetch Enabled" , data .get ("modelSourceConfig" , {}).get ("prefetchEnabled" )),
297
+ ("TLS Cert S3 URI" , data .get ("tlsConfig" , {}).get ("tlsCertificateOutputS3Uri" )),
298
+ ("FSx DNS Name" , data .get ("modelSourceConfig" , {}).get ("fsxStorage" , {}).get ("dnsName" )),
299
+ ("FSx File System ID" , data .get ("modelSourceConfig" , {}).get ("fsxStorage" , {}).get ("fileSystemId" )),
300
+ ("FSx Mount Name" , data .get ("modelSourceConfig" , {}).get ("fsxStorage" , {}).get ("mountName" )),
301
+ ("S3 Bucket Name" , data .get ("modelSourceConfig" , {}).get ("s3Storage" , {}).get ("bucketName" )),
302
+ ("S3 Region" , data .get ("modelSourceConfig" , {}).get ("s3Storage" , {}).get ("region" )),
303
+ ("Image URI" , data .get ("imageUri" )
304
+ or data .get ("worker" , {}).get ("image" )),
305
+ ("Container Port" , data .get ("containerPort" )
306
+ or data .get ("worker" , {})
307
+ .get ("modelInvocationPort" , {})
308
+ .get ("containerPort" )),
309
+ ("Model Volume Mount Path" , data .get ("modelVolumeMountPath" )
310
+ or data .get ("worker" , {})
311
+ .get ("modelVolumeMount" , {})
312
+ .get ("mountPath" )),
313
+ ("Model Volume Mount Name" , data .get ("modelVolumeMountName" )
314
+ or data .get ("worker" , {})
315
+ .get ("modelVolumeMount" , {})
316
+ .get ("name" )),
317
+ ("Resources Limits" , data .get ("resourcesLimits" )
318
+ or data .get ("worker" , {})
319
+ .get ("resources" , {})
320
+ .get ("limits" )),
321
+ ("Resources Requests" , data .get ("resourcesRequests" )
322
+ or data .get ("worker" , {})
323
+ .get ("resources" , {})
324
+ .get ("requests" )),
325
+ ("Dimensions" , data .get ("dimensions" )
326
+ or data .get ("autoScalingSpec" , {})
327
+ .get ("cloudWatchTrigger" , {})
328
+ .get ("dimensions" )),
329
+ ("Metric Collection Period" , data .get ("metricCollectionPeriod" )
330
+ or data .get ("autoScalingSpec" , {})
331
+ .get ("cloudWatchTrigger" , {})
332
+ .get ("metricCollectionPeriod" )),
333
+ ("Metric Collection Start Time" ,data .get ("metricCollectionStartTime" )
334
+ or data .get ("autoScalingSpec" , {})
335
+ .get ("cloudWatchTrigger" , {})
336
+ .get ("metricCollectionStartTime" )),
337
+ ("Metric Name" , data .get ("metricName" )
338
+ or data .get ("autoScalingSpec" , {})
339
+ .get ("cloudWatchTrigger" , {})
340
+ .get ("metricName" )),
341
+ ("Metric Stat" , data .get ("metricStat" )
342
+ or data .get ("autoScalingSpec" , {})
343
+ .get ("cloudWatchTrigger" , {})
344
+ .get ("metricStat" )),
345
+ ("Metric Type" , data .get ("metricType" )
346
+ or data .get ("autoScalingSpec" , {})
347
+ .get ("cloudWatchTrigger" , {})
348
+ .get ("metricType" )),
349
+ ("Min Value" , data .get ("minValue" )
350
+ or data .get ("autoScalingSpec" , {})
351
+ .get ("cloudWatchTrigger" , {})
352
+ .get ("minValue" )),
353
+ ("CW Trigger Name" , data .get ("cloudWatchTriggerName" )
354
+ or data .get ("autoScalingSpec" , {})
355
+ .get ("cloudWatchTrigger" , {})
356
+ .get ("name" )),
357
+ ("CW Trigger Namespace" , data .get ("cloudWatchTriggerNamespace" )
358
+ or data .get ("autoScalingSpec" , {})
359
+ .get ("cloudWatchTrigger" , {})
360
+ .get ("namespace" )),
361
+ ("Target Value" , data .get ("targetValue" )
362
+ or data .get ("autoScalingSpec" , {})
363
+ .get ("cloudWatchTrigger" , {})
364
+ .get ("targetValue" )),
365
+ ("Use Cached Metrics" , data .get ("useCachedMetrics" )
366
+ or data .get ("autoScalingSpec" , {})
367
+ .get ("cloudWatchTrigger" , {})
368
+ .get ("useCachedMetrics" )),
369
+ ]
370
+
371
+ click .echo (tabulate (summary , tablefmt = "plain" ))
372
+
373
+ click .echo ("\n SageMaker Endpoint:" )
374
+ status = data .get ("status" ) or {}
375
+ endpoints = status .get ("endpoints" ) or {}
376
+ sagemaker_info = endpoints .get ("sagemaker" )
377
+ if not sagemaker_info :
378
+ click .secho (" <no SageMaker endpoint information available>" , fg = "yellow" )
379
+ else :
380
+ ep_rows = [
381
+ ("State:" , data .get ("status" , {}).get ("endpoints" , {}).get ("sagemaker" , {}).get ("state" )),
382
+ ("Name:" , data .get ("sageMakerEndpoint" , {}).get ("name" )),
383
+ ("ARN:" , data .get ("status" , {}).get ("endpoints" , {}).get ("sagemaker" , {}).get ("endpointArn" )),
384
+ ]
385
+ click .echo (tabulate (ep_rows , tablefmt = "plain" ))
386
+
387
+ click .echo ("\n Conditions:" )
388
+ conds = data .get ("status" , {}).get ("conditions" , [])
389
+ if conds :
390
+ headers = ["TYPE" , "STATUS" , "LAST TRANSITION" , "LAST UPDATE" , "MESSAGE" ]
391
+ rows = [
392
+ [
393
+ c .get ("type" , "" ),
394
+ c .get ("status" , "" ),
395
+ c .get ("lastTransitionTime" , "" ),
396
+ c .get ("lastUpdateTime" , "" ),
397
+ c .get ("message" ) or ""
398
+ ]
399
+ for c in conds
400
+ ]
401
+ click .echo (tabulate (rows , headers = headers , tablefmt = "github" ))
402
+ else :
403
+ click .echo (" <none>" )
404
+
405
+ click .echo ("\n DeploymentStatus Conditions:" )
406
+ dep_status = data .get ("status" , {}).get ("deploymentStatus" , {})
407
+ dep_conds = dep_status .get ("status" , {}).get ("conditions" , [])
408
+ if dep_conds :
409
+ headers = ["TYPE" , "STATUS" , "LAST TRANSITION" , "LAST UPDATE" , "MESSAGE" ]
410
+ rows = [
411
+ [
412
+ c .get ("type" , "" ),
413
+ c .get ("status" , "" ),
414
+ c .get ("lastTransitionTime" , "" ),
415
+ c .get ("lastUpdateTime" , "" ),
416
+ c .get ("message" ) or ""
417
+ ]
418
+ for c in dep_conds
419
+ ]
420
+ click .echo (tabulate (rows , headers = headers , tablefmt = "github" ))
421
+ else :
422
+ click .echo (" <none>" )
181
423
182
424
183
425
@click .command ("hyp-jumpstart-endpoint" )
@@ -301,12 +543,12 @@ def custom_get_logs(
301
543
@click .command ("hyp-jumpstart-endpoint" )
302
544
@click .option (
303
545
"--since-hours" ,
304
- type = click .INT ,
546
+ type = click .FLOAT ,
305
547
required = True ,
306
548
help = "Required. The time frame to get logs for." ,
307
549
)
308
550
def js_get_operator_logs (
309
- since_hours : int ,
551
+ since_hours : float ,
310
552
):
311
553
"""
312
554
Get specific pod log for jumpstart model endpoint.
@@ -319,12 +561,12 @@ def js_get_operator_logs(
319
561
@click .command ("hyp-custom-endpoint" )
320
562
@click .option (
321
563
"--since-hours" ,
322
- type = click .INT ,
564
+ type = click .FLOAT ,
323
565
required = True ,
324
566
help = "Required. The time frame get logs for." ,
325
567
)
326
568
def custom_get_operator_logs (
327
- since_hours : int ,
569
+ since_hours : float ,
328
570
):
329
571
"""
330
572
Get specific pod log for custom model endpoint.
0 commit comments