idmtools-platform-container 0.0.0.dev0__py3-none-any.whl → 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. docker_image/BASE_VERSION +1 -0
  2. docker_image/Dockerfile +48 -0
  3. docker_image/Dockerfile_buildenv +46 -0
  4. docker_image/ImageName +1 -0
  5. docker_image/README.md +78 -0
  6. docker_image/__init__.py +6 -0
  7. docker_image/build_docker_image.py +145 -0
  8. docker_image/debian/BASE_VERSION +1 -0
  9. docker_image/debian/Dockerfile +40 -0
  10. docker_image/debian/ImageName +1 -0
  11. docker_image/debian/README.md +48 -0
  12. docker_image/debian/pip.conf +3 -0
  13. docker_image/debian/requirements.txt +1 -0
  14. docker_image/docker_image_history.py +101 -0
  15. docker_image/pip.conf +3 -0
  16. docker_image/push_docker_image.py +62 -0
  17. docker_image/requirements.txt +1 -0
  18. docker_image/rocky_meta_runtime.txt +37 -0
  19. idmtools_platform_container/__init__.py +18 -8
  20. idmtools_platform_container/cli/__init__.py +5 -0
  21. idmtools_platform_container/cli/container.py +682 -0
  22. idmtools_platform_container/container_operations/__init__.py +5 -0
  23. idmtools_platform_container/container_operations/docker_operations.py +593 -0
  24. idmtools_platform_container/container_platform.py +375 -0
  25. idmtools_platform_container/platform_operations/__init__.py +5 -0
  26. idmtools_platform_container/platform_operations/experiment_operations.py +112 -0
  27. idmtools_platform_container/platform_operations/simulation_operations.py +58 -0
  28. idmtools_platform_container/plugin_info.py +79 -0
  29. idmtools_platform_container/utils/__init__.py +5 -0
  30. idmtools_platform_container/utils/general.py +136 -0
  31. idmtools_platform_container/utils/status.py +130 -0
  32. idmtools_platform_container-0.0.2.dist-info/METADATA +212 -0
  33. idmtools_platform_container-0.0.2.dist-info/RECORD +69 -0
  34. idmtools_platform_container-0.0.2.dist-info/entry_points.txt +5 -0
  35. idmtools_platform_container-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
  36. {idmtools_platform_container-0.0.0.dev0.dist-info → idmtools_platform_container-0.0.2.dist-info}/top_level.txt +2 -0
  37. tests/inputs/Assets/MyLib/functions.py +2 -0
  38. tests/inputs/__init__.py +0 -0
  39. tests/inputs/model.py +28 -0
  40. tests/inputs/model1.py +31 -0
  41. tests/inputs/model3.py +21 -0
  42. tests/inputs/model_file.py +18 -0
  43. tests/inputs/run.sh +1 -0
  44. tests/inputs/sleep.py +9 -0
  45. tests/test_container_cli/__init__.py +0 -0
  46. tests/test_container_cli/helper.py +57 -0
  47. tests/test_container_cli/test_base.py +14 -0
  48. tests/test_container_cli/test_cancel.py +96 -0
  49. tests/test_container_cli/test_clear_results.py +54 -0
  50. tests/test_container_cli/test_container.py +72 -0
  51. tests/test_container_cli/test_file_container_cli.py +121 -0
  52. tests/test_container_cli/test_get_detail.py +60 -0
  53. tests/test_container_cli/test_history.py +136 -0
  54. tests/test_container_cli/test_history_count.py +53 -0
  55. tests/test_container_cli/test_inspect.py +53 -0
  56. tests/test_container_cli/test_install.py +48 -0
  57. tests/test_container_cli/test_is_running.py +69 -0
  58. tests/test_container_cli/test_jobs.py +138 -0
  59. tests/test_container_cli/test_list_containers.py +99 -0
  60. tests/test_container_cli/test_packages.py +41 -0
  61. tests/test_container_cli/test_path.py +96 -0
  62. tests/test_container_cli/test_ps.py +47 -0
  63. tests/test_container_cli/test_remove_container.py +78 -0
  64. tests/test_container_cli/test_status.py +149 -0
  65. tests/test_container_cli/test_stop_container.py +71 -0
  66. tests/test_container_cli/test_sync_history.py +98 -0
  67. tests/test_container_cli/test_verify_docker.py +28 -0
  68. tests/test_container_cli/test_volume.py +28 -0
  69. idmtools_platform_container-0.0.0.dev0.dist-info/METADATA +0 -41
  70. idmtools_platform_container-0.0.0.dev0.dist-info/RECORD +0 -5
  71. {idmtools_platform_container-0.0.0.dev0.dist-info → idmtools_platform_container-0.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1 @@
1
+ 0.0
@@ -0,0 +1,48 @@
1
+ # FROM docker-production.packages.idmod.org/dtk-rocky-buildenv:0.2-dev
2
+ # Replace the following lines with above line after the offical image is available
3
+ #############################################################
4
+ FROM rockylinux:9.2
5
+ # Set the timezone and the frontend
6
+ ENV TZ=UTC DEBIAN_FRONTEND=noninteractive
7
+ # To suppress warning without altering the installation when pip install with root user
8
+ ENV PIP_ROOT_USER_ACTION=ignore
9
+ # Install the necessary packages
10
+ RUN yum -y install rpm dnf-plugins-core \
11
+ && yum -y update \
12
+ && dnf -y install \
13
+ python3 \
14
+ python3-devel \
15
+ mpich \
16
+ snappy \
17
+ glibc-devel \
18
+ epel-release \
19
+ wget \
20
+ nano
21
+
22
+ # Update the system
23
+ RUN yum clean all
24
+
25
+ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # This is for setting up the timezone
26
+
27
+ # Install pip
28
+ RUN python3 -m pip install pip --upgrade
29
+ # Create a symbolic link to python3
30
+ RUN ln -s /usr/bin/python3 /usr/bin/python
31
+ # Create a directory for pip configurations
32
+ RUN mkdir /root/.pip
33
+ # Copy the pip configuration file
34
+ COPY pip.conf /root/.pip
35
+
36
+ # Set the path and library path
37
+ ENV PATH ${PATH}:/usr/lib64/mpich/bin
38
+ ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/usr/lib64/mpich/lib
39
+
40
+ # Add the requirements file
41
+ ADD requirements.txt /tmp/
42
+
43
+ # make the PIP index configurable so we can build against staging, production, or a local PyPI server
44
+ ARG CONTAINER_VERSION
45
+
46
+ # Install the packages
47
+ RUN bash -c "pip3 install -r /tmp/requirements.txt"
48
+
@@ -0,0 +1,46 @@
1
+ #FROM docker-production.packages.idmod.org/dtk-rocky-buildenv:0.2-dev
2
+ # Replace the following lines with above line after the offical image is available
3
+ #############################################################
4
+ FROM rockylinux:9.2
5
+ ENV TZ=UTC DEBIAN_FRONTEND=noninteractive
6
+ ENV GNUMAKEFLAGS=-j4
7
+
8
+ RUN yum -y install rpm dnf-plugins-core \
9
+ && yum -y update \
10
+ && dnf -y install \
11
+ python3 \
12
+ python3-devel \
13
+ snappy \
14
+ mpich \
15
+ sudo \
16
+ epel-release \
17
+ git \
18
+ wget \
19
+ nano
20
+
21
+ RUN yum -y update
22
+ RUN yum -y group install "Development Tools" \
23
+ && yum clean all
24
+
25
+ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # This is for setting up the timezone
26
+
27
+ RUN python3 -m pip install pip --upgrade
28
+ RUN ln -s /usr/bin/python3 /usr/bin/python
29
+ RUN mkdir /root/.pip
30
+ COPY pip.conf /root/.pip
31
+ # RUN dnf install -y R
32
+ ENV PATH ${PATH}:/usr/lib64/mpich/bin
33
+ ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/usr/lib64/mpich/lib
34
+
35
+ #############################################################
36
+ RUN dnf -y install dos2unix
37
+
38
+ # Add the requirements file
39
+ ADD requirements.txt /tmp/
40
+
41
+ # make the PIP index configurable so we can build against staging, production, or a local PyPI server
42
+ ARG CONTAINER_VERSION
43
+
44
+ # Install the packages
45
+ RUN bash -c "pip3 install -r /tmp/requirements.txt"
46
+
docker_image/ImageName ADDED
@@ -0,0 +1 @@
1
+ container-rocky-runtime
docker_image/README.md ADDED
@@ -0,0 +1,78 @@
1
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
2
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
3
+ **Table of Contents**
4
+
5
+ - [idmtools_platform_container Docker image](#idmtools_platform_container-docker-image)
6
+ - [Introduction](#introduction)
7
+ - [Prerequisites](#prerequisites)
8
+ - [Build Docker image](#build-docker-image)
9
+ - [Docker image versioning](#docker-image-versioning)
10
+ - [Docker image usage](#docker-image-usage)
11
+ - [Publish Docker image](#publish-docker-image)
12
+ - [Extend the Docker image](#extend-the-docker-image)
13
+
14
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
15
+
16
+ # idmtools_platform_container Docker image
17
+
18
+ **Note**: This document is primarily for developers. It is not necessary for users to build and push the Docker image. However, if you wish to use your own Docker image, please follow the instructions below at [Extend the Docker Image](#extend-the-docker-image).
19
+
20
+ ## Introduction
21
+ This Docker image is designed to facilitate idmtools_platform_container. It serves as local running platform with all necessary tools and dependencies installed. The image is based on rockylinux 9.2 and includes the following tools:
22
+ - python 3.9
23
+ - mipch 4.1.1
24
+ - emod-api 1.33.3
25
+ - emod-api's dependencies like numpy, pandas, scipy, matplotlib etc.
26
+
27
+ ## Prerequisites
28
+ - Docker
29
+ On Windows or Mac, please use Docker Desktop 2.1.0.5 or 2.2.0.1
30
+
31
+ ## Build Docker image
32
+ Note, you do not need to build the image locally. The image is auto built in github action and pushed to idmod artifactory.
33
+
34
+ To build Docker image locally, run:
35
+ ```bash
36
+ python build_docker_image.py --username <username> --password <password>
37
+ ```
38
+ where `<username>` and `<password>` are the username and password for the idmod artifactory account.
39
+
40
+ You can also build the image with different docker file and image name by specifying `--dockerfile` and `--image_name` arguments.
41
+ ```bash
42
+ python build_docker_image.py --username <username> --password <password> --dockerfile Dockerfile_buildenv --image_name container-rocky-buildenv
43
+ ```
44
+ which will build image name as 'idm-docker-staging.packages.idmod.org/idmtools/container-rocky-buildenv:x.x.x'
45
+
46
+ ## Docker image versioning
47
+ The Docker image version is determined by the version in idm docker-staging artifactory. It will advance the version number by 0.0.1 for each new build.
48
+
49
+ ## Docker image usage
50
+ By default, you DO NOT need to worry about the image build and how to use image. The image is auto built in github action and pushed to idmod artifactory. The image is used in idmtools_platform_container Platform object. For example,
51
+ ```python
52
+ from idmtools.core.platform_factory import Platform
53
+ platform = Platform('CONTAINER', job_directory='any_dir', docker_image='idm-docker-public.packages.idmod.org/idmtools/container-rocky-runtime:x.x.x')
54
+ ```
55
+ where docker_image can be your local built image or the image in idmod artifactory.
56
+ If you do not provide docker_image, the default image will be used.
57
+
58
+ ## Publish Docker image
59
+ Note, you do not need to push docker image to artifactory. The image is auto built in github action and pushed to idmod artifactory.
60
+ If you want to push the image to artifactory, run:
61
+ ```bash
62
+ python push_docker_image.py --username <username> --password <password>
63
+ ```
64
+ where `<username>` and `<password>` are the username and password for the idmod artifactory account.
65
+
66
+ ## Extend the Docker image
67
+ If you want to build you own Docker image, please use our ``container-rocky-runtime`` as your baseline image and add the following line to the top of your Dockerfile:
68
+
69
+ ```bash
70
+ FROM docker-production-public/idmtools/container-rocky-runtime/0.0.3
71
+ ```
72
+ You can use general Docker build [command](https://docs.docker.com/reference/cli/docker/buildx/build/) to build your own Docker image.
73
+ Then use that image in the Platform object. For example:
74
+
75
+ ```bash
76
+ from idmtools_platform_container import Platform
77
+ platform = Platform('CONTAINER', job_directory='any_dir', docker_image='your_own_image_name:x.x.x')
78
+ ```
@@ -0,0 +1,6 @@
1
+ """idmtools comps platform.
2
+
3
+ Build docker image.
4
+
5
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
6
+ """
@@ -0,0 +1,145 @@
1
+ """This script is used to build a docker image for the idmtools_platform_container.
2
+
3
+ Copyright 2024, Bill Gates Foundation. All rights reserved.
4
+ """
5
+ import argparse
6
+ import os
7
+ import subprocess
8
+ import sys
9
+ import requests
10
+ import keyring
11
+ from logging import getLogger, basicConfig, DEBUG, INFO
12
+ from getpass import getpass
13
+ from requests.auth import HTTPBasicAuth
14
+ from natsort import natsorted
15
+
16
+
17
+ logger = getLogger(__name__)
18
+ # Global Configurations
19
+ KEYRING_NAME = "idmtools_container_docker_builder"
20
+ BASE_REPO = 'packages.idmod.org'
21
+ REPO_KEY = 'idm-docker-staging'
22
+ DOCKER_REPO = f'{REPO_KEY}.{BASE_REPO}'
23
+ BASE_IMAGE_NAME = f'{DOCKER_REPO}/idmtools'
24
+ current_working_directory = os.getcwd()
25
+ BASE_VERSION = open(os.path.join(current_working_directory, 'BASE_VERSION')).read().strip()
26
+
27
+ logger.info("Please be sure you are logged into the docker-production.packages.idmod.org Docker Repo")
28
+
29
+
30
+ def get_username_and_password(disable_keyring_load=False, disable_keyring_save=False):
31
+ """
32
+ Try to get username.
33
+
34
+ It first attempts loading from environment vars, then keyring if not disabled, then lastly prompts.
35
+
36
+ Args:
37
+ disable_keyring_load: Disable loading credentials from keyring
38
+ disable_keyring_save: Disable keyring save
39
+
40
+ Returns:
41
+ Username password
42
+ """
43
+ if 'PYPI_STAGING_USERNAME' in os.environ:
44
+ logger.info("Loading Credentials from environment")
45
+ if 'PYPI_STAGING_PASSWORD' not in os.environ:
46
+ logger.error("When specifying username from environment variable, you must also specify password")
47
+ sys.exit(-1)
48
+ username = os.environ['PYPI_STAGING_USERNAME']
49
+ password = os.environ['PYPI_STAGING_PASSWORD']
50
+ elif not disable_keyring_load and keyring.get_credential(KEYRING_NAME, "username"):
51
+ username = keyring.get_password(KEYRING_NAME, "username")
52
+ password = keyring.get_password(KEYRING_NAME, "password")
53
+ else:
54
+ username = input('Username:')
55
+ password = getpass(prompt='Password:')
56
+ if not disable_keyring_save:
57
+ logger.info("Saving Credentials")
58
+ keyring.set_password(KEYRING_NAME, "username", username)
59
+ keyring.set_password(KEYRING_NAME, "password", password)
60
+ return username, password
61
+
62
+
63
+ def get_latest_image_version_from_registry(username, password, image_name):
64
+ """
65
+ Fetch the latest image version from repo.
66
+ Args:
67
+ username: Username to use with registry
68
+ password: Password to use with registry
69
+ image_name: Docker image name to use for building image
70
+ Returns:
71
+ Latest version published in the registry
72
+ """
73
+ url = f'https://{BASE_REPO}/artifactory/api/docker/{REPO_KEY}/v2/idmtools/{image_name}/tags/list'
74
+ auth = HTTPBasicAuth(username=username, password=password)
75
+ logger.info(f"Loading Credentials from {url}")
76
+ response = requests.get(url, auth=auth)
77
+ logger.debug(f"Return Code: {response.status_code}")
78
+ if response.status_code != 200 and response.status_code != 404:
79
+ print(response.status_code)
80
+ print(response.content)
81
+ raise Exception('Could not load images')
82
+ elif response.status_code == 404:
83
+ logger.info(f"First Version {url}")
84
+ return f'{BASE_VERSION}.0'
85
+ else:
86
+ images = natsorted(response.json()['tags'], reverse=True)
87
+ images = [i for i in images if len(i) >= 5]
88
+ logger.debug(f"Images: {images}")
89
+ last_version = images[0]
90
+ logger.info(f"Last Version {url}")
91
+ version_parts = last_version.split('.')
92
+ base_part = '.'.join(version_parts[:-1])
93
+ if BASE_VERSION in base_part:
94
+ version_parts[-1] = str(int(version_parts[-1]) + 1)
95
+ version = '.'.join(version_parts)
96
+ else:
97
+ version = f'{BASE_VERSION}.0'
98
+ logger.info(f"Next Version: {version}")
99
+ return version
100
+
101
+
102
+ def build_image(username, password, dockerfile, image_name, disable_keyring_load, disable_keyring_save):
103
+ """
104
+ Run the docker build command.
105
+
106
+ Args:
107
+ username: Username to use with registry
108
+ password: Password to use with registry
109
+ dockerfile: Dockerfile to use for building image
110
+ image_name: Docker image name to use for building image
111
+ disable_keyring_load: Disable keyring which caches passwords
112
+ disable_keyring_save: Disable caching password to the keyring
113
+
114
+ Returns:
115
+ None
116
+ """
117
+ if username is None or password is None:
118
+ username, password = get_username_and_password(disable_keyring_load, disable_keyring_save)
119
+ version = get_latest_image_version_from_registry(username, password, image_name)
120
+ cmd = ['docker', 'build', '--network=host', '--build-arg', f'CONTAINER_VERSION={version}', '--tag',
121
+ f'{BASE_IMAGE_NAME}/{image_name}:{version}', '-f', dockerfile, '.']
122
+ logger.info(f'Running: {" ".join(cmd)}')
123
+ p = subprocess.Popen(" ".join(cmd), cwd=current_working_directory, shell=True)
124
+ p.wait()
125
+
126
+ if p.returncode == 0:
127
+ logger.info("Tagging image")
128
+ os.system(f'docker tag {BASE_IMAGE_NAME}/{image_name}:{version} {BASE_IMAGE_NAME}/{image_name}:{version[:-2]}')
129
+ sys.exit(p.returncode)
130
+
131
+
132
+ if __name__ == "__main__":
133
+ parser = argparse.ArgumentParser("Build Container Image")
134
+ parser.add_argument("--username", default=None, help="Docker Production Username")
135
+ parser.add_argument("--password", default=None, help="Docker Production Password")
136
+ parser.add_argument("--dockerfile", default="Dockerfile", help="Dockerfile to use for building image")
137
+ parser.add_argument("--image_name", default="container-rocky-runtime", help="image name to use for building image")
138
+ parser.add_argument("--disable-keyring-load", default=False, help="Disable loading password from keyring")
139
+ parser.add_argument("--disable-keyring-save", default=False, help="Disable saving password to keyring after user prompts")
140
+ parser.add_argument("--verbose", default=False, help="Enable Debug logging")
141
+ parser.add_argument("--debug", default=False, help="Enable Debug logging")
142
+ args = parser.parse_args()
143
+
144
+ basicConfig(filename="build.log", level=DEBUG if any([args.verbose, args.debug]) else INFO)
145
+ build_image(args.username, args.password, args.dockerfile, args.image_name, args.disable_keyring_load, args.disable_keyring_save)
@@ -0,0 +1 @@
1
+ 0.0
@@ -0,0 +1,40 @@
1
+ FROM debian:12.6
2
+ ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
3
+
4
+ RUN set -x && \
5
+ apt-get update --fix-missing && \
6
+ apt-get install -y --no-install-recommends \
7
+ python3 \
8
+ python3-pip \
9
+ python3-dev \
10
+ python3-venv \
11
+ mpich \
12
+ wget \
13
+ nano \
14
+ && apt-get clean \
15
+ && rm -rf /var/lib/apt/lists/*
16
+
17
+ # Update the system
18
+ RUN apt-get clean
19
+
20
+ RUN mkdir /root/.pip
21
+ # Copy the pip configuration file
22
+ COPY pip.conf /root/.pip
23
+
24
+ # Set up a virtual environment
25
+ RUN python3 -m venv /pyenv
26
+ ENV PATH="/pyenv/bin:$PATH"
27
+
28
+ RUN pip3 install --upgrade pip setuptools
29
+ # Add the requirements file
30
+ ADD requirements.txt /tmp/
31
+ # Install the packages
32
+ RUN pip3 install -r /tmp/requirements.txt
33
+
34
+ RUN ln -s /usr/bin/python3 /usr/bin/python
35
+
36
+ ARG CONTAINER_VERSION
37
+
38
+ ENV LD_LIBRARY_PATH /usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}
39
+
40
+
@@ -0,0 +1 @@
1
+ container-debian-runtime
@@ -0,0 +1,48 @@
1
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
2
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
3
+ **Table of Contents**
4
+
5
+ - [Debian12 Docker Image](#debian12-docker-image)
6
+ - [Introduction](#introduction)
7
+ - [Prerequisites](#prerequisites)
8
+ - [Build Docker Image locally](#build-docker-image-locally)
9
+ - [Use docker image in idmtools](#use-docker-image-in-idmtools)
10
+ - [Build and Publish Debian Docker Image in GitHub Actions](#build-and-publish-debian-docker-image-in-github-actions)
11
+
12
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
13
+
14
+ # Debian12 Docker Image
15
+
16
+ ## Introduction
17
+ This Docker image is designed to facilitate idmtools_platform_container. It serves as local running platform with all necessary tools and dependencies installed.
18
+
19
+ The image built from this Dockerfile is based on debian:12 docker image and includes the following packages and utilities:
20
+ - python 3.11
21
+ - mipch 4.0.2
22
+ - emod-api 2.0.1
23
+
24
+ ## Prerequisites
25
+ - Docker
26
+
27
+ ## Build Docker Image locally
28
+ ```bash
29
+ docker build -t debian12-env:0.0.1 .
30
+ ```
31
+
32
+ ## Use docker image in idmtools
33
+ ```python
34
+ from idmtools.core.platform_factory import Platform
35
+ platform = Platform('CONTAINER', docker_image='debian12-env:0.0.1')
36
+ ```
37
+ Note, here `debian12-env:0.0.1` is the image name you built in the previous step.
38
+
39
+ If your script needs extra python packages, you can install with extra_packages argument in Platform at runtime:
40
+ ```python
41
+ from idmtools.core.platform_factory import Platform
42
+ platform = Platform('CONTAINER', docker_image='debian12-env', extra_packages=['emodpy~=2.0.0', 'pytest'])
43
+
44
+ # or use idmtools cli command to install before run script: idmtools container install <package>
45
+ ```
46
+
47
+ ## Build and Publish Debian Docker Image in GitHub Actions
48
+ You can build and publish the docker image to idmod artifactory using GitHub Actions. The script is located at `.github/workflows/build_debian_image.yml`.
@@ -0,0 +1,3 @@
1
+ [global]
2
+ index-url = https://packages.idmod.org/api/pypi/pypi-production/simple
3
+ extra-index-url = https://packages.idmod.org/api/pypi/pypi-production/simple
@@ -0,0 +1 @@
1
+ emod-api~=2.0.1
@@ -0,0 +1,101 @@
1
+ """This script fetches the history of a Docker image and prints it in a tabular format."""
2
+ import argparse
3
+ import re
4
+ import shutil
5
+ import subprocess
6
+ import pandas as pd
7
+ from tabulate import tabulate
8
+
9
+
10
+ def parse_size(size_str):
11
+ """
12
+ Parse the size string from Docker and convert to bytes.
13
+ Args:
14
+ size_str:
15
+
16
+ Returns:
17
+ Size in bytes
18
+ """
19
+ """Parse the size string from Docker and convert to bytes."""
20
+ units = {'B': 1, 'KB': 1024, 'MB': 1024**2, 'GB': 1024**3}
21
+ size_str = size_str.upper().replace(" ", "")
22
+ num, unit = re.findall(r'([0-9.]+)([A-Z]+)', size_str)[0]
23
+ return float(num) * units.get(unit, 1)
24
+
25
+
26
+ def format_size(size_in_bytes):
27
+ """
28
+ Convert a size in bytes to a human-readable string of the most appropriate unit.
29
+ Args:
30
+ size_in_bytes:
31
+
32
+ Returns:
33
+ Size in human-readable format
34
+ """
35
+ if size_in_bytes < 1024:
36
+ return f"{size_in_bytes} B" # Bytes
37
+ elif size_in_bytes < 1024**2:
38
+ return f"{size_in_bytes / 1024:.2f} KB" # Kilobytes
39
+ elif size_in_bytes < 1024**3:
40
+ return f"{size_in_bytes / 1024**2:.2f} MB" # Megabytes
41
+ elif size_in_bytes < 1024**4:
42
+ return f"{size_in_bytes / 1024**3:.2f} GB" # Gigabytes
43
+ else:
44
+ return f"{size_in_bytes / 1024**4:.2f} TB" # Terabytes
45
+
46
+
47
+ def get_docker_image_history(image_id_or_name):
48
+ """
49
+ Fetch the history of a Docker image.
50
+ Args:
51
+ image_id_or_name:
52
+
53
+ Returns:
54
+ df
55
+ """
56
+ result = subprocess.run(
57
+ ['docker', 'history', '--no-trunc', image_id_or_name, '--format', '{{.ID}}|{{.CreatedBy}}|{{.Size}}'],
58
+ capture_output=True,
59
+ text=True,
60
+ encoding='utf-8'
61
+ )
62
+ if result.returncode != 0:
63
+ print("Error fetching Docker image history")
64
+ return None
65
+
66
+ history_lines = result.stdout.strip().split('\n')
67
+ data = [line.split('|') for line in history_lines]
68
+ for i, line in enumerate(data):
69
+ if len(line) == 4:
70
+ data[i] = [line[0], line[1] + " " + line[2], line[3]]
71
+ df = pd.DataFrame(data, columns=['LAYER ID', 'COMMAND', 'SIZE'])
72
+ df = df.iloc[:, -2:]
73
+ return df
74
+
75
+
76
+ def main(image_id):
77
+ """
78
+ This script fetches the history of a Docker image and prints it in a tabular format.
79
+ Returns:
80
+ None
81
+ """
82
+ df = get_docker_image_history(image_id)
83
+ total_size = sum(parse_size(size) for size in df['SIZE'])
84
+ size = format_size(total_size)
85
+ if df is not None:
86
+ terminal_width = shutil.get_terminal_size().columns
87
+ max_command_width = terminal_width - 10
88
+ table = tabulate(df, headers='keys', tablefmt='fancy_grid', showindex=False,
89
+ maxcolwidths=[None, max_command_width, None])
90
+ print(table)
91
+ with open('rocky_meta_runtime.txt', 'w', encoding='utf-8') as outputfile:
92
+ outputfile.write(f"Total size: {size}\n\n")
93
+ outputfile.write(table)
94
+
95
+
96
+ if __name__ == "__main__":
97
+ if __name__ == "__main__":
98
+ parser = argparse.ArgumentParser("Get Image Build History")
99
+ parser.add_argument("--image_id", default="10bed3221522", help="Docker image id")
100
+ args = parser.parse_args()
101
+ main(args.image_id)
docker_image/pip.conf ADDED
@@ -0,0 +1,3 @@
1
+ [global]
2
+ index-url = https://packages.idmod.org/api/pypi/pypi-production/simple
3
+ extra-index-url = https://pypi.org/simple
@@ -0,0 +1,62 @@
1
+ """This is the script to push docker image to idm staging artifactory.
2
+
3
+ Copyright 2024, Bill Gates Foundation. All rights reserved.
4
+ """
5
+ import argparse
6
+ import os
7
+ import subprocess
8
+ import sys
9
+ from logging import getLogger, basicConfig, DEBUG, INFO
10
+ current_directory = os.path.dirname(os.path.realpath(__file__))
11
+ sys.path.append(os.path.join(current_directory))
12
+ from build_docker_image import get_username_and_password, get_latest_image_version_from_registry # noqa: E402
13
+
14
+ current_working_directory = os.getcwd()
15
+ BASE_VERSION = open(os.path.join(current_working_directory, 'BASE_VERSION')).read().strip()
16
+ BASE_REPO = 'packages.idmod.org'
17
+ REPO_KEY = 'idm-docker-staging'
18
+ DOCKER_REPO = f'{REPO_KEY}.{BASE_REPO}'
19
+ BASE_IMAGE_NAME = f'{DOCKER_REPO}/idmtools'
20
+
21
+ logger = getLogger(__name__)
22
+
23
+
24
+ def push_image(username, password, dockerfile, image_name, disable_keyring_load, disable_keyring_save):
25
+ """
26
+ Push docker image to idm staging artifactory.
27
+
28
+ Args:
29
+ username: Username to use with registry
30
+ password: Password to use with registry
31
+ dockerfile: Dockerfile to use for building image
32
+ image_name: Docker image name to use for building image
33
+ disable_keyring_load: Disable keyring which caches passwords
34
+ disable_keyring_save: Disable caching password to the keyring
35
+
36
+ Returns:
37
+ None
38
+ """
39
+ if username is None or password is None:
40
+ username, password = get_username_and_password(disable_keyring_load, disable_keyring_save)
41
+ version = get_latest_image_version_from_registry(username, password, image_name)
42
+ cmd = ['docker', 'push', f'{BASE_IMAGE_NAME}/{image_name}:{version}']
43
+ print(f'Running: {" ".join(cmd)}')
44
+ p = subprocess.Popen(" ".join(cmd), cwd=current_working_directory, shell=True)
45
+ p.wait()
46
+ sys.exit(p.returncode)
47
+
48
+
49
+ if __name__ == "__main__":
50
+ parser = argparse.ArgumentParser("Publish Container Image to Artifactory")
51
+ parser.add_argument("--username", default=None, help="Docker Staging Username")
52
+ parser.add_argument("--password", default=None, help="Docker Staging Password")
53
+ parser.add_argument("--dockerfile", default="Dockerfile", help="Dockerfile to use for building image")
54
+ parser.add_argument("--image_name", default="container-rocky-runtime", help="image name to use for building image")
55
+ parser.add_argument("--disable-keyring-load", default=False, help="Disable loading password from keyring")
56
+ parser.add_argument("--disable-keyring-save", default=False, help="Disable saving password to keyring after user prompts")
57
+ parser.add_argument("--verbose", default=False, help="Enable Debug logging")
58
+ parser.add_argument("--debug", default=False, help="Enable Debug logging")
59
+ args = parser.parse_args()
60
+
61
+ basicConfig(filename="build.log", level=DEBUG if any([args.verbose, args.debug]) else INFO)
62
+ push_image(args.username, args.password, args.dockerfile, args.image_name, args.disable_keyring_load, args.disable_keyring_save)
@@ -0,0 +1 @@
1
+ emod-api~=1.30