easy-sm 0.1.0__py2.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.

Potentially problematic release.


This version of easy-sm might be problematic. Click here for more details.

Files changed (39) hide show
  1. easy_sm/__init__.py +0 -0
  2. easy_sm/__main__.py +27 -0
  3. easy_sm/commands/__init__.py +0 -0
  4. easy_sm/commands/build.py +74 -0
  5. easy_sm/commands/cloud.py +266 -0
  6. easy_sm/commands/initialize.py +169 -0
  7. easy_sm/commands/local.py +80 -0
  8. easy_sm/commands/push.py +79 -0
  9. easy_sm/config/__init__.py +0 -0
  10. easy_sm/config/config.py +52 -0
  11. easy_sm/sagemaker/__init__.py +0 -0
  12. easy_sm/sagemaker/sagemaker.py +265 -0
  13. easy_sm/template/__init__.py +0 -0
  14. easy_sm/template/easy_sm_base/Dockerfile +27 -0
  15. easy_sm/template/easy_sm_base/__init__.py +0 -0
  16. easy_sm/template/easy_sm_base/build.sh +20 -0
  17. easy_sm/template/easy_sm_base/executor.sh +7 -0
  18. easy_sm/template/easy_sm_base/local_test/deploy_local.sh +7 -0
  19. easy_sm/template/easy_sm_base/local_test/test_dir/input/data/training/.gitkeep +0 -0
  20. easy_sm/template/easy_sm_base/local_test/test_dir/model/.gitkeep +0 -0
  21. easy_sm/template/easy_sm_base/local_test/test_dir/output/.gitkeep +0 -0
  22. easy_sm/template/easy_sm_base/local_test/train_local.sh +7 -0
  23. easy_sm/template/easy_sm_base/prediction/__init__.py +0 -0
  24. easy_sm/template/easy_sm_base/prediction/serve +57 -0
  25. easy_sm/template/easy_sm_base/push.sh +74 -0
  26. easy_sm/template/easy_sm_base/training/__init__.py +0 -0
  27. easy_sm/template/easy_sm_base/training/train +83 -0
  28. easy_sm/template/easy_sm_base/training/training.py +10 -0
  29. easy_sm-0.1.0.dist-info/LICENSE +21 -0
  30. easy_sm-0.1.0.dist-info/METADATA +9 -0
  31. easy_sm-0.1.0.dist-info/RECORD +39 -0
  32. easy_sm-0.1.0.dist-info/WHEEL +6 -0
  33. easy_sm-0.1.0.dist-info/entry_points.txt +2 -0
  34. easy_sm-0.1.0.dist-info/top_level.txt +2 -0
  35. src/__init__.py +0 -0
  36. src/easy_sm_base/__init__.py +0 -0
  37. src/easy_sm_base/prediction/__init__.py +0 -0
  38. src/easy_sm_base/training/__init__.py +0 -0
  39. src/easy_sm_base/training/training.py +29 -0
