def install(image_name): """Method to install the Gigantum Image Args: image_name(str): Image name, including repository and namespace (e.g. gigantum/labmanager) """ # Make sure user is not root if is_running_as_admin(): raise ExitCLI("Do not run `gigantum install` as root.") docker = DockerInterface() try: try: # Check to see if the image has already been pulled docker.client.images.get(image_name) raise ExitCLI( "** Application already installed. Run `gigantum update` instead." ) except ImageNotFound: # Pull for the first time print( "\nDownloading and installing the Gigantum Docker Image. Please wait...\n" ) image = docker.client.images.pull(image_name, 'latest') except APIError: msg = "ERROR: failed to pull image!" msg += "\n- Are you signed into DockerHub?" msg += "\n- Do you have access to {}? If not, contact Gigantum.".format( image_name) msg += "\n - Can test by going here: https://hub.docker.com/r/gigantum/labmanager/" msg += "\n - If you see `404 Not Found`, request access from Gigantum\n" raise ExitCLI(msg) short_id = image.short_id.split(':')[1] print("\nSuccessfully pulled {}:{}\n".format(image_name, short_id))
def update(image_name, tag=None): """Method to update the existing image, warning about changes before accepting Args: image_name(str): Image name, including repository and namespace (e.g. gigantum/labmanager) tag(str): Tag to pull if you wish to override `latest` Returns: None """ # Make sure user is not root if is_running_as_admin(): raise ExitCLI("Do not run `gigantum update` as root.") docker = DockerInterface() try: cl = ChangeLog() if "edge" not in image_name: # Normal install, so do checks if not tag: # Trying to update to the latest version tag = 'latest' # Get id of current labmanager install try: current_image = docker.client.images.get( "{}:latest".format(image_name)) except ImageNotFound: raise ExitCLI( "Gigantum Image not yet installed. Run 'gigantum install' first." ) short_id = current_image.short_id.split(':')[1] # Check if there is an update available if not cl.is_update_available(short_id): print("Latest version already installed.") sys.exit(0) # Get Changelog info for the latest or specified version try: print(cl.get_changelog(tag)) except ValueError as err: raise ExitCLI(err) else: # Edge build, set tag if needed if not tag: # Trying to update to the latest version tag = 'latest' # Make sure user wants to pull if ask_question("Are you sure you want to update?"): # Pull print( "\nDownloading and installing the Gigantum Docker Image. Please wait...\n" ) image = docker.client.images.pull(image_name, tag) # If pulling not truly latest, force to latest if tag != 'latest': print("Tagging explicit version {} with latest".format(tag)) docker.client.api.tag('{}:{}'.format(tag, image_name), image_name, 'latest') else: raise ExitCLI("Update cancelled") except APIError: msg = "ERROR: failed to pull image!" msg += "\n- Are you signed into DockerHub?" msg += "\n- Do you have access to {}? If not, contact Gigantum.".format( image_name) msg += "\n - Can test by going here: https://hub.docker.com/r/gigantum/labmanager/" msg += "\n - If you see `404 Not Found`, request access\n" raise ExitCLI(msg) short_id = image.short_id.split(':')[1] print("\nSuccessfully pulled {}:{}\n".format(short_id, image_name))
def start(image_name, tag=None): """Method to start the application Args: tag(str): Tag to run, defaults to latest image_name(str): Image name, including repository and namespace (e.g. gigantum/labmanager) Returns: None """ print("Verifying Docker is available...") # Check if Docker is running docker = DockerInterface() if not tag: # Trying to update to the latest version tag = 'latest' # Make sure user is not root if is_running_as_admin(): raise ExitCLI("Do not run `gigantum start` as root.") # Check if working dir exists working_dir = os.path.join(os.path.expanduser("~"), "gigantum") if not os.path.exists(working_dir): os.makedirs(working_dir) # Check if application has been installed try: docker.client.images.get("{}:{}".format(image_name, tag)) except ImageNotFound: raise ExitCLI( "Application not found. Did you run `gigantum install` yet?") # Check to see if already running try: if _check_for_api(launch_browser=False, timeout=1): print("Application already running on http://localhost:10000") _check_for_api(launch_browser=True) raise ExitCLI( "If app does not load in your browser, run `gigantum stop` and then `gigantum start`" ) # Check to see if the container already exists old_container = docker.client.containers.get( image_name.replace("/", "-")) # if here it does, so for now remove the old container so you can relaunch old_container.stop() old_container.remove() # Do a container prune to make sure things are cleaned up docker.client.containers.prune() except NotFound: # If here, the API isn't running and an older container isn't lingering, so just move along. pass # Start port_mapping = {'10000/tcp': 10000} # Make sure the container-container share volume exists if not docker.share_volume_exists(): docker.create_share_volume() volume_mapping = { docker.share_vol_name: { 'bind': '/mnt/share', 'mode': 'rw' } } if platform.system() == 'Windows': # windows docker has the following eccentricities # no user ids, WINDOWS_HOST env var, /C/a/b/ format for volume C:\\a\\b environment_mapping = { 'HOST_WORK_DIR': docker.dockerize_volume_path(working_dir), 'WINDOWS_HOST': 1 } volume_mapping[docker.dockerize_volume_path(working_dir)] = { 'bind': '/mnt/gigantum', 'mode': 'rw' } elif platform.system() == 'Darwin': # For macOS, use the cached mode for improved performance environment_mapping = { 'HOST_WORK_DIR': working_dir, 'LOCAL_USER_ID': os.getuid() } volume_mapping[working_dir] = { 'bind': '/mnt/gigantum', 'mode': 'cached' } else: # For anything else, just use default mode. environment_mapping = { 'HOST_WORK_DIR': working_dir, 'LOCAL_USER_ID': os.getuid() } volume_mapping[working_dir] = {'bind': '/mnt/gigantum', 'mode': 'rw'} volume_mapping['/var/run/docker.sock'] = { 'bind': '/var/run/docker.sock', 'mode': 'rw' } container = docker.client.containers.run(image="{}:{}".format( image_name, tag), detach=True, name=image_name.replace("/", "."), init=True, ports=port_mapping, volumes=volume_mapping, environment=environment_mapping) print("Starting, please wait...") time.sleep(1) # Make sure volumes have mounted properly, by checking for the log file for up to 30 seconds success = False for _ in range(30): if os.path.exists( os.path.join(working_dir, '.labmanager', 'logs', 'labmanager.log')): success = True break # Sleep for 1 sec and increment counter time.sleep(1) if not success: msg = "\n\nWorking directory failed to mount! Have you granted Docker access to your user directory?" msg = msg + " \nIn both Docker for Mac and Docker for Windows this should be shared by default, but may require" msg = msg + " a confirmation from the user." msg = msg + "\n\nRun `gigantum stop`, verify your OS and Docker versions are supported, the allowed Docker" msg = msg + " volume share locations include `{}`, and try again.".format( working_dir) msg = msg + "\n\nIf this problem persists, contact support." # Stop and remove the container container.stop() container.remove() raise ExitCLI(msg) # Wait for API to be live before opening the user's browser if not _check_for_api(launch_browser=True, timeout=15): msg = "\n\nGigantum client failed to start! Try restarting Docker and then start again." # Stop and remove the container container.stop() container.remove() raise ExitCLI(msg)