1# Copyright The Cloud Custodian Authors.
2# SPDX-License-Identifier: Apache-2.0
3
4from c7n.actions import BaseAction
5from c7n.exceptions import PolicyValidationError
6from c7n.manager import resources
7from c7n.query import QueryResourceManager, TypeInfo, DescribeSource, ConfigSource
8from c7n.utils import local_session, type_schema
9from c7n.tags import RemoveTag, Tag, TagActionFilter, TagDelayedAction, universal_augment
10from c7n.filters.vpc import SubnetFilter, SecurityGroupFilter, NetworkLocation
11from c7n.filters.kms import KmsRelatedFilter
12from c7n.filters.offhours import OffHour, OnHour
13
14
15class NotebookDescribe(DescribeSource):
16
17 def augment(self, resources):
18 client = local_session(self.manager.session_factory).client('sagemaker')
19
20 def _augment(r):
21 # List tags for the Notebook-Instance & set as attribute
22 tags = self.manager.retry(client.list_tags,
23 ResourceArn=r['NotebookInstanceArn'])['Tags']
24 r['Tags'] = tags
25 return r
26
27 # Describe notebook-instance & then list tags
28 resources = super().augment(resources)
29 return list(map(_augment, resources))
30
31
32@resources.register('sagemaker-notebook')
33class NotebookInstance(QueryResourceManager):
34
35 class resource_type(TypeInfo):
36 service = 'sagemaker'
37 enum_spec = ('list_notebook_instances', 'NotebookInstances', None)
38 detail_spec = (
39 'describe_notebook_instance', 'NotebookInstanceName',
40 'NotebookInstanceName', None)
41 arn = id = 'NotebookInstanceArn'
42 name = 'NotebookInstanceName'
43 date = 'CreationTime'
44 config_type = cfn_type = 'AWS::SageMaker::NotebookInstance'
45 permissions_augment = ("sagemaker:ListTags",)
46
47 source_mapping = {'describe': NotebookDescribe, 'config': ConfigSource}
48
49
50NotebookInstance.filter_registry.register('marked-for-op', TagActionFilter)
51NotebookInstance.filter_registry.register('offhour', OffHour)
52NotebookInstance.filter_registry.register('onhour', OnHour)
53
54
55@resources.register('sagemaker-job')
56class SagemakerJob(QueryResourceManager):
57
58 class resource_type(TypeInfo):
59 service = 'sagemaker'
60 enum_spec = ('list_training_jobs', 'TrainingJobSummaries', None)
61 detail_spec = (
62 'describe_training_job', 'TrainingJobName', 'TrainingJobName', None)
63 arn = id = 'TrainingJobArn'
64 name = 'TrainingJobName'
65 date = 'CreationTime'
66 permission_augment = (
67 'sagemaker:DescribeTrainingJob', 'sagemaker:ListTags')
68
69 def __init__(self, ctx, data):
70 super(SagemakerJob, self).__init__(ctx, data)
71 self.queries = QueryFilter.parse(
72 self.data.get('query', [
73 {'StatusEquals': 'InProgress'}]))
74
75 def resources(self, query=None):
76 for q in self.queries:
77 if q is None:
78 continue
79 query = query or {}
80 for k, v in q.items():
81 query[k] = v
82 return super(SagemakerJob, self).resources(query=query)
83
84 def augment(self, jobs):
85 client = local_session(self.session_factory).client('sagemaker')
86
87 def _augment(j):
88 tags = self.retry(client.list_tags,
89 ResourceArn=j['TrainingJobArn'])['Tags']
90 j['Tags'] = tags
91 return j
92
93 jobs = super(SagemakerJob, self).augment(jobs)
94 return list(map(_augment, jobs))
95
96
97@resources.register('sagemaker-transform-job')
98class SagemakerTransformJob(QueryResourceManager):
99
100 class resource_type(TypeInfo):
101 arn_type = "transform-job"
102 service = 'sagemaker'
103 enum_spec = ('list_transform_jobs', 'TransformJobSummaries', None)
104 detail_spec = (
105 'describe_transform_job', 'TransformJobName', 'TransformJobName', None)
106 arn = id = 'TransformJobArn'
107 name = 'TransformJobName'
108 date = 'CreationTime'
109 filter_name = 'NameContains'
110 filter_type = 'scalar'
111 permission_augment = ('sagemaker:DescribeTransformJob', 'sagemaker:ListTags')
112
113 def __init__(self, ctx, data):
114 super(SagemakerTransformJob, self).__init__(ctx, data)
115 self.queries = QueryFilter.parse(
116 self.data.get('query', [
117 {'StatusEquals': 'InProgress'}]))
118
119 def resources(self, query=None):
120 for q in self.queries:
121 if q is None:
122 continue
123 query = query or {}
124 for k, v in q.items():
125 query[k] = v
126 return super(SagemakerTransformJob, self).resources(query=query)
127
128 def augment(self, jobs):
129 client = local_session(self.session_factory).client('sagemaker')
130
131 def _augment(j):
132 tags = self.retry(client.list_tags,
133 ResourceArn=j['TransformJobArn'])['Tags']
134 j['Tags'] = tags
135 return j
136
137 return list(map(_augment, super(SagemakerTransformJob, self).augment(jobs)))
138
139
140class SagemakerHyperParameterTuningJobDescribe(DescribeSource):
141
142 def augment(self, resources):
143 return universal_augment(self.manager, super().augment(resources))
144
145
146@resources.register('sagemaker-hyperparameter-tuning-job')
147class SagemakerHyperParameterTuningJob(QueryResourceManager):
148 class resource_type(TypeInfo):
149 service = 'sagemaker'
150 enum_spec = ('list_hyper_parameter_tuning_jobs', 'HyperParameterTuningJobSummaries', None)
151 detail_spec = (
152 'describe_hyper_parameter_tuning_job', 'HyperParameterTuningJobName',
153 'HyperParameterTuningJobName', None)
154 arn = id = 'HyperParameterTuningJobArn'
155 name = 'HyperParameterTuningJobName'
156 date = 'CreationTime'
157 permission_prefix = 'sagemaker'
158 universal_taggable = object()
159
160 source_mapping = {'describe': SagemakerHyperParameterTuningJobDescribe}
161
162 def __init__(self, ctx, data):
163 super(SagemakerHyperParameterTuningJob, self).__init__(ctx, data)
164 self.queries = QueryFilter.parse(
165 self.data.get('query', [
166 {'StatusEquals': 'InProgress'}]))
167
168 def resources(self, query=None):
169 for q in self.queries:
170 if q is None:
171 continue
172 query = query or {}
173 for k, v in q.items():
174 query[k] = v
175 return super(SagemakerHyperParameterTuningJob, self).resources(query=query)
176
177
178class SagemakerAutoMLDescribeV2(DescribeSource):
179
180 def get_permissions(self):
181 perms = super().get_permissions()
182 perms.remove('sagemaker:DescribeAutoMlJobV2')
183 return perms
184
185 def augment(self, resources):
186 return universal_augment(self.manager, super().augment(resources))
187
188
189@resources.register('sagemaker-auto-ml-job')
190class SagemakerAutoMLJob(QueryResourceManager):
191
192 class resource_type(TypeInfo):
193 service = 'sagemaker'
194 enum_spec = ('list_auto_ml_jobs', 'AutoMLJobSummaries', None)
195 detail_spec = (
196 'describe_auto_ml_job_v2', 'AutoMLJobName', 'AutoMLJobName', None)
197 arn = id = 'AutoMLJobArn'
198 name = 'AutoMLJobName'
199 date = 'CreationTime'
200 # override defaults to casing issues
201 permissions_augment = ('sagemaker:DescribeAutoMLJobV2',)
202 permissions_enum = ('sagemaker:ListAutoMLJobs',)
203 universal_taggable = object()
204
205 source_mapping = {'describe': SagemakerAutoMLDescribeV2}
206
207 def __init__(self, ctx, data):
208 super(SagemakerAutoMLJob, self).__init__(ctx, data)
209 self.queries = QueryFilter.parse(
210 self.data.get('query', [
211 {'StatusEquals': 'InProgress'}]))
212
213 def resources(self, query=None):
214 for q in self.queries:
215 if q is None:
216 continue
217 query = query or {}
218 for k, v in q.items():
219 query[k] = v
220 return super(SagemakerAutoMLJob, self).resources(query=query)
221
222
223class SagemakerCompilationJobDescribe(DescribeSource):
224
225 def augment(self, resources):
226 return universal_augment(self.manager, super().augment(resources))
227
228
229@resources.register('sagemaker-compilation-job')
230class SagemakerCompilationJob(QueryResourceManager):
231
232 class resource_type(TypeInfo):
233 service = 'sagemaker'
234 enum_spec = ('list_compilation_jobs', 'CompilationJobSummaries', None)
235 detail_spec = (
236 'describe_compilation_job', 'CompilationJobName', 'CompilationJobName', None)
237 arn = id = 'CompilationJobArn'
238 name = 'CompilationJobName'
239 date = 'CreationTime'
240 permission_prefix = 'sagemaker'
241 universal_taggable = object()
242
243 source_mapping = {'describe': SagemakerCompilationJobDescribe}
244
245 def __init__(self, ctx, data):
246 super(SagemakerCompilationJob, self).__init__(ctx, data)
247 self.queries = QueryFilter.parse(
248 self.data.get('query', [
249 {'StatusEquals': 'INPROGRESS'}]))
250
251 def resources(self, query=None):
252 for q in self.queries:
253 if q is None:
254 continue
255 query = query or {}
256 for k, v in q.items():
257 query[k] = v
258 return super(SagemakerCompilationJob, self).resources(query=query)
259
260
261class SagemakerProcessingJobDescribe(DescribeSource):
262
263 def augment(self, resources):
264 return universal_augment(self.manager, super().augment(resources))
265
266
267@resources.register('sagemaker-processing-job')
268class SagemakerProcessingJob(QueryResourceManager):
269
270 class resource_type(TypeInfo):
271 service = 'sagemaker'
272 enum_spec = ('list_processing_jobs', 'ProcessingJobSummaries', None)
273 detail_spec = (
274 'describe_processing_job', 'ProcessingJobName', 'ProcessingJobName', None)
275 arn = id = 'ProcessingJobArn'
276 name = 'ProcessingJobName'
277 date = 'CreationTime'
278 permission_prefix = 'sagemaker'
279 universal_taggable = object()
280
281 source_mapping = {'describe': SagemakerProcessingJobDescribe}
282
283 def __init__(self, ctx, data):
284 super(SagemakerProcessingJob, self).__init__(ctx, data)
285 self.queries = QueryFilter.parse(
286 self.data.get('query', [
287 {'StatusEquals': 'InProgress'}]))
288
289 def resources(self, query=None):
290 for q in self.queries:
291 if q is None:
292 continue
293 query = query or {}
294 for k, v in q.items():
295 query[k] = v
296 return super(SagemakerProcessingJob, self).resources(query=query)
297
298
299class SagemakerModelBiasJobDefinitionDescribe(DescribeSource):
300
301 def augment(self, resources):
302 return universal_augment(self.manager, super().augment(resources))
303
304
305@resources.register('sagemaker-model-bias-job-definition')
306class SagemakerModelBiasJobDefinition(QueryResourceManager):
307
308 class resource_type(TypeInfo):
309 service = 'sagemaker'
310 enum_spec = ('list_model_bias_job_definitions', 'JobDefinitionSummaries', None)
311 detail_spec = (
312 'describe_model_bias_job_definition', 'JobDefinitionName',
313 'MonitoringJobDefinitionName', None)
314 arn = id = 'JobDefinitionArn'
315 name = 'JobDefinitionName'
316 date = 'CreationTime'
317 permissions_prefix = 'sagemaker'
318 universal_taggable = object()
319
320 source_mapping = {'describe': SagemakerModelBiasJobDefinitionDescribe}
321
322
323class QueryFilter:
324
325 JOB_FILTERS = ('StatusEquals', 'NameContains',)
326
327 @classmethod
328 def parse(cls, data):
329 results = []
330 names = set()
331 for d in data:
332 if not isinstance(d, dict):
333 raise PolicyValidationError(
334 "Job Query Filter Invalid structure %s" % d)
335 for k, v in d.items():
336 if isinstance(v, list):
337 raise ValueError(
338 'Job query filter invalid structure %s' % v)
339 query = cls(d).validate().query()
340 if query['Name'] in names:
341 # Cannot filter multiple times on the same key
342 continue
343 names.add(query['Name'])
344 if isinstance(query['Value'], list):
345 results.append({query['Name']: query['Value'][0]})
346 continue
347 results.append({query['Name']: query['Value']})
348 if 'StatusEquals' not in names:
349 # add default StatusEquals if not included
350 results.append({'Name': 'StatusEquals', 'Value': 'InProgress'})
351 return results
352
353 def __init__(self, data):
354 self.data = data
355 self.key = None
356 self.value = None
357
358 def validate(self):
359 if not len(list(self.data.keys())) == 1:
360 raise PolicyValidationError(
361 "Job Query Filter Invalid %s" % self.data)
362 self.key = list(self.data.keys())[0]
363 self.value = list(self.data.values())[0]
364
365 if self.key not in self.JOB_FILTERS and not self.key.startswith('tag:'):
366 raise PolicyValidationError(
367 "Job Query Filter invalid filter name %s" % (
368 self.data))
369
370 if self.value is None:
371 raise PolicyValidationError(
372 "Job Query Filters must have a value, use tag-key"
373 " w/ tag name as value for tag present checks"
374 " %s" % self.data)
375 return self
376
377 def query(self):
378 value = self.value
379 if isinstance(self.value, str):
380 value = [self.value]
381 return {'Name': self.key, 'Value': value}
382
383
384class EndpointDescribe(DescribeSource):
385
386 def augment(self, resources):
387 client = local_session(self.manager.session_factory).client('sagemaker')
388
389 def _augment(e):
390 tags = self.manager.retry(client.list_tags,
391 ResourceArn=e['EndpointArn'])['Tags']
392 e['Tags'] = tags
393 return e
394
395 # Describe endpoints & then list tags
396 endpoints = super().augment(resources)
397 return list(map(_augment, endpoints))
398
399
400@resources.register('sagemaker-endpoint')
401class SagemakerEndpoint(QueryResourceManager):
402
403 class resource_type(TypeInfo):
404 service = 'sagemaker'
405 enum_spec = ('list_endpoints', 'Endpoints', None)
406 detail_spec = (
407 'describe_endpoint', 'EndpointName',
408 'EndpointName', None)
409 arn = id = 'EndpointArn'
410 name = 'EndpointName'
411 date = 'CreationTime'
412 cfn_type = 'AWS::SageMaker::Endpoint'
413
414 permissions = ('sagemaker:ListTags',)
415
416 source_mapping = {'describe': EndpointDescribe}
417
418
419SagemakerEndpoint.filter_registry.register('marked-for-op', TagActionFilter)
420
421
422class EndpointConfigDescribe(DescribeSource):
423
424 def augment(self, resources):
425 client = local_session(self.manager.session_factory).client('sagemaker')
426
427 def _augment(e):
428 tags = self.manager.retry(client.list_tags,
429 ResourceArn=e['EndpointConfigArn'])['Tags']
430 e['Tags'] = tags
431 return e
432
433 endpoints = super().augment(resources)
434 return list(map(_augment, endpoints))
435
436
437@resources.register('sagemaker-endpoint-config')
438class SagemakerEndpointConfig(QueryResourceManager):
439
440 class resource_type(TypeInfo):
441 service = 'sagemaker'
442 enum_spec = ('list_endpoint_configs', 'EndpointConfigs', None)
443 detail_spec = (
444 'describe_endpoint_config', 'EndpointConfigName',
445 'EndpointConfigName', None)
446 arn = id = 'EndpointConfigArn'
447 name = 'EndpointConfigName'
448 date = 'CreationTime'
449 config_type = cfn_type = 'AWS::SageMaker::EndpointConfig'
450 permissions_augment = ('sagemaker:ListTags',)
451
452 source_mapping = {'describe': EndpointConfigDescribe, 'config': ConfigSource}
453
454
455SagemakerEndpointConfig.filter_registry.register('marked-for-op', TagActionFilter)
456
457
458class DescribeModel(DescribeSource):
459
460 def augment(self, resources):
461 client = local_session(self.manager.session_factory).client('sagemaker')
462
463 def _augment(r):
464 tags = self.manager.retry(client.list_tags,
465 ResourceArn=r['ModelArn'])['Tags']
466 r.setdefault('Tags', []).extend(tags)
467 return r
468
469 resources = super(DescribeModel, self).augment(resources)
470 return list(map(_augment, resources))
471
472
473@resources.register('sagemaker-model')
474class Model(QueryResourceManager):
475
476 class resource_type(TypeInfo):
477 service = 'sagemaker'
478 enum_spec = ('list_models', 'Models', None)
479 detail_spec = (
480 'describe_model', 'ModelName',
481 'ModelName', None)
482 arn = id = 'ModelArn'
483 name = 'ModelName'
484 date = 'CreationTime'
485 cfn_type = config_type = 'AWS::SageMaker::Model'
486
487 source_mapping = {
488 'describe': DescribeModel,
489 'config': ConfigSource
490 }
491
492 permissions = ('sagemaker:ListTags',)
493
494
495Model.filter_registry.register('marked-for-op', TagActionFilter)
496
497
498class SagemakerClusterDescribe(DescribeSource):
499
500 def augment(self, resources):
501 return universal_augment(self.manager, super().augment(resources))
502
503
504@resources.register('sagemaker-cluster')
505class Cluster(QueryResourceManager):
506
507 class resource_type(TypeInfo):
508 service = 'sagemaker'
509 enum_spec = ('list_clusters', 'ClusterSummaries', None)
510 detail_spec = (
511 'describe_cluster', 'ClusterName',
512 'ClusterName', None)
513 arn = id = 'ClusterArn'
514 name = 'ClusterName'
515 date = 'CreationTime'
516 cfn_type = None
517 permission_prefix = 'sagemaker'
518 universal_taggable = object()
519
520 source_mapping = {'describe': SagemakerClusterDescribe}
521
522
523class SagemakerDataQualityJobDefinitionDescribe(DescribeSource):
524
525 def augment(self, resources):
526 return universal_augment(self.manager, super().augment(resources))
527
528
529@resources.register('sagemaker-data-quality-job-definition')
530class SagemakerDataQualityJobDefinition(QueryResourceManager):
531 class resource_type(TypeInfo):
532 service = 'sagemaker'
533 enum_spec = ('list_data_quality_job_definitions', 'JobDefinitionSummaries', None)
534 detail_spec = ('describe_data_quality_job_definition', 'JobDefinitionName',
535 'MonitoringJobDefinitionName', None)
536 arn = id = 'JobDefinitionArn'
537 name = 'JobDefinitionName'
538 date = 'CreationTime'
539 cfn_type = 'AWS::SageMaker::DataQualityJobDefinition'
540 permission_prefix = 'sagemaker'
541 filter_name = 'EndpointName'
542 filter_type = 'scalar'
543 universal_taggable = object()
544
545 source_mapping = {'describe': SagemakerDataQualityJobDefinitionDescribe}
546
547
548class SagemakerModelExplainabilityJobDefinitionDescribe(DescribeSource):
549
550 def augment(self, resources):
551 return universal_augment(self.manager, super().augment(resources))
552
553
554@resources.register('sagemaker-model-explainability-job-definition')
555class SagemakerModelExplainabilityJobDefinition(QueryResourceManager):
556 class resource_type(TypeInfo):
557 service = 'sagemaker'
558 enum_spec = ('list_model_explainability_job_definitions', 'JobDefinitionSummaries', None)
559 detail_spec = ('describe_model_explainability_job_definition', 'JobDefinitionName',
560 'MonitoringJobDefinitionName', None)
561 arn = id = 'JobDefinitionArn'
562 name = 'JobDefinitionName'
563 date = 'CreationTime'
564 cfn_type = 'AWS::SageMaker::ModelExplainabilityJobDefinition'
565 permission_prefix = 'sagemaker'
566 filter_name = 'EndpointName'
567 filter_type = 'scalar'
568 universal_taggable = object()
569
570 source_mapping = {'describe': SagemakerModelExplainabilityJobDefinitionDescribe}
571
572
573class SagemakerModelQualityJobDefinitionDescribe(DescribeSource):
574
575 def augment(self, resources):
576 return universal_augment(self.manager, super().augment(resources))
577
578
579@resources.register('sagemaker-model-quality-job-definition')
580class SagemakerModelQualityJobDefinition(QueryResourceManager):
581 class resource_type(TypeInfo):
582 service = 'sagemaker'
583 enum_spec = ('list_model_quality_job_definitions', 'JobDefinitionSummaries', None)
584 detail_spec = ('describe_model_quality_job_definition', 'JobDefinitionName',
585 'MonitoringJobDefinitionName', None)
586 arn = id = 'JobDefinitionArn'
587 name = 'JobDefinitionName'
588 date = 'CreationTime'
589 cfn_type = 'AWS::SageMaker::ModelQualityJobDefinition'
590 permission_prefix = 'sagemaker'
591 filter_name = 'EndpointName'
592 filter_type = 'scalar'
593 universal_taggable = object()
594
595 source_mapping = {'describe': SagemakerModelQualityJobDefinitionDescribe}
596
597
598@SagemakerEndpoint.action_registry.register('tag')
599@SagemakerEndpointConfig.action_registry.register('tag')
600@NotebookInstance.action_registry.register('tag')
601@SagemakerJob.action_registry.register('tag')
602@SagemakerTransformJob.action_registry.register('tag')
603@Model.action_registry.register('tag')
604class TagNotebookInstance(Tag):
605 """Action to create tag(s) on a SageMaker resource
606 (notebook-instance, endpoint, endpoint-config)
607
608 :example:
609
610 .. code-block:: yaml
611
612 policies:
613 - name: tag-sagemaker-notebook
614 resource: sagemaker-notebook
615 filters:
616 - "tag:target-tag": absent
617 actions:
618 - type: tag
619 key: target-tag
620 value: target-value
621
622 - name: tag-sagemaker-endpoint
623 resource: sagemaker-endpoint
624 filters:
625 - "tag:required-tag": absent
626 actions:
627 - type: tag
628 key: required-tag
629 value: required-value
630
631 - name: tag-sagemaker-endpoint-config
632 resource: sagemaker-endpoint-config
633 filters:
634 - "tag:required-tag": absent
635 actions:
636 - type: tag
637 key: required-tag
638 value: required-value
639
640 - name: tag-sagemaker-job
641 resource: sagemaker-job
642 filters:
643 - "tag:required-tag": absent
644 actions:
645 - type: tag
646 key: required-tag
647 value: required-value
648 """
649 permissions = ('sagemaker:AddTags',)
650
651 def process_resource_set(self, client, resources, tags):
652 mid = self.manager.resource_type.id
653 for r in resources:
654 client.add_tags(ResourceArn=r[mid], Tags=tags)
655
656
657@SagemakerEndpoint.action_registry.register('remove-tag')
658@SagemakerEndpointConfig.action_registry.register('remove-tag')
659@NotebookInstance.action_registry.register('remove-tag')
660@SagemakerJob.action_registry.register('remove-tag')
661@SagemakerTransformJob.action_registry.register('remove-tag')
662@Model.action_registry.register('remove-tag')
663class RemoveTagNotebookInstance(RemoveTag):
664 """Remove tag(s) from SageMaker resources
665 (notebook-instance, endpoint, endpoint-config)
666
667 :example:
668
669 .. code-block:: yaml
670
671 policies:
672 - name: sagemaker-notebook-remove-tag
673 resource: sagemaker-notebook
674 filters:
675 - "tag:BadTag": present
676 actions:
677 - type: remove-tag
678 tags: ["BadTag"]
679
680 - name: sagemaker-endpoint-remove-tag
681 resource: sagemaker-endpoint
682 filters:
683 - "tag:expired-tag": present
684 actions:
685 - type: remove-tag
686 tags: ["expired-tag"]
687
688 - name: sagemaker-endpoint-config-remove-tag
689 resource: sagemaker-endpoint-config
690 filters:
691 - "tag:expired-tag": present
692 actions:
693 - type: remove-tag
694 tags: ["expired-tag"]
695
696 - name: sagemaker-job-remove-tag
697 resource: sagemaker-job
698 filters:
699 - "tag:expired-tag": present
700 actions:
701 - type: remove-tag
702 tags: ["expired-tag"]
703 """
704 permissions = ('sagemaker:DeleteTags',)
705
706 def process_resource_set(self, client, resources, keys):
707 for r in resources:
708 client.delete_tags(ResourceArn=r[self.id_key], TagKeys=keys)
709
710
711@SagemakerEndpoint.action_registry.register('mark-for-op')
712@SagemakerEndpointConfig.action_registry.register('mark-for-op')
713@NotebookInstance.action_registry.register('mark-for-op')
714@Model.action_registry.register('mark-for-op')
715class MarkNotebookInstanceForOp(TagDelayedAction):
716 """Mark SageMaker resources for deferred action
717 (notebook-instance, endpoint, endpoint-config)
718
719 :example:
720
721 .. code-block:: yaml
722
723 policies:
724 - name: sagemaker-notebook-invalid-tag-stop
725 resource: sagemaker-notebook
726 filters:
727 - "tag:InvalidTag": present
728 actions:
729 - type: mark-for-op
730 op: stop
731 days: 1
732
733 - name: sagemaker-endpoint-failure-delete
734 resource: sagemaker-endpoint
735 filters:
736 - 'EndpointStatus': 'Failed'
737 actions:
738 - type: mark-for-op
739 op: delete
740 days: 1
741
742 - name: sagemaker-endpoint-config-invalid-size-delete
743 resource: sagemaker-notebook
744 filters:
745 - type: value
746 - key: ProductionVariants[].InstanceType
747 - value: 'ml.m4.10xlarge'
748 - op: contains
749 actions:
750 - type: mark-for-op
751 op: delete
752 days: 1
753 """
754
755
756@NotebookInstance.action_registry.register('start')
757class StartNotebookInstance(BaseAction):
758 """Start sagemaker-notebook(s)
759
760 :example:
761
762 .. code-block:: yaml
763
764 policies:
765 - name: start-sagemaker-notebook
766 resource: sagemaker-notebook
767 actions:
768 - start
769 """
770 schema = type_schema('start')
771 permissions = ('sagemaker:StartNotebookInstance',)
772 valid_origin_states = ('Stopped',)
773
774 def process(self, resources):
775 resources = self.filter_resources(resources, 'NotebookInstanceStatus',
776 self.valid_origin_states)
777 if not len(resources):
778 return
779
780 client = local_session(self.manager.session_factory).client('sagemaker')
781
782 for n in resources:
783 try:
784 client.start_notebook_instance(
785 NotebookInstanceName=n['NotebookInstanceName'])
786 except client.exceptions.ResourceNotFound:
787 pass
788
789
790@NotebookInstance.action_registry.register('stop')
791class StopNotebookInstance(BaseAction):
792 """Stop sagemaker-notebook(s)
793
794 :example:
795
796 .. code-block:: yaml
797
798 policies:
799 - name: stop-sagemaker-notebook
800 resource: sagemaker-notebook
801 filters:
802 - "tag:DeleteMe": present
803 actions:
804 - stop
805 """
806 schema = type_schema('stop')
807 permissions = ('sagemaker:StopNotebookInstance',)
808 valid_origin_states = ('InService',)
809
810 def process(self, resources):
811 resources = self.filter_resources(resources, 'NotebookInstanceStatus',
812 self.valid_origin_states)
813 if not len(resources):
814 return
815
816 client = local_session(self.manager.session_factory).client('sagemaker')
817
818 for n in resources:
819 try:
820 client.stop_notebook_instance(
821 NotebookInstanceName=n['NotebookInstanceName'])
822 except client.exceptions.ResourceNotFound:
823 pass
824
825
826@NotebookInstance.action_registry.register('delete')
827class DeleteNotebookInstance(BaseAction):
828 """Deletes sagemaker-notebook(s)
829
830 :example:
831
832 .. code-block:: yaml
833
834 policies:
835 - name: delete-sagemaker-notebook
836 resource: sagemaker-notebook
837 filters:
838 - "tag:DeleteMe": present
839 actions:
840 - delete
841 """
842 schema = type_schema('delete')
843 permissions = ('sagemaker:DeleteNotebookInstance',)
844 valid_origin_states = ('Stopped', 'Failed',)
845
846 def process(self, resources):
847 resources = self.filter_resources(resources, 'NotebookInstanceStatus',
848 self.valid_origin_states)
849 if not len(resources):
850 return
851
852 client = local_session(self.manager.session_factory).client('sagemaker')
853
854 for n in resources:
855 try:
856 client.delete_notebook_instance(
857 NotebookInstanceName=n['NotebookInstanceName'])
858 except client.exceptions.ResourceNotFound:
859 pass
860
861
862@NotebookInstance.filter_registry.register('security-group')
863class NotebookSecurityGroupFilter(SecurityGroupFilter):
864
865 RelatedIdsExpression = "SecurityGroups[]"
866
867
868@NotebookInstance.filter_registry.register('subnet')
869class NotebookSubnetFilter(SubnetFilter):
870
871 RelatedIdsExpression = "SubnetId"
872
873
874@Cluster.filter_registry.register('security-group')
875class ClusterSecurityGroupFilter(SecurityGroupFilter):
876
877 RelatedIdsExpression = "VpcConfig.SecurityGroupIds[]"
878
879
880@Cluster.filter_registry.register('subnet')
881class ClusterSubnetFilter(SubnetFilter):
882
883 RelatedIdsExpression = "VpcConfig.Subnets[]"
884
885
886@Cluster.filter_registry.register('network-location', NetworkLocation)
887@NotebookInstance.filter_registry.register('kms-key')
888@SagemakerEndpointConfig.filter_registry.register('kms-key')
889class NotebookKmsFilter(KmsRelatedFilter):
890
891 RelatedIdsExpression = "KmsKeyId"
892
893
894@Model.action_registry.register('delete')
895class DeleteModel(BaseAction):
896 """Deletes sagemaker-model(s)
897
898 :example:
899
900 .. code-block:: yaml
901
902 policies:
903 - name: delete-sagemaker-model
904 resource: sagemaker-model
905 filters:
906 - "tag:DeleteMe": present
907 actions:
908 - delete
909 """
910 schema = type_schema('delete')
911 permissions = ('sagemaker:DeleteModel',)
912
913 def process(self, resources):
914 client = local_session(self.manager.session_factory).client('sagemaker')
915
916 for m in resources:
917 try:
918 client.delete_model(ModelName=m['ModelName'])
919 except client.exceptions.ResourceNotFound:
920 pass
921
922
923@SagemakerJob.action_registry.register('stop')
924class SagemakerJobStop(BaseAction):
925 """Stops a SageMaker job
926
927 :example:
928
929 .. code-block:: yaml
930
931 policies:
932 - name: stop-ml-job
933 resource: sagemaker-job
934 filters:
935 - TrainingJobName: ml-job-10
936 actions:
937 - stop
938 """
939 schema = type_schema('stop')
940 permissions = ('sagemaker:StopTrainingJob',)
941
942 def process(self, jobs):
943 client = local_session(self.manager.session_factory).client('sagemaker')
944
945 for j in jobs:
946 try:
947 client.stop_training_job(TrainingJobName=j['TrainingJobName'])
948 except client.exceptions.ResourceNotFound:
949 pass
950
951
952@SagemakerEndpoint.action_registry.register('delete')
953class SagemakerEndpointDelete(BaseAction):
954 """Delete a SageMaker endpoint
955
956 :example:
957
958 .. code-block:: yaml
959
960 policies:
961 - name: delete-sagemaker-endpoint
962 resource: sagemaker-endpoint
963 filters:
964 - EndpointName: sagemaker-ep--2018-01-01-00-00-00
965 actions:
966 - type: delete
967 """
968 permissions = (
969 'sagemaker:DeleteEndpoint',
970 'sagemaker:DeleteEndpointConfig')
971 schema = type_schema('delete')
972
973 def process(self, endpoints):
974 client = local_session(self.manager.session_factory).client('sagemaker')
975 for e in endpoints:
976 try:
977 client.delete_endpoint(EndpointName=e['EndpointName'])
978 except client.exceptions.ResourceNotFound:
979 pass
980
981
982@SagemakerModelBiasJobDefinition.action_registry.register('delete')
983class SagemakerModelBiasJobDefinitionDelete(BaseAction):
984 """ Deletes sagemaker-model-bias-job-definition """
985 schema = type_schema('delete')
986 permissions = ('sagemaker:DeleteModelBiasJobDefinition',)
987
988 def process(self, definitions):
989 client = local_session(self.manager.session_factory).client('sagemaker')
990
991 for d in definitions:
992 try:
993 client.delete_model_bias_job_definition(
994 JobDefinitionName=d['JobDefinitionName'])
995 except client.exceptions.ResourceNotFound:
996 pass
997
998
999@SagemakerEndpointConfig.action_registry.register('delete')
1000class SagemakerEndpointConfigDelete(BaseAction):
1001 """Delete a SageMaker endpoint
1002
1003 :example:
1004
1005 .. code-block:: yaml
1006
1007 policies:
1008 - name: delete-sagemaker-endpoint-config
1009 resource: sagemaker-endpoint-config
1010 filters:
1011 - EndpointConfigName: sagemaker-2018-01-01-00-00-00-T00
1012 actions:
1013 - delete
1014 """
1015 schema = type_schema('delete')
1016 permissions = ('sagemaker:DeleteEndpointConfig',)
1017
1018 def process(self, endpoints):
1019 client = local_session(self.manager.session_factory).client('sagemaker')
1020 for e in endpoints:
1021 try:
1022 client.delete_endpoint_config(
1023 EndpointConfigName=e['EndpointConfigName'])
1024 except client.exceptions.ResourceNotFound:
1025 pass
1026
1027
1028@SagemakerDataQualityJobDefinition.action_registry.register('delete')
1029class SagemakerDataQualityJobDefinitionDelete(BaseAction):
1030 """Delete a SageMaker Data Quality Job Definition
1031
1032 :example:
1033
1034 .. code-block:: yaml
1035
1036 policies:
1037 - name: delete-sagemaker-data-quality-job-definition
1038 resource: sagemaker-data-quality-job-definition
1039 filters:
1040 - JobDefinitionName: job-def-1
1041 actions:
1042 - delete
1043 """
1044 schema = type_schema('delete')
1045 permissions = ('sagemaker:DeleteDataQualityJobDefinition',)
1046
1047 def process(self, job_definitions):
1048 client = local_session(self.manager.session_factory).client('sagemaker')
1049 for j in job_definitions:
1050 try:
1051 client.delete_data_quality_job_definition(
1052 JobDefinitionName=j['JobDefinitionName'])
1053 except client.exceptions.ResourceNotFound:
1054 pass
1055
1056
1057@SagemakerModelExplainabilityJobDefinition.action_registry.register('delete')
1058class SagemakerModelExplainabilityJobDefinitionDelete(BaseAction):
1059 """Delete a SageMaker Model Explainability Job Definition
1060
1061 :example:
1062
1063 .. code-block:: yaml
1064
1065 policies:
1066 - name: delete-sagemaker-model-explainability-job-definition
1067 resource: sagemaker-model-explainability-job-definition
1068 filters:
1069 - JobDefinitionName: job-def-1
1070 actions:
1071 - delete
1072 """
1073 schema = type_schema('delete')
1074 permissions = ('sagemaker:DeleteModelExplainabilityJobDefinition',)
1075
1076 def process(self, job_definitions):
1077 client = local_session(self.manager.session_factory).client('sagemaker')
1078 for j in job_definitions:
1079 try:
1080 client.delete_model_explainability_job_definition(
1081 JobDefinitionName=j['JobDefinitionName'])
1082 except client.exceptions.ResourceNotFound:
1083 pass
1084
1085
1086@SagemakerModelQualityJobDefinition.action_registry.register('delete')
1087class SagemakerModelQualityJobDefinitionDelete(BaseAction):
1088 """Delete a SageMaker Model Quality Job Definition
1089
1090 :example:
1091
1092 .. code-block:: yaml
1093
1094 policies:
1095 - name: delete-sagemaker-model-quality-job-definition
1096 resource: sagemaker-model-quality-job-definition
1097 filters:
1098 - JobDefinitionName: job-def-1
1099 actions:
1100 - delete
1101 """
1102 schema = type_schema('delete')
1103 permissions = ('sagemaker:DeleteModelQualityJobDefinition',)
1104
1105 def process(self, job_definitions):
1106 client = local_session(self.manager.session_factory).client('sagemaker')
1107 for j in job_definitions:
1108 try:
1109 client.delete_model_quality_job_definition(
1110 JobDefinitionName=j['JobDefinitionName'])
1111 except client.exceptions.ResourceNotFound:
1112 pass
1113
1114
1115@SagemakerTransformJob.action_registry.register('stop')
1116class SagemakerTransformJobStop(BaseAction):
1117 """Stops a SageMaker Transform job
1118
1119 :example:
1120
1121 .. code-block:: yaml
1122
1123 policies:
1124 - name: stop-tranform-job
1125 resource: sagemaker-transform-job
1126 filters:
1127 - TransformJobName: ml-job-10
1128 actions:
1129 - stop
1130 """
1131 schema = type_schema('stop')
1132 permissions = ('sagemaker:StopTransformJob',)
1133
1134 def process(self, jobs):
1135 client = local_session(self.manager.session_factory).client('sagemaker')
1136
1137 for j in jobs:
1138 try:
1139 client.stop_transform_job(TransformJobName=j['TransformJobName'])
1140 except client.exceptions.ResourceNotFound:
1141 pass
1142
1143
1144@SagemakerHyperParameterTuningJob.action_registry.register('stop')
1145class SagemakerHyperParameterTuningJobStop(BaseAction):
1146 """Stops a SageMaker Hyperparameter Tuning job
1147
1148 :example:
1149
1150 .. code-block:: yaml
1151
1152 policies:
1153 - name: stop-hyperparameter-tuning-job
1154 resource: sagemaker-hyperparameter-tuning-job
1155 filters:
1156 - HyperParameterTuningJobName: ml-job-10
1157 actions:
1158 - stop
1159 """
1160 schema = type_schema('stop')
1161 permissions = ('sagemaker:StopHyperParameterTuningJob',)
1162
1163 def process(self, jobs):
1164 client = local_session(self.manager.session_factory).client('sagemaker')
1165
1166 for j in jobs:
1167 try:
1168 client.stop_hyper_parameter_tuning_job(HyperParameterTuningJobName=j['HyperParameterTuningJobName'])
1169 except client.exceptions.ResourceNotFound:
1170 pass
1171
1172
1173@SagemakerAutoMLJob.action_registry.register('stop')
1174class SagemakerAutoMLJobStop(BaseAction):
1175 """Stops a SageMaker AutoML job
1176
1177 :example:
1178
1179 .. code-block:: yaml
1180
1181 policies:
1182 - name: stop-automl-job
1183 resource: sagemaker-auto-ml-job
1184 filters:
1185 - AutoMLJobName: ml-job-01
1186 actions:
1187 - stop
1188 """
1189 schema = type_schema('stop')
1190 permissions = ('sagemaker:StopAutoMLJob',)
1191
1192 def process(self, jobs):
1193 client = local_session(self.manager.session_factory).client('sagemaker')
1194
1195 for j in jobs:
1196 try:
1197 client.stop_auto_ml_job(AutoMLJobName=j['AutoMLJobName'])
1198 except client.exceptions.ResourceNotFound:
1199 pass
1200
1201
1202@SagemakerCompilationJob.action_registry.register('stop')
1203class SagemakerCompilationJobStop(BaseAction):
1204 """Stops a SageMaker Compilation job
1205
1206 :example:
1207
1208 .. code-block:: yaml
1209
1210 policies:
1211 - name: stop-compilation-job
1212 resource: sagemaker-compilation-job
1213 filters:
1214 - CompilationJobName: ml-job-10
1215 actions:
1216 - stop
1217 """
1218 schema = type_schema('stop')
1219 permissions = ('sagemaker:StopCompilationJob',)
1220
1221 def process(self, jobs):
1222 client = local_session(self.manager.session_factory).client('sagemaker')
1223
1224 for j in jobs:
1225 try:
1226 client.stop_compilation_job(CompilationJobName=j['CompilationJobName'])
1227 except client.exceptions.ResourceNotFound:
1228 pass
1229
1230
1231@SagemakerProcessingJob.action_registry.register('stop')
1232class SagemakerProcessingJobStop(BaseAction):
1233 """Stops a Sagemaker Processing job
1234
1235 :example:
1236
1237 .. code-block:: yaml
1238
1239 policies:
1240 - name: stop-processing-job
1241 resource: sagemaker-processing-job
1242 filters:
1243 - ProcessingJobName: ml-job-10
1244 actions:
1245 - stop
1246 """
1247 schema = type_schema('stop')
1248 permissions = ('sagemaker:StopProcessingJob',)
1249
1250 def process(self, jobs):
1251 client = local_session(self.manager.session_factory).client('sagemaker')
1252
1253 for j in jobs:
1254 try:
1255 client.stop_processing_job(ProcessingJobName=j['ProcessingJobName'])
1256 except client.exceptions.ResourceNotFound:
1257 pass
1258
1259
1260@Cluster.action_registry.register('delete')
1261class ClusterDelete(BaseAction):
1262 """Deletes sagemaker-cluster(s)
1263
1264 :example:
1265
1266 .. code-block:: yaml
1267
1268 policies:
1269 - name: delete-sagemaker-cluster
1270 resource: sagemaker-cluster
1271 filters:
1272 - "tag:DeleteMe": present
1273 actions:
1274 - delete
1275 """
1276 schema = type_schema('delete')
1277 permissions = ('sagemaker:DeleteCluster',)
1278
1279 def process(self, resources):
1280 client = local_session(self.manager.session_factory).client('sagemaker')
1281
1282 for c in resources:
1283 try:
1284 client.delete_cluster(ClusterName=c['ClusterName'])
1285 except client.exceptions.ResourceNotFound:
1286 pass
1287
1288
1289class SagemakerDomainDescribe(DescribeSource):
1290
1291 def augment(self, resources):
1292 return universal_augment(self.manager, super().augment(resources))
1293
1294
1295@resources.register('sagemaker-domain')
1296class SagemakerDomain(QueryResourceManager):
1297
1298 class resource_type(TypeInfo):
1299 service = 'sagemaker'
1300 enum_spec = ('list_domains', 'Domains', None)
1301 detail_spec = ('describe_domain', 'DomainId', 'DomainId', None)
1302 id = 'DomainId'
1303 arn = 'DomainArn'
1304 name = 'DomainName'
1305 cfn_type = 'AWS::SageMaker::Domain'
1306 permission_prefix = 'sagemaker'
1307 universal_taggable = object()
1308
1309 source_mapping = {'describe': SagemakerDomainDescribe}
1310
1311
1312@SagemakerDomain.filter_registry.register('kms-key')
1313class SagemakerDomainKmsFilter(KmsRelatedFilter):
1314 RelatedIdsExpression = 'KmsKeyId'