easy_sm/__init__.py ADDED
File without changes
easy_sm/__main__.py ADDED
@@ -0,0 +1,27 @@
1
+ import click
2
+ from easy_sm.commands.local import local
3
+ from easy_sm.commands.initialize import init
4
+ from easy_sm.commands.build import build
5
+ from easy_sm.commands.push import push
6
+ from easy_sm.commands.cloud import cloud
7
+
8
+ @click.group()
9
+ @click.option(u"-t", u"--docker-tag", default=u"latest", help=u"Specify tag for Docker image")
10
+ @click.pass_context
11
+ def cli(ctx, docker_tag):
12
+ """
13
+ easy_sm enables training and deploying machine learning models on AWS SageMaker in a few minutes!
14
+ """
15
+ ctx.obj = {'docker_tag': docker_tag}
16
+
17
+
18
+ def add_commands(cli):
19
+ cli.add_command(init)
20
+ cli.add_command(build)
21
+ cli.add_command(local)
22
+ cli.add_command(push)
23
+ cli.add_command(cloud)
24
+ # cli.add_command(configure)
25
+
26
+
27
+ add_commands(cli)
File without changes
@@ -0,0 +1,74 @@
1
+ import sys
2
+ import click
3
+ import os
4
+ import subprocess
5
+ from easy_sm.config.config import ConfigManager
6
+
7
+
8
+ def _build(source_dir, requirements_dir, image_name, docker_tag, python_version):
9
+ """
10
+ Builds a Docker image that contains code under the given source root directory.
11
+
12
+ Assumes that Docker is installed and running locally.
13
+
14
+ :param source_dir: [str], source root directory
15
+ :param requirements_dir: [str], path to requirements.txt
16
+ :param image_name: [str], The name of the Docker image
17
+ :param docker_tag: [str], the Docker tag for the image
18
+ """
19
+ easy_sm_module_path = os.path.relpath(os.path.join(source_dir, 'easy_sm_base/'))
20
+
21
+ build_script_path = os.path.join(easy_sm_module_path, 'build.sh')
22
+ dockerfile_path = os.path.join(easy_sm_module_path, 'Dockerfile')
23
+
24
+ train_file_path = os.path.join(easy_sm_module_path, 'training', 'train')
25
+ serve_file_path = os.path.join(easy_sm_module_path, 'prediction', 'serve')
26
+ executor_file_path = os.path.join(easy_sm_module_path, 'executor.sh')
27
+
28
+ if not os.path.isfile(build_script_path) or not os.path.isfile(train_file_path) or not \
29
+ os.path.isfile(serve_file_path):
30
+ raise ValueError("This is not a easy_sm directory: {}".format(source_dir))
31
+
32
+ os.chmod(train_file_path, 0o777)
33
+ os.chmod(serve_file_path, 0o777)
34
+ os.chmod(executor_file_path, 0o777)
35
+
36
+ target_dir_name = os.path.basename(os.path.normpath(source_dir))
37
+ print("------------ Using docker buildx to build from Mac for Sagemaker ------------")
38
+ print("------------ this behaviour is set in src/easy_sm_base/build.sh ------------")
39
+ output = subprocess.check_output(
40
+ [
41
+ "{}".format(build_script_path),
42
+ "{}".format(os.path.relpath(source_dir)),
43
+ "{}".format(os.path.relpath(target_dir_name)),
44
+ "{}".format(dockerfile_path),
45
+ "{}".format(os.path.relpath(requirements_dir)),
46
+ docker_tag,
47
+ image_name,
48
+ python_version
49
+ ]
50
+ )
51
+ print(output)
52
+
53
+
54
+ @click.command()
55
+ @click.pass_obj
56
+ def build(obj):
57
+ """
58
+ Command to build SageMaker app
59
+ """
60
+ print("Started building SageMaker Docker image. It will take some minutes...\n")
61
+
62
+ config_file_path = os.path.join('.easy_sm.json')
63
+ if not os.path.isfile(config_file_path):
64
+ raise ValueError("This is not a easy_sm directory: {}".format(os.getcwd()))
65
+
66
+ config = ConfigManager(config_file_path).get_config()
67
+ _build(
68
+ source_dir=config.easy_sm_module_dir,
69
+ requirements_dir=config.requirements_dir,
70
+ docker_tag=obj['docker_tag'],
71
+ image_name=config.image_name,
72
+ python_version=config.python_version)
73
+
74
+ print("Docker image built successfully!")
@@ -0,0 +1,266 @@
1
+ import os
2
+ import sys
3
+ import click
4
+ from easy_sm.config.config import ConfigManager
5
+ from easy_sm.sagemaker import sagemaker
6
+
7
+
8
+ def _config():
9
+ if not os.path.isfile('.easy_sm.json'):
10
+ raise ValueError("This is not a easy_sm directory: {}".format(os.getcwd()))
11
+ else:
12
+ return ConfigManager('.easy_sm.json').get_config()
13
+
14
+
15
+ @click.group()
16
+ def cloud():
17
+ """
18
+ Commands for AWS operations: upload data, train and deploy
19
+ """
20
+ pass
21
+
22
+
23
+ @click.command(name='upload-data')
24
+ @click.option(u"-i", u"--input-dir", required=True, help="Path to data input directory")
25
+ @click.option(
26
+ u"-s", u"--s3-dir",
27
+ required=True,
28
+ help="s3 location to upload data",
29
+ type=click.Path()
30
+ )
31
+ @click.option(
32
+ u"-r",
33
+ u"--iam-role-arn",
34
+ required=False,
35
+ help="The AWS role to use for the upload command"
36
+ )
37
+ def upload_data(input_dir, s3_dir, iam_role_arn):
38
+ """
39
+ Command to upload data to S3
40
+ """
41
+ print("Started uploading data to S3...\n")
42
+ config = _config()
43
+ sage_maker_client = sagemaker.SageMakerClient(config.aws_profile, config.aws_region, iam_role_arn)
44
+ s3_path = sage_maker_client.upload_data(input_dir, s3_dir)
45
+ print("Data uploaded to {} successfully".format(s3_path))
46
+
47
+
48
+ @click.command(name='train')
49
+ @click.option(
50
+ u"-i", u"--input-s3-dir",
51
+ required=True,
52
+ help="s3 location to input data",
53
+ type=click.Path()
54
+ )
55
+ @click.option(
56
+ u"-o", u"--output-s3-dir",
57
+ required=True,
58
+ help="s3 location to save output (models, etc)",
59
+ type=click.Path()
60
+ )
61
+ @click.option(u"-e", u"--ec2-type", required=True, help="ec2 instance type")
62
+ @click.option(
63
+ u"-r",
64
+ u"--iam-role-arn",
65
+ required=True,
66
+ help="The AWS role to use for the train command"
67
+ )
68
+ @click.option(
69
+ u"-n",
70
+ u"--base-job-name",
71
+ required=False,
72
+ help="Optional prefix for the SageMaker training job."
73
+ "If not specified, the estimator generates a default job name, based on the training image name and current timestamp."
74
+ )
75
+ @click.pass_obj
76
+ def train(
77
+ obj,
78
+ input_s3_dir,
79
+ output_s3_dir,
80
+ ec2_type,
81
+ iam_role_arn,
82
+ base_job_name
83
+ ):
84
+ """
85
+ Command to train ML model(s) on SageMaker
86
+ """
87
+
88
+ print("Started training on SageMaker...\n")
89
+ config = _config()
90
+ sage_maker_client = sagemaker.SageMakerClient(config.aws_profile, config.aws_region, iam_role_arn)
91
+
92
+ image_name = config.image_name+':'+obj['docker_tag']
93
+
94
+ s3_model_location = sage_maker_client.train(
95
+ image_name=image_name,
96
+ input_s3_data_location=input_s3_dir,
97
+ train_instance_type=ec2_type,
98
+ output_path=output_s3_dir,
99
+ base_job_name=base_job_name
100
+ )
101
+
102
+ print("Training on SageMaker succeeded")
103
+ print("Model S3 location: {}".format(s3_model_location))
104
+ return s3_model_location # To pipe into other commands
105
+
106
+
107
+ @click.command(name='deploy_serverless')
108
+ @click.option(
109
+ u"-m", u"--s3-model-location",
110
+ required=True,
111
+ help="s3 location to model tar.gz",
112
+ type=click.Path()
113
+ )
114
+ @click.option(u"-s",
115
+ u"--memory-size-in-mb",
116
+ required=True,
117
+ type=click.INT,
118
+ help="memory size in MB for serverless endpoint")
119
+ @click.option(
120
+ u"-r",
121
+ u"--iam-role-arn",
122
+ required=False,
123
+ help="The AWS role to use for the deploy command"
124
+ )
125
+ @click.option(
126
+ u"-n",
127
+ u"--endpoint-name",
128
+ required=True,
129
+ default=None,
130
+ help="Name for the SageMaker endpoint"
131
+ )
132
+ @click.pass_obj
133
+ def deploy_serverless(
134
+ obj,
135
+ s3_model_location,
136
+ memory_size_in_mb,
137
+ iam_role_arn,
138
+ endpoint_name
139
+ ):
140
+ """
141
+ Command to deploy ML model(s) on SageMaker
142
+ """
143
+
144
+ print("Started deployment on SageMaker ...\n")
145
+ config = _config()
146
+ image_name = config.image_name+':'+obj['docker_tag']
147
+
148
+ sage_maker_client = sagemaker.SageMakerClient(config.aws_profile, config.aws_region, iam_role_arn)
149
+ endpoint_name = sage_maker_client.deploy_serverless(
150
+ image_name=image_name,
151
+ s3_model_location=s3_model_location,
152
+ memory_size_in_mb=memory_size_in_mb,
153
+ endpoint_name=endpoint_name
154
+ )
155
+
156
+ print("Endpoint name: {}".format(endpoint_name))
157
+
158
+
159
+ @click.command(name='batch-transform')
160
+ @click.option(
161
+ u"-m", u"--s3-model-location",
162
+ required=True,
163
+ help="s3 location to model tar.gz",
164
+ type=click.Path()
165
+ )
166
+ @click.option(
167
+ u"-i", u"--s3-input-location",
168
+ required=True,
169
+ help="s3 input data location",
170
+ type=click.Path()
171
+ )
172
+ @click.option(
173
+ u"-o", u"--s3-output-location",
174
+ required=True,
175
+ help="s3 location to save predictions",
176
+ type=click.Path()
177
+ )
178
+ @click.option(u"-n", u"--num-instances", required=True, type=int, help="Number of ec2 instances")
179
+ @click.option(u"-e", u"--ec2-type", required=True, help="ec2 instance type")
180
+ @click.option(
181
+ u"-r",
182
+ u"--iam-role-arn",
183
+ required=False,
184
+ help="The AWS role to use for batch transform command"
185
+ )
186
+ @click.option(
187
+ u"-w",
188
+ u"--wait",
189
+ default=False,
190
+ is_flag=True,
191
+ help="Wait until Batch Transform is finished. "
192
+ "Default: don't wait"
193
+ )
194
+ @click.option(
195
+ u"--job-name",
196
+ required=True,
197
+ default=None,
198
+ help="Name for the SageMaker batch transform job."
199
+ )
200
+ @click.pass_obj
201
+ def batch_transform(
202
+ obj,
203
+ s3_model_location,
204
+ s3_input_location,
205
+ s3_output_location,
206
+ num_instances,
207
+ ec2_type,
208
+ iam_role_arn,
209
+ wait,
210
+ job_name
211
+ ):
212
+ """
213
+ Command to execute a batch transform job given a trained ML model on SageMaker
214
+ """
215
+ print("Started configuration of batch transform on SageMaker ...\n")
216
+
217
+ config = _config()
218
+ image_name = config.image_name+':'+obj['docker_tag']
219
+
220
+ sage_maker_client = sagemaker.SageMakerClient(config.aws_profile, config.aws_region, iam_role_arn)
221
+ status = sage_maker_client.batch_transform(
222
+ image_name=image_name,
223
+ s3_model_location=s3_model_location,
224
+ s3_input_location=s3_input_location,
225
+ s3_output_location=s3_output_location,
226
+ transform_instance_count=num_instances,
227
+ transform_instance_type=ec2_type,
228
+ wait=wait,
229
+ job_name=job_name
230
+ )
231
+
232
+ if wait:
233
+ print("Batch transform on SageMaker finished with status: {}".format(status))
234
+ if status == "Failed":
235
+ sys.exit(1)
236
+ else:
237
+ print("Started batch transform on SageMaker successfully")
238
+
239
+
240
+ @click.command(name='delete_endpoint')
241
+ @click.option(
242
+ u"-n",
243
+ u"--endpoint-name",
244
+ required=True,
245
+ default=None,
246
+ help="Name of the SageMaker endpoint"
247
+ )
248
+ @click.option(
249
+ u"-r",
250
+ u"--iam-role-arn",
251
+ required=False,
252
+ help="The AWS role to use for delete command"
253
+ )
254
+ @click.pass_obj
255
+ def delete_endpoint(obj, endpoint_name, iam_role_arn):
256
+ config = _config()
257
+ sage_maker_client = sagemaker.SageMakerClient(config.aws_profile, config.aws_region, iam_role_arn)
258
+ sage_maker_client.shutdown_endpoint(endpoint_name)
259
+ print(f"Endpoint {endpoint_name} has been deleted")
260
+
261
+
262
+ cloud.add_command(upload_data)
263
+ cloud.add_command(train)
264
+ cloud.add_command(deploy_serverless)
265
+ cloud.add_command(batch_transform)
266
+ cloud.add_command(delete_endpoint)
@@ -0,0 +1,169 @@
1
+ import os
2
+ import sys
3
+
4
+ import boto3
5
+ import click
6
+ from click import BadParameter
7
+ import os
8
+ from pathlib import Path
9
+ from easy_sm.config.config import ConfigManager
10
+ from distutils.dir_util import copy_tree
11
+
12
+ _FILE_DIR_PATH = os.path.dirname(os.path.realpath(__file__))
13
+
14
+
15
+ def _template_creation(app_name, aws_profile, aws_region, python_version, output_dir, requirements_dir):
16
+ easy_sm_module_name = 'easy_sm_base'
17
+
18
+ easy_sm_exists = os.path.exists(os.path.join(output_dir, easy_sm_module_name))
19
+ if easy_sm_exists:
20
+ raise ValueError(
21
+ "There is a easy_sm directory/module already. "
22
+ "Please, rename it in order to use easy_sm."
23
+ )
24
+
25
+ Path(output_dir).mkdir(exist_ok=True)
26
+ Path(os.path.join(output_dir, '__init__.py')).touch()
27
+
28
+ # Set 'easy_sm module' directory up
29
+ copy_tree(os.path.join(_FILE_DIR_PATH, '../template'), output_dir)
30
+
31
+ # Set configuration file up
32
+ config_manager = ConfigManager(os.path.join('.easy_sm.json'))
33
+ config = config_manager.get_config()
34
+
35
+ config.image_name = app_name
36
+ config.aws_region = aws_region
37
+ config.aws_profile = aws_profile
38
+ config.easy_sm_module_dir = output_dir
39
+ config.python_version = python_version
40
+ config.requirements_dir = requirements_dir
41
+ config_manager.set_config(config)
42
+
43
+
44
+ def _get_local_aws_profiles():
45
+ return boto3.Session().available_profiles
46
+
47
+
48
+ def ask_for_app_name():
49
+ return click.prompt(
50
+ text="Type in a name for your SageMaker app (Only alphanumeric characters and - are allowed))",
51
+ type=str
52
+ )
53
+
54
+
55
+ def ask_if_existing_project_exists():
56
+ return click.confirm(text="Are you starting a new project?")
57
+
58
+
59
+ def ask_for_root_dir():
60
+ return click.prompt(text="Type in the directory where your code lives. Example: src", type=str).strip('/')
61
+
62
+
63
+ def ask_for_python_version():
64
+ print("Select Python interpreter:")
65
+ print('{}'.format('\n'.join(['1 - Python39', '2 - Python310', '3 - Python311'])))
66
+
67
+ def _validate_python_option(input_value):
68
+ if int(input_value) not in {1, 2, 3}:
69
+ raise BadParameter(
70
+ message="invalid choice: {}. (choose from 1, 2, 3)".format(str(input_value))
71
+ )
72
+
73
+ return int(input_value)
74
+
75
+ chosen_python_index = click.prompt(
76
+ text="Choose from 1, 2, 3",
77
+ default=1,
78
+ value_proc=lambda x: _validate_python_option(x)
79
+ )
80
+
81
+ _index_to_version = {
82
+ 1: '3.9',
83
+ 2: '3.10',
84
+ 3: '3.11'
85
+ }
86
+
87
+ return _index_to_version[chosen_python_index]
88
+
89
+
90
+ def ask_for_aws_details():
91
+ available_profiles = _get_local_aws_profiles()
92
+
93
+ if len(available_profiles) == 0:
94
+ print("aws cli is not configured!")
95
+ return
96
+
97
+ valid_positions = list(range(1, len(available_profiles) + 1))
98
+ print("Select AWS profile:")
99
+ print('{}'.format(
100
+ '\n'.join(
101
+ [
102
+ '{} - {}'.format(pos, profile)
103
+ for pos, profile in zip(valid_positions, available_profiles)
104
+ ]
105
+ )
106
+ )
107
+ )
108
+
109
+ def _validate_profile_position(input_pos):
110
+ if int(input_pos) not in valid_positions:
111
+ raise BadParameter(
112
+ message="invalid choice: {}. (choose from {})".format(
113
+ input_pos,
114
+ ', '.join([str(pos) for pos in valid_positions])
115
+ )
116
+ )
117
+ return int(input_pos)
118
+
119
+ chosen_profile_index = click.prompt(
120
+ text="Choose from {}".format(', '.join([str(pos) for pos in valid_positions])),
121
+ default=1,
122
+ value_proc=lambda x: _validate_profile_position(x)
123
+ )
124
+ chosen_profile_index -= 1
125
+
126
+ chosen_profile = available_profiles[chosen_profile_index]
127
+
128
+ chosen_region = click.prompt(
129
+ text="Type in your preferred AWS region name",
130
+ default='eu-west-1',
131
+ type=str
132
+ )
133
+
134
+ return chosen_profile, chosen_region
135
+
136
+
137
+ def ask_for_requirements_dir():
138
+ return click.prompt(text="Type in the path to requirements.txt. Example: requirements.txt", type=str).strip('/')
139
+
140
+
141
+ @click.command()
142
+ def init():
143
+ """
144
+ Command to initialize SageMaker template
145
+ """
146
+
147
+ easy_sm_app_name = ask_for_app_name()
148
+
149
+ is_new_project = ask_if_existing_project_exists()
150
+
151
+ root_dir = None
152
+ if not is_new_project:
153
+ root_dir = ask_for_root_dir()
154
+
155
+ python_version = ask_for_python_version()
156
+
157
+ aws_profile, aws_region = ask_for_aws_details()
158
+
159
+ requirements_dir = ask_for_requirements_dir()
160
+ _template_creation(
161
+ app_name=easy_sm_app_name,
162
+ aws_profile=aws_profile,
163
+ aws_region=aws_region,
164
+ python_version=python_version,
165
+ output_dir=root_dir if root_dir else 'src',
166
+ requirements_dir=requirements_dir
167
+ )
168
+
169
+ print("\neasy_sm module is created! ヽ(´▽`)/")
@@ -0,0 +1,80 @@
1
+ import os
2
+ import sys
3
+ import click
4
+ import subprocess
5
+
6
+ from easy_sm.config.config import ConfigManager
7
+
8
+
9
+ @click.group()
10
+ def local():
11
+ """
12
+ Commands for local operations: train and deploy
13
+ """
14
+ pass
15
+
16
+
17
+ @click.command()
18
+ @click.pass_obj
19
+ def train(obj):
20
+ """
21
+ Command to train ML model(s) locally
22
+ """
23
+ print("Started local training...\n")
24
+ config = ConfigManager(os.path.join('.easy_sm.json')).get_config()
25
+ dir = config.easy_sm_module_dir
26
+ docker_tag = obj['docker_tag']
27
+ image_name = config.image_name
28
+ easy_sm_module_path = os.path.join(dir, 'easy_sm_base')
29
+ local_train_script_path = os.path.join(easy_sm_module_path, 'local_test', 'train_local.sh')
30
+ test_path = os.path.join(easy_sm_module_path, 'local_test', 'test_dir')
31
+
32
+ if not os.path.isdir(test_path):
33
+ raise ValueError("This is not a easy_sm directory: {}".format(dir))
34
+
35
+ output = subprocess.check_output(
36
+ [
37
+ "{}".format(local_train_script_path),
38
+ "{}".format(os.path.abspath(test_path)),
39
+ docker_tag,
40
+ image_name
41
+ ]
42
+ )
43
+ print(output)
44
+
45
+ print("Local training completed successfully!")
46
+
47
+
48
+ @click.command()
49
+ @click.pass_obj
50
+ def deploy(obj):
51
+ """
52
+ Command to deploy ML model(s) locally
53
+ """
54
+
55
+ config = ConfigManager(os.path.join('.easy_sm.json')).get_config()
56
+ dir = config.easy_sm_module_dir
57
+ docker_tag = obj['docker_tag']
58
+ image_name = config.image_name
59
+
60
+ easy_sm_module_path = os.path.join(dir, 'easy_sm_base')
61
+ local_deploy_script_path = os.path.join(easy_sm_module_path, 'local_test', 'deploy_local.sh')
62
+ test_path = os.path.join(easy_sm_module_path, 'local_test', 'test_dir')
63
+
64
+ if not os.path.isdir(test_path):
65
+ raise ValueError("This is not a easy_sm directory: {}".format(dir))
66
+
67
+ print("Started local deployment at localhost:8080 ...\n")
68
+ output = subprocess.check_output(
69
+ [
70
+ "{}".format(local_deploy_script_path),
71
+ "{}".format(os.path.abspath(test_path)),
72
+ docker_tag,
73
+ image_name
74
+ ]
75
+ )
76
+ print(output)
77
+
78
+
79
+ local.add_command(train)
80
+ local.add_command(deploy)
@@ -0,0 +1,79 @@
1
+ import sys
2
+ import click
3
+ import subprocess
4
+ import os
5
+ from easy_sm.config.config import ConfigManager
6
+
7
+
8
+ def _push(dir, docker_tag, aws_region, iam_role_arn, aws_profile, external_id, image_name):
9
+ """
10
+ Push Docker image to AWS ECR
11
+
12
+ :param dir: [str], source root directory
13
+ :param docker_tag: [str], the Docker tag for the image
14
+ :param aws_region: [str], the AWS region to push the image to
15
+ :param iam_role_arn: [str], the AWS role used to push the image to ECR
16
+ :param aws_profile: [str], the AWS profile used to push the image to ECR
17
+ :param external_id: [str], Optional external id used when using an IAM role
18
+ :param image_name: [str], The name of the Docker image
19
+ """
20
+
21
+ easy_sm_module_path = os.path.relpath(os.path.join(dir, 'easy_sm_base/'))
22
+ push_script_path = os.path.join(easy_sm_module_path, 'push.sh')
23
+
24
+ if not os.path.isfile(push_script_path):
25
+ raise ValueError("This is not a easy_sm directory: {}".format(dir))
26
+
27
+ output = subprocess.check_output([
28
+ "{}".format(push_script_path),
29
+ docker_tag,
30
+ aws_region,
31
+ iam_role_arn,
32
+ aws_profile,
33
+ external_id,
34
+ image_name])
35
+ print(output)
36
+
37
+ @click.command()
38
+ @click.option(u"-r", u"--aws-region", required=False, help="The AWS region to push the image to")
39
+ @click.option(u"-i", u"--iam-role-arn", required=False, help="The AWS role to use for the push command")
40
+ @click.option(u"-p", u"--aws-profile", required=False, help="The AWS profile to use for the push command")
41
+ @click.option(u"-e", u"--external-id", required=False, help="Optional external id used when using an IAM role")
42
+ @click.pass_obj
43
+ def push(obj, aws_region, iam_role_arn, aws_profile, external_id):
44
+ """
45
+ Command to push Docker image to AWS ECR
46
+ """
47
+
48
+ if iam_role_arn is not None and aws_profile is not None:
49
+ print('Only one of iam-role-arn and aws-profile can be used.')
50
+ sys.exit(2)
51
+
52
+ if iam_role_arn is not None:
53
+ aws_profile = ''
54
+
55
+ config_file_path = os.path.join('.easy_sm.json')
56
+ if not os.path.isfile(config_file_path):
57
+ raise ValueError("This is not a easy_sm directory: {}".format(os.getcwd()))
58
+
59
+ config = ConfigManager(config_file_path).get_config()
60
+ image_name = config.image_name
61
+ aws_region = config.aws_region if aws_region is None else aws_region
62
+ aws_profile = config.aws_profile if (aws_profile is None and iam_role_arn is None) else aws_profile
63
+ external_id = "" if external_id is None else external_id
64
+ iam_role_arn = "" if iam_role_arn is None else iam_role_arn
65
+
66
+ print("Started pushing Docker image to AWS ECR. It will take some time. Please, be patient...\n")
67
+
68
+ _push(
69
+ dir=config.easy_sm_module_dir,
70
+ docker_tag=obj['docker_tag'],
71
+ aws_region=aws_region,
72
+ iam_role_arn=iam_role_arn,
73
+ aws_profile=aws_profile,
74
+ external_id=external_id,
75
+ image_name=image_name)
76
+
77
+ print("Docker image pushed to ECR successfully!")
78
+
79
+
File without changes