@@ -173,6 +173,20 @@ def remove_image(image):
173
173
run_command ('grub-set-default --boot-directory=' + HOST_PATH + ' 0' )
174
174
click .echo ('Image removed' )
175
175
176
+ # TODO: Embed tag name info into docker image meta data at build time,
177
+ # and extract tag name from docker image file.
178
+ def get_docker_tag_name (image ):
179
+ # Try to get tag name from label metadata
180
+ cmd = "docker inspect --format '{{.ContainerConfig.Labels.Tag}}' " + image
181
+ proc = subprocess .Popen (cmd , stdout = subprocess .PIPE , shell = True )
182
+ (out , err ) = proc .communicate ()
183
+ if proc .returncode != 0 :
184
+ return "unknown"
185
+ tag = out .rstrip ()
186
+ if tag == "<no value>" :
187
+ return "unknown"
188
+ return tag
189
+
176
190
# Callback for confirmation prompt. Aborts if user enters "n"
177
191
def abort_if_false (ctx , param , value ):
178
192
if not value :
@@ -343,5 +357,92 @@ def cleanup():
343
357
if image_removed == 0 :
344
358
click .echo ("No image(s) to remove" )
345
359
360
+ # Upgrade docker image
361
+ @cli .command ()
362
+ @click .option ('-y' , '--yes' , is_flag = True , callback = abort_if_false ,
363
+ expose_value = False , prompt = 'New docker image will be installed, continue?' )
364
+ @click .option ('--cleanup_image' , is_flag = True , help = "Clean up old docker image" )
365
+ @click .option ('--enforce_check' , is_flag = True , help = "Enforce pending task check for docker upgrade" )
366
+ @click .option ('--tag' , type = str , help = "Tag for the new docker image" )
367
+ @click .argument ('container_name' , metavar = '<container_name>' , required = True ,
368
+ type = click .Choice (["swss" , "snmp" , "lldp" , "bgp" , "pmon" , "dhcp_relay" , "telemetry" , "teamd" ]))
369
+ @click .argument ('url' )
370
+ def upgrade_docker (container_name , url , cleanup_image , enforce_check , tag ):
371
+ """ Upgrade docker image from local binary or URL"""
372
+
373
+ # example image: docker-lldp-sv2:latest
374
+ cmd = "docker inspect --format '{{.Config.Image}}' " + container_name
375
+ proc = subprocess .Popen (cmd , stdout = subprocess .PIPE , shell = True )
376
+ (out , err ) = proc .communicate ()
377
+ if proc .returncode != 0 :
378
+ sys .exit (proc .returncode )
379
+ image_latest = out .rstrip ()
380
+
381
+ # example image_name: docker-lldp-sv2
382
+ cmd = "echo " + image_latest + " | cut -d ':' -f 1"
383
+ proc = subprocess .Popen (cmd , stdout = subprocess .PIPE , shell = True )
384
+ image_name = proc .stdout .read ().rstrip ()
385
+
386
+ DEFAULT_IMAGE_PATH = os .path .join ("/tmp/" , image_name )
387
+ if url .startswith ('http://' ) or url .startswith ('https://' ):
388
+ click .echo ('Downloading image...' )
389
+ try :
390
+ urllib .urlretrieve (url , DEFAULT_IMAGE_PATH , reporthook )
391
+ except Exception , e :
392
+ click .echo ("Download error" , e )
393
+ return
394
+ image_path = DEFAULT_IMAGE_PATH
395
+ else :
396
+ image_path = os .path .join ("./" , url )
397
+
398
+ # make sure orchagent is in clean state if swss is to be upgraded
399
+ if container_name == "swss" :
400
+ skipPendingTaskCheck = " -s"
401
+ if enforce_check :
402
+ skipPendingTaskCheck = ""
403
+
404
+ cmd = "docker exec -it " + container_name + " orchagent_restart_check" + skipPendingTaskCheck
405
+ proc = subprocess .Popen (cmd , stdout = subprocess .PIPE , shell = True )
406
+ (out , err ) = proc .communicate ()
407
+ if proc .returncode != 0 :
408
+ if enforce_check :
409
+ click .echo ("Orchagent is not in clean state, check syslog and try later" )
410
+ sys .exit (proc .returncode )
411
+ else :
412
+ click .echo ("Orchagent is not in clean state, upgrading it anyway" )
413
+ else :
414
+ click .echo ("Orchagent is in clean state and frozen for warm upgrade" )
415
+
416
+ run_command ("systemctl stop %s" % container_name )
417
+ run_command ("docker rm %s " % container_name )
418
+ run_command ("docker rmi %s " % image_latest )
419
+ run_command ("docker load < %s" % image_path )
420
+ if tag == None :
421
+ # example image: docker-lldp-sv2:latest
422
+ tag = get_docker_tag_name (image_latest )
423
+ run_command ("docker tag %s:latest %s:%s" % (image_name , image_name , tag ))
424
+ run_command ("systemctl restart %s" % container_name )
425
+
426
+ # Clean up old docker images
427
+ if cleanup_image :
428
+ # All images id under the image name
429
+ cmd = "docker images --format '{{.ID}}' " + image_name
430
+ proc = subprocess .Popen (cmd , stdout = subprocess .PIPE , shell = True )
431
+ image_id_all = proc .stdout .read ()
432
+ image_id_all = image_id_all .splitlines ()
433
+ image_id_all = set (image_id_all )
434
+
435
+ # this is image_id for image with "latest" tag
436
+ cmd = "docker images --format '{{.ID}}' " + image_latest
437
+ proc = subprocess .Popen (cmd , stdout = subprocess .PIPE , shell = True )
438
+ image_id_latest = proc .stdout .read ().rstrip ()
439
+
440
+ for id in image_id_all :
441
+ if id != image_id_latest :
442
+ run_command ("docker rmi -f %s" % id )
443
+
444
+ run_command ("sleep 5" ) # wait 5 seconds for application to sync
445
+ click .echo ('Done' )
446
+
346
447
if __name__ == '__main__' :
347
448
cli ()
0 commit comments