1
- import boto3
2
- import docker
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+ """Utility function to capture local environment"""
3
14
import logging
4
15
import subprocess
5
16
import sys
6
17
from typing import Optional
18
+
19
+ import boto3
20
+ import docker
7
21
import yaml
8
22
9
23
logger = logging .getLogger (__name__ )
@@ -66,38 +80,41 @@ def capture_local_environment(
66
80
"""
67
81
Capture all dependency packages installed in the local environment and build a docker image.
68
82
When using this utility method, the docker daemon must be active in the environment.
69
- Please note that this is an experimental feature. This utility function is not be able to detect the package
70
- compatability between platforms. It is also not able to detect dependency conflicts between the local environment
71
- and the additional dependencies.
83
+ Please note that this is an experimental feature. This utility function is not be able to
84
+ detect the package compatability between platforms. It is also not able to detect dependency
85
+ conflicts between the local environment and the additional dependencies.
72
86
73
87
Args:
74
88
image_name (str): The name of the docker image.
75
- env_name (str): The name of the virtual environment to be activated in the image, defaults to "saved_local_env".
89
+ env_name (str): The name of the virtual environment to be activated in the image,
90
+ defaults to "saved_local_env".
76
91
package_manager (str): The package manager, must be one of "conda" or "pip".
77
- deploy_to_ecr (bool): Whether to deploy the docker image to AWS ECR, defaults to False. If set to True, the AWS
78
- credentials must be configured in the environment.
79
- base_image_name (Optional[str]): If provided will be used as the base image, else the utility will evaluate
80
- from local environment in following manner:
92
+ deploy_to_ecr (bool): Whether to deploy the docker image to AWS ECR, defaults to False.
93
+ If set to True, the AWS credentials must be configured in the environment.
94
+ base_image_name (Optional[str]): If provided will be used as the base image, else the
95
+ utility will evaluate from local environment in following manner:
81
96
1. If package manager is conda, it will use ubuntu:latest.
82
- 2. If package manager is pip, it is resolved to base python image with the same python version
83
- as the environment running the local code.
84
- job_conda_env (Optional[str]): If set, the dependencies will be captured from this specific conda Env,
85
- otherwise the dependencies will be the installed packages in the current active environment. This parameter
86
- is only valid when the package manager is conda.
87
- additional_dependencies (Optional[str]): Either the path to a dependencies file (conda environment.yml OR pip
88
- requirements.txt file). Regardless of this setting utility will automatically generate the dependencies
89
- file corresponding to the current active environment’s snapshot. In addition to this, additional dependencies
90
- is configurable.
91
- ecr_repo_name (Optional[str]): The AWS ECR repo to push the docker image. If not specified, it will use image_name as
92
- the ECR repo name. This parameter is only valid when deploy_to_ecr is True.
93
- boto_session (Optional[boto3.Session]): The boto3 session with AWS account info. If not provided, a new boto session
94
- will be created.
97
+ 2. If package manager is pip, it is resolved to base python image with the same
98
+ python version as the environment running the local code.
99
+ job_conda_env (Optional[str]): If set, the dependencies will be captured from this specific
100
+ conda Env, otherwise the dependencies will be the installed packages in the current
101
+ active environment. This parameter is only valid when the package manager is conda.
102
+ additional_dependencies (Optional[str]): Either the path to a dependencies file (conda
103
+ environment.yml OR pip requirements.txt file). Regardless of this setting utility will
104
+ automatically generate the dependencies file corresponding to the current active
105
+ environment’s snapshot. In addition to this, additional dependencies is configurable.
106
+ ecr_repo_name (Optional[str]): The AWS ECR repo to push the docker image. If not specified,
107
+ it will use image_name as the ECR repo name. This parameter is only valid when
108
+ deploy_to_ecr is True.
109
+ boto_session (Optional[boto3.Session]): The boto3 session with AWS account info. If not
110
+ provided, a new boto session will be created.
95
111
96
112
Exceptions:
97
113
docker.errors.DockerException: Error while fetching server API version:
98
114
The docker engine is not running in your environment.
99
- docker.errors.BuildError: The docker failed to build the image. The most likely reason is: 1) Some packages are not
100
- supported in the base image. 2) There are dependency conflicts between your local environment and additional dependencies.
115
+ docker.errors.BuildError: The docker failed to build the image. The most likely reason is:
116
+ 1) Some packages are not supported in the base image. 2) There are dependency conflicts
117
+ between your local environment and additional dependencies.
101
118
botocore.exceptions.ClientError: AWS credentials are not configured.
102
119
"""
103
120
@@ -118,7 +135,8 @@ def capture_local_environment(
118
135
".yml"
119
136
) and not additional_dependencies .endswith (".txt" ):
120
137
raise ValueError (
121
- "When package manager is conda, additional dependencies file must be a yml file or a txt file."
138
+ "When package manager is conda, additional dependencies "
139
+ "file must be a yml file or a txt file."
122
140
)
123
141
if additional_dependencies .endswith (".yml" ):
124
142
_merge_environment_ymls (
@@ -153,7 +171,7 @@ def capture_local_environment(
153
171
additional_requirements = f .read ()
154
172
with open (REQUIREMENT_TXT_PATH , "a" ) as f :
155
173
f .write (additional_requirements )
156
- logger .info (f "Merged requirements file saved to { REQUIREMENT_TXT_PATH } " )
174
+ logger .info ("Merged requirements file saved to %s" , REQUIREMENT_TXT_PATH )
157
175
158
176
if not base_image_name :
159
177
version = sys .version_info
@@ -165,23 +183,24 @@ def capture_local_environment(
165
183
166
184
else :
167
185
raise ValueError (
168
- "The provided package manager is not supported. Use conda or pip as the package manager."
186
+ "The provided package manager is not supported. "
187
+ "Use conda or pip as the package manager."
169
188
)
170
189
171
190
# Create the Dockerfile
172
191
with open (DOCKERFILE_PATH , "w" ) as f :
173
192
f .write (dockerfile_contents )
174
193
175
194
client = docker .from_env ()
176
- image , logs = client .images .build (
195
+ _ , logs = client .images .build (
177
196
path = "/tmp" ,
178
197
dockerfile = DOCKERFILE_PATH ,
179
198
rm = True ,
180
199
tag = image_name ,
181
200
)
182
201
for log in logs :
183
202
logger .info (log .get ("stream" , "" ).strip ())
184
- logger .info (f "Docker image { image_name } built successfully" )
203
+ logger .info ("Docker image %s built successfully" , image_name )
185
204
186
205
if deploy_to_ecr :
187
206
if boto_session is None :
@@ -232,14 +251,15 @@ def _merge_environment_ymls(env_name: str, env_file1: str, env_file2: str, outpu
232
251
with open (output_file , "w" ) as f :
233
252
yaml .dump (merged_env , f , sort_keys = False )
234
253
235
- logger .info (f "Merged environment file saved to '{ output_file } '" )
254
+ logger .info ("Merged environment file saved to '%s'" , output_file )
236
255
237
256
238
257
def _merge_environment_yml_with_requirement_txt (
239
258
env_name : str , env_file : str , req_txt : str , output_file : str
240
259
):
241
260
"""
242
- Merge an environment.yml file with a requirements.txt file and save to a new environment.yml file.
261
+ Merge an environment.yml file with a requirements.txt file and save to a new
262
+ environment.yml file.
243
263
244
264
Args:
245
265
env_name (str): The name of the virtual environment to be activated in the image.
@@ -278,7 +298,7 @@ def _merge_environment_yml_with_requirement_txt(
278
298
with open (output_file , "w" ) as f :
279
299
yaml .dump (merged_env , f , sort_keys = False )
280
300
281
- logger .info (f "Merged environment file saved to '{ output_file } '" )
301
+ logger .info ("Merged environment file saved to '%s'" , output_file )
282
302
283
303
284
304
def _push_image_to_ecr (image_name : str , ecr_repo_name : str , boto_session : Optional [boto3 .Session ]):
@@ -317,4 +337,4 @@ def _push_image_to_ecr(image_name: str, ecr_repo_name: str, boto_session: Option
317
337
docker_push_cmd = f"docker push { ecr_image_uri } "
318
338
subprocess .run (docker_push_cmd , shell = True , check = True )
319
339
320
- logger .info (f "Image { image_name } pushed to { ecr_image_uri } " )
340
+ logger .info ("Image %s pushed to %s" , image_name , ecr_image_uri )
0 commit comments