├── .github ├── ISSUE_TEMPLATE │ ├── enhancement-request.md │ ├── feature_request.md │ └── question.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app.py ├── cdk.json ├── img └── aws_cdk_sagemake_studio_deploy_confimation.png ├── requirements.txt ├── sagemakerStudioCDK ├── __init__.py └── sagemaker_studio_stack.py ├── sagemakerStudioConstructs ├── __init__.py └── sagemakerStudioCloudformationStack │ ├── sagemaker-domain-template.yaml │ └── sagemaker-user-template.yaml ├── setup.py ├── source.bat └── tests ├── __init__.py └── unit ├── __init__.py └── test_sagemaker_studio_stack.py /.github/ISSUE_TEMPLATE/enhancement-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancement request 3 | about: Suggest an idea to enhance some existing feature 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your idea related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | *P.S. Don't attach files. Please, prefer add code snippets directly in the message body.* 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | *P.S. Please Don't attach files. Add code snippets directly in the message body instead.* -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask with as many useful details as possible 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | *P.S. Don't attach files. Please, prefer add code snippets directly in the message body.* 11 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Feature or Bugfix 2 | 3 | - Feature 4 | - Bugfix 5 | - Refactoring 6 | 7 | ### Detail 8 | - 9 | - 10 | 11 | ### Relates 12 | - 13 | 14 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | package-lock.json 3 | .pytest_cache 4 | *.egg-info 5 | .idea/ 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # Environments 12 | .env 13 | .venv 14 | env/ 15 | venv/ 16 | env.bak/ 17 | venv.bak/ 18 | 19 | # CDK Context & Staging files 20 | .cdk.staging/ 21 | cdk.out/ 22 | /cdk.context.json 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build and automatize the management of your Sagemaker Studio Users using AWS CDK! 2 | 3 | You should explore the contents of this project. It demonstrates a CDK app with an instance of a 4 | stack (`sagemakerStudioCDK`) 5 | 6 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 7 | 8 | ## Deployment Steps 9 | 10 | Pre-requisites: 11 | 12 | * An AWS profile with permissions to create AWS Identity and Access Management (AWS IAM) roles, Studio domains, and Studio user profiles 13 | * AWS CLI, authenticated and configured 14 | * Python 3.6+ 15 | * AWS CDK 16 | * Git 17 | * Knowledge on how Amazon Sagemaker Studio works. 18 | 19 | Step 1: Using your device’s command line, check out our Git repository to a local directory on your device: 20 | 21 | `git clone https://github.com/aws-samples/aws-cdk-sagemaker-studio` 22 | 23 | Step 2: Change directories to the new directory that was created during the previous step: 24 | 25 | `cd aws-cdk-sagemaker-studio/` 26 | 27 | Step 3: Create a virtual environment: 28 | 29 | `macOS/Linux: python3 -m venv .cdk-venv`
30 | `Windows: python -m venv .cdk-venv` 31 | 32 | Step 4: Activate the virtual environment after the init process completes, and the virtual environment is created: 33 | 34 | `macOS/Linux: source .cdk-venv/bin/activate`
35 | `Windows: .cdk-venv\Scripts\activate.bat` 36 | 37 | Step 5: Install the required dependencies: 38 | 39 | `pip3 install -r requirements.txt` 40 | 41 | Step 6: Synthesize the templates. AWS CDK apps use code to define the infrastructure, and when run, they produce, or 42 | “synthesize” an AWS CloudFormation template for each stack defined in the application: 43 | 44 | `cdk synthesize` 45 | 46 | Step 7: Deploy the solution. 47 | 48 | `cdk deploy sagemakerStudioCDK -c existing_vpc_id=""` 49 | 50 | Review the resources that AWS CDK creates for you in your AWS account and choose yes to deploy the stack. 51 | 52 | ![Diagram](img/aws_cdk_sagemake_studio_deploy_confimation.png) 53 | 54 | Wait for your stack to be deployed by checking the status on the AWS CloudFormation console. 55 | 56 | Enjoy! 57 | 58 | ## Useful commands 59 | 60 | * `cdk ls` list all stacks in the app 61 | * `cdk synth` emits the synthesized CloudFormation template 62 | * `cdk deploy` deploy this stack to your default AWS account/region 63 | * `cdk diff` compare deployed stack with current state 64 | * `cdk docs` open CDK documentation 65 | 66 | ## Cleanup 67 | 68 | Follow this step to remove the resources that were deployed in this post. 69 | 70 | `cdk destroy` 71 | 72 | When asked to confirm the deletion of the four stacks, select “`y`”. 73 | 74 | ## Security 75 | 76 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 77 | 78 | ## License 79 | 80 | This library is licensed under the MIT-0 License. See the LICENSE file. 81 | 82 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from aws_cdk import core 4 | 5 | from sagemakerStudioCDK.sagemaker_studio_stack import SagemakerStudioStack 6 | import os 7 | import boto3 8 | 9 | sts_client = boto3.client("sts") 10 | account_id = os.environ.get('CDK_DEFAULT_ACCOUNT', sts_client.get_caller_identity()["Account"]) 11 | region = os.environ.get('CDK_DEFAULT_REGION', 'eu-west-1') 12 | 13 | app = core.App() 14 | SagemakerStudioStack(app, "sagemakerStudioCDK", env={"account": account_id, 'region': region}) 15 | 16 | app.synth() 17 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py", 3 | "context": { 4 | "@aws-cdk/core:enableStackNameDuplicates": "true", 5 | "aws-cdk:enableDiffNoFail": "true", 6 | "@aws-cdk/core:stackRelativeExports": "true", 7 | "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, 8 | "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, 9 | "@aws-cdk/aws-kms:defaultKeyPolicies": true, 10 | "@aws-cdk/aws-s3:grantWriteWithoutAcl": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /img/aws_cdk_sagemake_studio_deploy_confimation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-sagemaker-studio/8ef49b8965d69c17af14f64fd54a0bbd8290cf38/img/aws_cdk_sagemake_studio_deploy_confimation.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -e . 2 | pytest 3 | -------------------------------------------------------------------------------- /sagemakerStudioCDK/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-sagemaker-studio/8ef49b8965d69c17af14f64fd54a0bbd8290cf38/sagemakerStudioCDK/__init__.py -------------------------------------------------------------------------------- /sagemakerStudioCDK/sagemaker_studio_stack.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | from aws_cdk import ( 5 | aws_iam as iam, 6 | aws_ec2 as ec2, 7 | core 8 | ) 9 | 10 | import sagemakerStudioConstructs 11 | 12 | 13 | class SagemakerStudioStack(core.Stack): 14 | 15 | def __init__(self, scope: core.Construct, construct_id: str, 16 | **kwargs) -> None: 17 | super().__init__(scope, construct_id, **kwargs) 18 | role_sagemaker_studio_domain = iam.Role(self, 'RoleForSagemakerStudioUsers', 19 | assumed_by=iam.ServicePrincipal('sagemaker.amazonaws.com'), 20 | role_name="RoleSagemakerStudioUsers", 21 | managed_policies=[ 22 | iam.ManagedPolicy.from_managed_policy_arn(self, 23 | id="SagemakerReadAccess", 24 | managed_policy_arn="arn:aws:iam::aws:policy/AmazonSageMakerFullAccess") 25 | ]) 26 | self.role_sagemaker_studio_domain = role_sagemaker_studio_domain 27 | self.sagemaker_domain_name = "DomainForSagemakerStudio" 28 | 29 | default_vpc_id = ec2.Vpc.from_lookup(self, "VPC", 30 | vpc_id=self.node.try_get_context('existing_vpc_id') 31 | ) 32 | 33 | self.vpc_id = default_vpc_id.vpc_id 34 | self.public_subnet_ids = [public_subnet.subnet_id for public_subnet in default_vpc_id.public_subnets] 35 | 36 | my_sagemaker_domain = sagemakerStudioConstructs.SagemakerStudioDomainConstruct(self, "mySagemakerStudioDomain", 37 | sagemaker_domain_name=self.sagemaker_domain_name, 38 | vpc_id=self.vpc_id, 39 | subnet_ids=self.public_subnet_ids, 40 | role_sagemaker_studio_users=self.role_sagemaker_studio_domain) 41 | 42 | team_to_add_in_sagemaker_studio = ["datascientist-team-A2", "datascientist-team-A3", 43 | "datascientist-team-A4"] 44 | for _team in team_to_add_in_sagemaker_studio: 45 | my_default_datascience_user = sagemakerStudioConstructs.SagemakerStudioUserConstruct(self, 46 | _team, 47 | sagemaker_domain_id=my_sagemaker_domain.sagemaker_domain_id, 48 | user_profile_name=_team) 49 | core.CfnOutput(self, f"cfnoutput{_team}", 50 | value=my_default_datascience_user.user_profile_arn, 51 | description="The User Arn TeamA domain ID", 52 | export_name=F"UserArn{_team}" 53 | ) 54 | 55 | core.CfnOutput(self, "DomainIdSagemaker", 56 | value=my_sagemaker_domain.sagemaker_domain_id, 57 | description="The sagemaker domain ID", 58 | export_name="DomainIdSagemaker" 59 | ) 60 | -------------------------------------------------------------------------------- /sagemakerStudioConstructs/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from aws_cdk import ( 4 | core, aws_iam as iam 5 | ) 6 | 7 | import aws_cdk.cloudformation_include as cfn_inc 8 | import os.path as path 9 | import typing 10 | 11 | 12 | class SagemakerStudioDomainConstruct(core.Construct): 13 | 14 | def __init__(self, scope: core.Construct, construct_id: str, *, 15 | sagemaker_domain_name: str, 16 | vpc_id: str, 17 | subnet_ids: typing.List[str], 18 | role_sagemaker_studio_users: iam.IRole, 19 | **kwargs 20 | ) -> None: 21 | super().__init__(scope, construct_id) 22 | 23 | my_sagemaker_domain = cfn_inc.CfnInclude(self, construct_id, 24 | template_file=path.join(path.dirname(path.abspath(__file__)), 25 | "sagemakerStudioCloudformationStack/sagemaker-domain-template.yaml"), 26 | parameters={ 27 | "auth_mode": "IAM", 28 | "domain_name": sagemaker_domain_name, 29 | "vpc_id": vpc_id, 30 | "subnet_ids": subnet_ids, 31 | "default_execution_role_user": role_sagemaker_studio_users.role_arn, 32 | }) 33 | self.sagemaker_domain_id = my_sagemaker_domain.get_resource('SagemakerDomainCDK').ref 34 | 35 | 36 | class SagemakerStudioUserConstruct(core.Construct): 37 | 38 | def __init__(self, scope: core.Construct, 39 | construct_id: str, *, 40 | sagemaker_domain_id: str, 41 | user_profile_name: str, 42 | **kwargs) -> None: 43 | super().__init__(scope, construct_id) 44 | 45 | my_sagemaker_studio_user_template = cfn_inc.CfnInclude(self, construct_id, 46 | template_file=path.join( 47 | path.dirname(path.abspath(__file__)), 48 | "sagemakerStudioCloudformationStack/sagemaker-user-template.yaml"), 49 | parameters={ 50 | "sagemaker_domain_id": sagemaker_domain_id, 51 | "user_profile_name": user_profile_name 52 | }, 53 | preserve_logical_ids=False) 54 | self.user_profile_arn = my_sagemaker_studio_user_template.get_resource('SagemakerUser').get_att( 55 | 'UserProfileArn').to_string() 56 | -------------------------------------------------------------------------------- /sagemakerStudioConstructs/sagemakerStudioCloudformationStack/sagemaker-domain-template.yaml: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | Parameters: 5 | auth_mode: 6 | Description: "Auth mode for Sagemaker Domain" 7 | domain_name: 8 | Description: "domain name for Sagemaker Domain" 9 | subnet_ids: 10 | Description: "subnet ids for Sagemaker Domain" 11 | vpc_id: 12 | Description: "vpc id for Sagemaker Domain" 13 | default_execution_role_user: 14 | Description: "default execution role user for Sagemaker Domain" 15 | Resources: 16 | SagemakerDomainCDK: 17 | Type: AWS::SageMaker::Domain 18 | Properties: 19 | AuthMode: !Ref auth_mode 20 | DefaultUserSettings: 21 | ExecutionRole: !Ref default_execution_role_user 22 | DomainName: !Ref domain_name 23 | SubnetIds: !Ref subnet_ids 24 | VpcId: !Ref vpc_id -------------------------------------------------------------------------------- /sagemakerStudioConstructs/sagemakerStudioCloudformationStack/sagemaker-user-template.yaml: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | Parameters: 5 | sagemaker_domain_id: 6 | Description: "Sagemaker domain id for the Sagemaker studio" 7 | user_profile_name: 8 | Description: "User profile name to add to the Sagemaker studio" 9 | 10 | Resources: 11 | SagemakerUser: 12 | Type: AWS::SageMaker::UserProfile 13 | Properties: 14 | DomainId: !Ref sagemaker_domain_id 15 | UserProfileName: !Ref user_profile_name -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | 4 | with open("README.md") as fp: 5 | long_description = fp.read() 6 | 7 | 8 | setuptools.setup( 9 | name="sagemakerStudioCDK", 10 | version="0.0.1", 11 | 12 | description="aws-cdk-sagemaker-studio", 13 | long_description=long_description, 14 | long_description_content_type="text/markdown", 15 | 16 | author="haramine", 17 | 18 | package_dir={"": "sagemakerStudioCDK"}, 19 | packages=setuptools.find_packages(where="sagemakerStudioCDK"), 20 | 21 | install_requires=[ 22 | "aws-cdk.core==1.87.1", 23 | "aws-cdk.cloudformation_include==1.87.1", 24 | "aws-cdk.aws_iam==1.87.1", 25 | "aws-cdk.aws_ec2==1.87.1", 26 | "boto3" 27 | ], 28 | 29 | python_requires=">=3.6", 30 | 31 | classifiers=[ 32 | "Development Status :: 4 - Beta", 33 | 34 | "Intended Audience :: Developers", 35 | 36 | "License :: OSI Approved :: Apache Software License", 37 | 38 | "Programming Language :: JavaScript", 39 | "Programming Language :: Python :: 3 :: Only", 40 | "Programming Language :: Python :: 3.6", 41 | "Programming Language :: Python :: 3.7", 42 | "Programming Language :: Python :: 3.8", 43 | 44 | "Topic :: Software Development :: Code Generators", 45 | "Topic :: Utilities", 46 | 47 | "Typing :: Typed", 48 | ], 49 | ) 50 | -------------------------------------------------------------------------------- /source.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem The sole purpose of this script is to make the command 4 | rem 5 | rem source .venv/bin/activate 6 | rem 7 | rem (which activates a Python virtualenv on Linux or Mac OS X) work on Windows. 8 | rem On Windows, this command just runs this batch file (the argument is ignored). 9 | rem 10 | rem Now we don't need to document a Windows command for activating a virtualenv. 11 | 12 | echo Executing .venv\Scripts\activate.bat for you 13 | .venv\Scripts\activate.bat 14 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-sagemaker-studio/8ef49b8965d69c17af14f64fd54a0bbd8290cf38/tests/__init__.py -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-cdk-sagemaker-studio/8ef49b8965d69c17af14f64fd54a0bbd8290cf38/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/test_sagemaker_studio_stack.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pytest 3 | 4 | from aws_cdk import core 5 | from sagemakerStudioCDK.sagemaker_studio_stack import SagemakerStudioStack 6 | 7 | 8 | def get_template(): 9 | app = core.App() 10 | SagemakerStudioStack(app, "sagemakerStudioCDK") 11 | return json.dumps(app.synth().get_stack("sagemakerStudioCDK").template) 12 | 13 | 14 | def test_sagemaker_domain_created(): 15 | assert("AWS::SageMaker::Domain" in get_template()) 16 | 17 | --------------------------------------------------------------------------------