From 2d3c5c422f35cdfb11cc1041b10905e07b034bf0 Mon Sep 17 00:00:00 2001 From: Anusha-janardhan Date: Thu, 30 Oct 2025 04:40:39 +0000 Subject: [PATCH 1/3] feat(settings): added settings configuration in settings-config.json to support new products fix(bootstrap): restore S3 mounts check in bootstrap script --- config/settings-config.json | 1427 ++++++++++++++---------- scripts/bootstrap-scripts/bootstrap.sh | 4 +- 2 files changed, 855 insertions(+), 576 deletions(-) diff --git a/config/settings-config.json b/config/settings-config.json index 551a263..e2833c4 100644 --- a/config/settings-config.json +++ b/config/settings-config.json @@ -1,4 +1,209 @@ { + "bedrock": { + "actions": { + "running": { + "connect": [ + { + "menu": "Open Bedrock", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [ + "BedrockExecutionRoleArn" + ] + } + ] + }, + "stopped": { + "connect": [], + "action": [] + }, + "default": { + "connect": [] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] + }, + "sagemaker-ai": { + "NotebookInstanceLifecycleConfigName": "Research-Portal-Setup", + "onStartScript": "tools/aws-scripts/sagemaker/onStart/Lifecycle_Conf.sh", + "actions": { + "running": { + "connect": [] + }, + "stopped": { + "connect": [] + }, + "default": { + "connect": [] + } + }, + "transient_states": [ + "pending", + "stopping", + "deleting" + ], + "active_states": [ + "inservice", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "deleted" + ] + }, + "aws-pcs": { + "actions": { + "running": { + "connect": [ + { + "menu": "SSH Terminal", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": ["ClusterId"] + }, + { + "menu": "Submit Job", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": ["ClusterId"] + } + ], + "action": [ + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [] + } + ] + }, + "default": { + "connect": [ + { + "menu": "SSH Terminal", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [] + }, + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png", + "outputsRequired": [] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [] + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] + }, + "ec2-remote-desktop": { + "actions": { + "running": { + "connect": [ + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png" + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "default": { + "connect": [ + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": ["running", "active"], + "stopped_states": ["stopped"], + "terminated_states": ["terminated"] + }, "sagemaker": { "NotebookInstanceLifecycleConfigName": "Research-Portal-Setup", "onStartScript": "tools/aws-scripts/sagemaker/onStart/Lifecycle_Conf.sh", @@ -58,72 +263,601 @@ "stopped" ], "terminated_states": [ - "deleted" + "deleted" + ] + }, + "s3": { + "Bucket": "research-portal-sagemaker-templates", + "notebooksDirectory": "tools/aws-scripts/s3/python-notebooks", + "actions": { + "running": { + "connect": [ + { + "menu": "Explore", + "imageUrl": "../../assets/images/direction@2x.png" + }, + { + "menu": "Link", + "imageUrl": "../../assets/images/link@2x.png" + } + ], + "action": [ + { + "action": "Share", + "imageUrl": "../../assets/images/share@2x.png" + }, + { + "action": "Unshare", + "imageUrl": "../../assets/images/unshare@2x.png" + } + ] + }, + "stopped": { + "connect": [], + "action": [] + }, + "default": { + "connect": [ + { + "menu": "Explore", + "imageUrl": "../../assets/images/direction@2x.png" + }, + { + "menu": "Link", + "imageUrl": "../../assets/images/link@2x.png" + } + ], + "action": [ + { + "action": "Share", + "imageUrl": "../../assets/images/share@2x.png" + }, + { + "action": "Upload", + "imageUrl": "../../assets/images/cloud-computing@2x.png" + } + ] + } + }, + "transient_states": [], + "active_states": [ + "active" + ], + "stopped_states": [], + "terminated_states": [ + "deleted" + ] + }, + "ec2": { + "actions": { + "running": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [ + "InstanceIPAddress", + "InstanceId" + ] + }, + { + "menu": "Explore", + "imageUrl": "../../assets/images/direction@2x.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/stop.png", + "outputsRequired": [ + "InstanceId" + ] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [ + "InstanceId" + ] + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "default": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/stop.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] + }, + "pcluster": { + "actions": { + "running": { + "connect": [ + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png", + "outputsRequired": [] + }, + { + "menu": "SSH Terminal", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png", + "outputsRequired": [] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [] + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [] + } + ] + }, + "default": { + "connect": [ + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png", + "outputsRequired": [] + }, + { + "menu": "SSH Terminal", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [] + }, + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png", + "outputsRequired": [] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [] + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] + }, + "rstudio": { + "actions": { + "running": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [ + "InstanceIPAddress", + "InstanceId" + ] + }, + { + "menu": "Open Link", + "imageUrl": "../../assets/images/link@2x.png", + "outputsRequired": [ + "InstanceDNSName", + "ApplicationPort" + ] + }, + { + "menu": "Explore", + "imageUrl": "../../assets/images/direction@2x.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/stop.png", + "outputsRequired": [ + "InstanceId" + ] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [ + "InstanceId" + ] + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "default": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/stop.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] + }, + "ec2-dcv": { + "actions": { + "running": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png" + }, + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png" + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "default": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] + }, + "nextflow": { + "actions": { + "running": { + "connect": [ + { + "menu": "SSH to Server", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [ + "InstanceIPAddress", + "InstanceId" + ] + }, + { + "menu": "Monitor Pipeline", + "imageUrl": "../../assets/images/monitor_pipeline.png", + "outputsRequired": [ + "InstanceIPAddress", + "InstanceId" + ] + }, + { + "menu": "View Outputs", + "imageUrl": "../../assets/images/view_outputs.png", + "outputsRequired": [ + "InstanceIPAddress", + "InstanceId" + ] + }, + { + "menu": "Explore", + "imageUrl": "../../assets/images/direction@2x.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/stop.png", + "outputsRequired": [ + "InstanceId" + ] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [ + "InstanceId" + ] + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] + }, + "default": { + "connect": [ + { + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/stop.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" ] }, - "s3": { - "Bucket": "research-portal-sagemaker-templates", - "notebooksDirectory": "tools/aws-scripts/s3/python-notebooks", + "ec2-secure-desktop": { "actions": { "running": { "connect": [ { - "menu": "Explore", - "imageUrl": "../../assets/images/direction@2x.png" - }, - { - "menu": "Link", - "imageUrl": "../../assets/images/link@2x.png" + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" } ], "action": [ { - "action": "Share", - "imageUrl": "../../assets/images/share@2x.png" + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" }, { - "action": "Unshare", - "imageUrl": "../../assets/images/unshare@2x.png" + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" } ] }, "stopped": { "connect": [], - "action": [] + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png" + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] + } + ] }, "default": { "connect": [ { - "menu": "Explore", - "imageUrl": "../../assets/images/direction@2x.png" - }, - { - "menu": "Link", - "imageUrl": "../../assets/images/link@2x.png" + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" } ], "action": [ { - "action": "Share", - "imageUrl": "../../assets/images/share@2x.png" + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" }, { - "action": "Upload", - "imageUrl": "../../assets/images/cloud-computing@2x.png" + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" } ] } }, - "transient_states": [], + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], "active_states": [ + "running", "active" ], - "stopped_states": [], + "stopped_states": [ + "stopped" + ], "terminated_states": [ - "deleted" + "terminated" ] }, - "ec2": { + "ec2-jupyterlab": { "actions": { "running": { "connect": [ @@ -135,6 +869,14 @@ "InstanceId" ] }, + { + "menu": "Open Link", + "imageUrl": "../../assets/images/link@2x.png", + "outputsRequired": [ + "InstanceDNSName", + "ApplicationPort" + ] + }, { "menu": "Explore", "imageUrl": "../../assets/images/direction@2x.png", @@ -169,9 +911,11 @@ ] }, { - "action":"Instance Type", + "action": "Instance Type", "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] + "outputsRequired": [ + "InstanceId" + ] } ] }, @@ -211,95 +955,8 @@ "terminated" ] }, - "pcluster": { + "ec2-vscode": { "actions": { - "running": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png", - "outputsRequired": [] - }, - { - "menu": "SSH Terminal", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": [] - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png", - "outputsRequired": [] - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png", - "outputsRequired": [] - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png", - "outputsRequired": [] - } - ] - }, - "default": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png", - "outputsRequired": [] - }, - { - "menu": "SSH Terminal", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": [] - } - ], - "action": [ - { - "action":"Start", - "imageUrl": "../../assets/images/play@2x.png", - "outputsRequired": [] - }, - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png", - "outputsRequired": [] - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png", - "outputsRequired": [] - } - ] - } - }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": [ - "running", - "active" - ], - "stopped_states": [ - "stopped" - ], - "terminated_states": [ - "terminated" - ] -}, -"rstudio": { - "actions": { "running": { "connect": [ { @@ -352,9 +1009,11 @@ ] }, { - "action":"Instance Type", + "action": "Instance Type", "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] + "outputsRequired": [ + "InstanceId" + ] } ] }, @@ -394,116 +1053,103 @@ "terminated" ] }, - "ec2-dcv":{ + "ec2-igv": { "actions": { - "running" : { - "connect":[ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png" - }, + "running": { + "connect": [ { "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png" + "imageUrl": "./../assets/images/Screen-icon.png" } ], - "action":[ - { - "action":"Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action":"Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] }, "stopped": { - "connect":[], - "action":[ + "connect": [], + "action": [ { - "action":"Start", - "imageUrl": "../../assets/images/play@2x.png" + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png" }, { - "action":"Instance Type", + "action": "Instance Type", "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] + "outputsRequired": [ + "InstanceId" + ] } ] }, - "default" : { - "connect":[ + "default": { + "connect": [ { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png" + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" } ], - "action":[ - { - "action":"Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action":"Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] } }, - "transient_states": ["pending", "shutting-down", "stopping", "deleting"], - "active_states": ["running", "active"], - "stopped_states":["stopped"], - "terminated_states": ["terminated"] + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] }, - "nextflow": { + "cromwell": { "actions": { "running": { "connect": [ { - "menu": "SSH to Server", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": [ - "InstanceIPAddress", - "InstanceId" - ] - }, - { - "menu": "Monitor Pipeline", - "imageUrl": "../../assets/images/monitor_pipeline.png", - "outputsRequired": [ - "InstanceIPAddress", - "InstanceId" - ] + "menu": "SSH/RDP", + "imageUrl": "../../assets/images/technology@2x.png" }, { "menu": "View Outputs", - "imageUrl": "../../assets/images/view_outputs.png", + "imageUrl": "../../assets/images/link@2x.png", "outputsRequired": [ "InstanceIPAddress", "InstanceId" ] - }, - { - "menu": "Explore", - "imageUrl": "../../assets/images/direction@2x.png", - "outputsRequired": [] } ], "action": [ { "action": "Stop", - "imageUrl": "../../assets/images/stop.png", - "outputsRequired": [ - "InstanceId" - ] + "imageUrl": "../../assets/images/stop.png" }, { "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png", - "outputsRequired": [ - "InstanceId" - ] + "imageUrl": "../../assets/images/reset@2x.png" } ] }, @@ -512,15 +1158,14 @@ "action": [ { "action": "Start", - "imageUrl": "../../assets/images/play@2x.png", - "outputsRequired": [ - "InstanceId" - ] + "imageUrl": "../../assets/images/play@2x.png" }, { - "action":"Instance Type", + "action": "Instance Type", "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] + "outputsRequired": [ + "InstanceId" + ] } ] }, @@ -560,377 +1205,6 @@ "terminated" ] }, - "ec2-secure-desktop": { - "actions": { - "running": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png" - }, - { - "action":"Instance Type", - "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "default": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - } - }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": ["running", "active"], - "stopped_states": ["stopped"], - "terminated_states": ["terminated"] -}, -"ec2-jupyterlab": { - "actions": { - "running": { - "connect": [ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": ["InstanceIPAddress", "InstanceId"] - }, - { - "menu": "Open Link", - "imageUrl": "../../assets/images/link@2x.png", - "outputsRequired": [ - "InstanceDNSName", - "ApplicationPort" - ] - }, - { - "menu": "Explore", - "imageUrl": "../../assets/images/direction@2x.png", - "outputsRequired": [] - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/stop.png", - "outputsRequired": ["InstanceId"] - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png", - "outputsRequired": ["InstanceId"] - }, - { - "action": "Instance Type", - "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "default": { - "connect": [ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/stop.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - } - }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": ["running", "active"], - "stopped_states": ["stopped"], - "terminated_states": ["terminated"] -}, -"ec2-vscode": { - "actions": { - "running": { - "connect": [ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": ["InstanceIPAddress", "InstanceId"] - }, - { - "menu": "Open Link", - "imageUrl": "../../assets/images/link@2x.png", - "outputsRequired": [ - "InstanceDNSName", - "ApplicationPort" - ] - }, - { - "menu": "Explore", - "imageUrl": "../../assets/images/direction@2x.png", - "outputsRequired": [] - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/stop.png", - "outputsRequired": ["InstanceId"] - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png", - "outputsRequired": ["InstanceId"] - }, - { - "action": "Instance Type", - "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "default": { - "connect": [ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/stop.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - } - }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": ["running", "active"], - "stopped_states": ["stopped"], - "terminated_states": ["terminated"] -}, -"ec2-igv": { - "actions": { - "running": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "./../assets/images/Screen-icon.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png" - }, - { - "action":"Instance Type", - "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "default": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - } - }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": [ - "running", - "active" - ], - "stopped_states": [ - "stopped" - ], - "terminated_states": [ - "terminated" - ] -}, - "cromwell": { - "actions": { - "running": { - "connect": [ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png" - }, - { - "menu": "View Outputs", - "imageUrl": "../../assets/images/link@2x.png", - "outputsRequired": [ - "InstanceIPAddress", - "InstanceId" - ] - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/stop.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png" - }, - { - "action":"Instance Type", - "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": ["InstanceId"] - } - ] - }, - "default": { - "connect": [ - { - "menu": "SSH/RDP", - "imageUrl": "../../assets/images/technology@2x.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/stop.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - } - }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": [ - "running", - "active" - ], - "stopped_states": [ - "stopped" - ], - "terminated_states": [ - "terminated" - ] -}, "wordpress": { "actions": { "running": { @@ -1088,7 +1362,7 @@ "action": [] }, "internal": { - "connect":[ + "connect": [ { "menu": "Explore", "imageUrl": "../../assets/images/direction@2x.png" @@ -1098,7 +1372,7 @@ "imageUrl": "../../assets/images/link@2x.png" } ], - "action":[ + "action": [ { "action": "Edit", "imageUrl": "../../assets/images/editStudy.png" @@ -1228,11 +1502,16 @@ "cromwell", "pcluster", "ec2-dcv", - "ec2-igv", + "bedrock", + "sagemaker-ai", + "aws-pcs", + "ec2-remote-desktop", + "ec2-spyder", + "sagemaker-studio", + "ec2-igv", "ec2-secure-desktop", "ec2-vscode", "ec2-jupyterlab" - ], "cft_active_states": [ "available", @@ -1257,4 +1536,4 @@ "PLAN_IN_PROGRESS" ], "s3FileSizeMaxLimit": "5368709120" -} +} \ No newline at end of file diff --git a/scripts/bootstrap-scripts/bootstrap.sh b/scripts/bootstrap-scripts/bootstrap.sh index eac71fe..96cbc85 100644 --- a/scripts/bootstrap-scripts/bootstrap.sh +++ b/scripts/bootstrap-scripts/bootstrap.sh @@ -9,8 +9,6 @@ S3_MOUNTS="$1" RSTUDIO_USER="$2" -# Exit if no S3 mounts were specified -[ -z "$S3_MOUNTS" -o "$S3_MOUNTS" = "[]" ] && exit 0 # Get directory in which this script is stored and define URL from which to download goofys FILES_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" @@ -88,6 +86,8 @@ sudo yum install ec2-instance-connect-1.1 echo "Mounting S3" chmod +x "${FILES_DIR}/bin/mount_s3.sh" ln -s "${FILES_DIR}/bin/mount_s3.sh" "/usr/local/bin/mount_s3.sh" +# Exit if no S3 mounts were specified +[ -z "$S3_MOUNTS" -o "$S3_MOUNTS" = "[]" ] && exit 0 printf "%s" "$S3_MOUNTS" > "/usr/local/etc/s3-mounts.json" echo "Finish mounting S3" From 02b012d97c8dbbc1dbf637d30439e93ad318b2cb Mon Sep 17 00:00:00 2001 From: Anusha-janardhan Date: Fri, 31 Oct 2025 05:55:01 +0000 Subject: [PATCH 2/3] feat: update standard catalog items and config.json with latest configurations --- cft-templates/awsSagemakerDomainAI.yaml | 67 +++ cft-templates/bedrock.yaml | 101 ++++ cft-templates/ec2-nginxWebServer.yml | 141 +++++ cft-templates/ec2-rockyLinux.yml | 379 ++++++++++++++ cft-templates/pcs.yaml | 650 ++++++++++++++++++++++++ cft-templates/pcs_quick_lt.yaml | 570 +++++++++++++++++++++ cft-templates/sagemakerUserProfile.yaml | 497 ++++++++++++++++++ cft-templates/windows-remotedesktop.yml | 144 ++++++ dump/configs.json | 147 +++++- dump/standardcatalogitems.json | 611 +++++++++++++++++++++- 10 files changed, 3300 insertions(+), 7 deletions(-) create mode 100644 cft-templates/awsSagemakerDomainAI.yaml create mode 100644 cft-templates/bedrock.yaml create mode 100644 cft-templates/ec2-nginxWebServer.yml create mode 100644 cft-templates/ec2-rockyLinux.yml create mode 100644 cft-templates/pcs.yaml create mode 100644 cft-templates/pcs_quick_lt.yaml create mode 100644 cft-templates/sagemakerUserProfile.yaml create mode 100644 cft-templates/windows-remotedesktop.yml diff --git a/cft-templates/awsSagemakerDomainAI.yaml b/cft-templates/awsSagemakerDomainAI.yaml new file mode 100644 index 0000000..c5dba42 --- /dev/null +++ b/cft-templates/awsSagemakerDomainAI.yaml @@ -0,0 +1,67 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: > + CloudFormation template to create a SageMaker Domain + with an IAM execution role. Applies project_name tag. + +Parameters: + Namespace: + Type: String + Description: An environment name that will be prefixed to resource names + VpcId: + Type: AWS::EC2::VPC::Id + Description: VPC where SageMaker domain will be created. + SubnetId: + Type: AWS::EC2::Subnet::Id + Description: Subnet for the SageMaker domain. + ProjectId: + Description: Project Id that will be added as tag to the resources. + Type: String + + +Resources: + SageMakerExecutionRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub "${Namespace}-SageMakerExecutionRole" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: sagemaker.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess + - arn:aws:iam::aws:policy/AmazonS3FullAccess + Tags: + - Key: project_name + Value: !Ref ProjectId + - Key: cost_resource + Value: !Ref "AWS::StackName" + + + SageMakerDomain: + Type: AWS::SageMaker::Domain + Properties: + AuthMode: IAM + DomainName: !Sub "${Namespace}-sagemaker-domain" + DefaultUserSettings: + ExecutionRole: !GetAtt SageMakerExecutionRole.Arn + SubnetIds: + - !Ref SubnetId + VpcId: !Ref VpcId + Tags: + - Key: project_name + Value: !Ref ProjectId + - Key: cost_resource + Value: !Ref "AWS::StackName" + + +Outputs: + SageMakerDomainId: + Description: ID of the created SageMaker Domain + Value: !Ref SageMakerDomain + + SageMakerExecutionRoleArn: + Description: IAM role created for SageMaker + Value: !GetAtt SageMakerExecutionRole.Arn diff --git a/cft-templates/bedrock.yaml b/cft-templates/bedrock.yaml new file mode 100644 index 0000000..f1e1a10 --- /dev/null +++ b/cft-templates/bedrock.yaml @@ -0,0 +1,101 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: > + CloudFormation template to create a Bedrock Execution Role + with a dummy parameter and a no-op resource for stack completion. + +Parameters: + EnvironmentName: + Type: String + Default: dev + Description: Environment name (e.g., dev, qa, prod) + +Resources: + # Dummy Resource (no functional purpose, just to ensure a complete stack) + DummyResource: + Type: AWS::CloudFormation::WaitConditionHandle + + # Bedrock Execution Role + BedrockExecutionRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub "${AWS::StackName}-bedrock-execution-role" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: bedrock.amazonaws.com + Action: sts:AssumeRole + - Effect: Allow + Principal: + AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" + Action: + - sts:AssumeRole + - sts:TagSession + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AmazonBedrockFullAccess + - arn:aws:iam::aws:policy/AmazonS3FullAccess + Policies: + - PolicyName: BedrockExecutionRolePolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "bedrock:*" + Resource: "*" + - Effect: Allow + Action: + - "s3:GetObject" + - "s3:PutObject" + - "s3:DeleteObject" + - "s3:ListBucket" + Resource: "*" + - Effect: Allow + Action: + - "s3vectors:*" + Resource: "*" + - Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: "*" + - Effect: Allow + Action: + - "iam:CreateRole" + - "iam:AttachRolePolicy" + - "iam:PutRolePolicy" + - "lambda:ListFunctions" + - "lambda:GetFunction" + - "lambda:InvokeFunction" + - "iam:CreateRole" + - "iam:GetRole" + - "iam:PassRole" + - "iam:ListAttachedRolePolicies" + Resource: "*" + - Effect: Allow + Action: + - "aoss:CreateCollection" + - "aoss:ListCollections" + - "aoss:BatchGetCollection" + - "aoss:DeleteCollection" + - "aoss:CreateAccessPolicy" + - "aoss:GetAccessPolicy" + - "aoss:ListAccessPolicies" + - "aoss:UpdateAccessPolicy" + - "aoss:DeleteAccessPolicy" + - "aoss:CreateSecurityPolicy" + - "aoss:GetSecurityPolicy" + - "aoss:ListSecurityPolicies" + - "aoss:UpdateSecurityPolicy" + - "aoss:DeleteSecurityPolicy" + Resource: "*" + +Outputs: + BedrockExecutionRoleArn: + Description: ARN of the created Bedrock Execution Role + Value: !GetAtt BedrockExecutionRole.Arn + Export: + Name: !Sub "${AWS::StackName}-BedrockExecutionRoleArn" + diff --git a/cft-templates/ec2-nginxWebServer.yml b/cft-templates/ec2-nginxWebServer.yml new file mode 100644 index 0000000..166d3d8 --- /dev/null +++ b/cft-templates/ec2-nginxWebServer.yml @@ -0,0 +1,141 @@ +Metadata: + License: Apache-2.0 +AWSTemplateFormatVersion: '2010-09-09' +Description: 'AWS CloudFormation Template to create an EC2 instance + **WARNING** This template creates an Amazon EC2 instance and an Elastic IP Address. + You will be billed for the AWS resources used if you create a stack from this template.' + +Parameters: + Namespace: + Type: String + Description: An environment name that will be prefixed to resource names + S3Mounts: + Type: String + Description: A JSON array of objects with name, bucket, and prefix properties used to mount data + IamPolicyDocument: + Type: String + Description: The IAM policy to be associated with the launched workstation + EnvironmentInstanceFiles: + Type: String + Description: >- + An S3 URI (starting with "s3://") that specifies the location of files to be copied to + the environment instance, including any bootstrap scripts + InstanceType: + Description: Choose the instance type e.g t3.small (2vCPU , 2GiB RAM) t3.medium (2vCPU , 4GiB RAM), t3.large (2vCPU, 8GiB RAM). + Type: String + Default: t3.small + AllowedValues: [t3.small, t3.medium, t3.large] + ConstraintDescription: must be a valid EC2 instance type. + EBSVolumeSize: + Description: The initial size of the volume (in GBs) EBS will use for storage. + Type: Number + Default: 8 + KeyPair: + Description: Name of an existing EC2 KeyPair to enable SSH access to the instance. If no key pairs exist, please create one from the button next to the dropdown. Please contact your Administrator if you are unable to create one. + Type: AWS::EC2::KeyPair::KeyName + ConstraintDescription: must be the name of an existing EC2 KeyPair. + AllowedSSHLocation: + Description: The IP address range that can be used to SSH to the EC2 instances + Type: String + MinLength: '9' + MaxLength: '18' + Default: 0.0.0.0/0 + AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) + ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. + LatestAmiId: + Type: 'AWS::SSM::Parameter::Value' + Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' + AvailabilityZone: + Description: Select the availability zone in which to create the instance. If you plan to attach a secondary volume to the instance, create this instance in the same AvailabilityZone as the volume you created. + Type: AWS::EC2::AvailabilityZone::Name + +Conditions: + IamPolicyEmpty: !Equals [!Ref IamPolicyDocument, '{}'] + +Resources: + IAMRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: !Join ['-', [Ref: Namespace, 'ec2-role']] + Path: '/' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'ec2.amazonaws.com' + Action: + - 'sts:AssumeRole' + Policies: + - !If + - IamPolicyEmpty + - !Ref 'AWS::NoValue' + - PolicyName: !Join ['-', [Ref: Namespace, 's3-studydata-policy']] + PolicyDocument: !Ref IamPolicyDocument + + InstanceProfile: + Type: 'AWS::IAM::InstanceProfile' + Properties: + InstanceProfileName: !Join ['-', [Ref: Namespace, 'ec2-profile']] + Path: '/' + Roles: + - Ref: IAMRole + + EC2Instance: + Type: AWS::EC2::Instance + Properties: + UserData: + Fn::Base64: !Sub | + #!/usr/bin/env bash + exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 + # Download and execute bootstrap script + aws s3 cp "${EnvironmentInstanceFiles}/get_bootstrap.sh" "/tmp" + chmod 500 "/tmp/get_bootstrap.sh" + /tmp/get_bootstrap.sh "${EnvironmentInstanceFiles}" '${S3Mounts}' + + # Signal result to CloudFormation + /opt/aws/bin/cfn-signal -e $? --stack "${AWS::StackName}" --resource "EC2Instance" --region "${AWS::Region}" + InstanceType: !Ref 'InstanceType' + AvailabilityZone: !Ref AvailabilityZone + SecurityGroups: [!Ref 'InstanceSecurityGroup'] + KeyName: !Ref 'KeyPair' + ImageId: !Ref 'LatestAmiId' + IamInstanceProfile: !Ref InstanceProfile + PropagateTagsToVolumeOnCreation: true + BlockDeviceMappings: + - DeviceName: /dev/xvda + Ebs: + VolumeSize: !Ref EBSVolumeSize + Encrypted: true + Tags: + - Key: Name + Value: !Join ['-', [Ref: Namespace, 'ec2-linux']] + - Key: Description + Value: EC2 workspace instance + - Key: cost_resource + Value: !Sub ${AWS::StackName} + + InstanceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Enable SSH access + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '22' + ToPort: '22' + CidrIp: !Ref 'AllowedSSHLocation' + +Outputs: + InstanceId: + Description: InstanceId of the newly created EC2 instance + Value: !Ref 'EC2Instance' + InstanceIPAddress: + Description: IP address of the newly created EC2 instance + Value: !GetAtt [EC2Instance, PublicIp] + InstanceDNSName: + Description: DNS name of the newly created EC2 instance + Value: !GetAtt [EC2Instance, PublicDnsName] + AvailabilityZone: + Description: AvailabilityZone of newly created EC2 instance + Value: !Ref AvailabilityZone \ No newline at end of file diff --git a/cft-templates/ec2-rockyLinux.yml b/cft-templates/ec2-rockyLinux.yml new file mode 100644 index 0000000..689fab4 --- /dev/null +++ b/cft-templates/ec2-rockyLinux.yml @@ -0,0 +1,379 @@ +Metadata: + License: Apache-2.0 +AWSTemplateFormatVersion: '2010-09-09' +Description: 'AWS CloudFormation Template to create an GPU based EC2 instance with NICE DCV pre installed.' + +Parameters: + Namespace: + Type: String + Description: An environment name that will be prefixed to resource names + S3Mounts: + Type: String + Description: A JSON array of objects with name, bucket, and prefix properties used to mount data + IamPolicyDocument: + Type: String + Description: The IAM policy to be associated with the launched workstation + EnvironmentInstanceFiles: + Type: String + Description: >- + An S3 URI (starting with "s3://") that specifies the location of files to be copied to + the environment instance, including any bootstrap scripts + InstanceType: + Description: Choose the instance type e.g t3.medium (2vCPU , 2GiB RAM), t3.large (2vCPU, 8GiB RAM), t3.xlarge(4vCPU, 16GiB RAM) + Type: String + Default: t3.large + AllowedValues: + [ + t3.medium, + t3.large, + t3.xlarge, + g4dn.2xlarge + + ] + ConstraintDescription: must be a valid EC2 instance type. + EBSVolumeSize: + Description: The initial size of the volume (in GBs) EBS will use for storage. + Type: Number + Default: 120 + KeyPair: + Description: Name of an existing EC2 KeyPair to enable SSH access to the instance. If no key pairs exist, please create one from the button next to the dropdown. Please contact your Administrator if you are unable to create one. + Type: AWS::EC2::KeyPair::KeyName + ConstraintDescription: Must be the name of an existing EC2 KeyPair. + AllowedIpAddress: + Description: The IP address range that can be used to SSH to instance and Connect to DCV + Type: String + MinLength: '9' + MaxLength: '18' + Default: 0.0.0.0/0 + AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) + ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. + +Conditions: + IamPolicyEmpty: !Equals [!Ref IamPolicyDocument, "{}"] + +Resources: + SSMPolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + ManagedPolicyName: !Join ["-", [Ref: Namespace, "SSM-Policy"]] + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowSSMParamActions + Effect: Allow + Action: + - ssm:GetParameter + - ssm:PutParameter + - ssm:DescribeParameters + Resource: "*" + - Sid: AllowAccessToEncryptionKeys + Effect: Allow + Action: + - kms:Decrypt + - kms:Encrypt + - kms:GenerateDataKey + - kms:DescribeKey + Resource: "*" + - Sid: AllowS3AccessToDCVLicenceServer + Effect: Allow + Action: + - s3:GetObject + Resource: + - arn:aws:s3:::dcv-license.us-east-1/* + IAMRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: !Join ['-', [Ref: Namespace, 'ec2-role']] + Path: '/' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'ec2.amazonaws.com' + Action: + - 'sts:AssumeRole' + Policies: + - !If + - IamPolicyEmpty + - !Ref 'AWS::NoValue' + - PolicyName: !Join ['-', [Ref: Namespace, 's3-studydata-policy']] + PolicyDocument: !Ref IamPolicyDocument + ManagedPolicyArns: + - Ref: SSMPolicy + - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore + + InstanceProfile: + Type: "AWS::IAM::InstanceProfile" + Properties: + InstanceProfileName: !Join ["-", [Ref: Namespace, "ec2-profile"]] + Path: "/" + Roles: + - Ref: IAMRole + + EC2Instance: + Type: AWS::EC2::Instance + CreationPolicy: + ResourceSignal: + Timeout: PT15M + Metadata: + AWS::CloudFormation::Init: + configSets: + default: + - config1 + - config2 + config1: + files: + "/home/ec2-user/.config/autostart/studymount.desktop": + mode: "000644" + owner: "ec2-user" + group: "ec2-user" + content: | + [Desktop Entry] + Type=Application + Exec="/home/ec2-user/mount_study.sh" + Hidden=false + NoDisplay=false + X-GNOME-Autostart-enabled=true + Terminal=true + Name=Study-Mounting + Comment=Study Mounting + "/home/ec2-user/.config/autostart/jupyter.desktop": + mode: "000644" + owner: "ec2-user" + group: "ec2-user" + content: | + [Desktop Entry] + Type=Application + Exec="/home/ec2-user/jupyter.sh" + Hidden=false + NoDisplay=false + X-GNOME-Autostart-enabled=true + Terminal=true + Name=JupyterLab + Comment=Icon for Jupyter + "/home/ec2-user/.config/autostart/rstudio.desktop": + mode: "000644" + owner: "ec2-user" + group: "ec2-user" + content: | + [Desktop Entry] + Type=Application + Exec="/home/ec2-user/rstudio.sh" + Hidden=false + NoDisplay=false + X-GNOME-Autostart-enabled=true + Terminal=true + Name=rstudio-server + Comment=Icon for rstudio + "/home/ec2-user/rstudio.sh": + mode: "000755" + owner: "ec2-user" + group: "ec2-user" + content: !Sub | + #!/bin/bash + url="http://localhost:8787/" + link_name="RStudio" + custom_icon="/home/ec2-user/logos/black.png" + mkdir -p $HOME/Desktop + desktop_file="$HOME/Desktop/rstudio.desktop" + cat > "$desktop_file" <&1 | grep token | awk '{print $2}' | sed 's/.*=//') + if [ -n "$jtoken" ]; then + echo "Token value: $jtoken" + else + echo "Error: Unable to retrieve the Jupyter token." + fi + url="http://127.0.0.1:8888/?token=$jtoken" + firefox $url + "/usr/share/applications/jupyter.desktop": + mode: "000755" + owner: "root" + group: "root" + content: !Sub | + [Desktop Entry] + Name=Jupyter Notebook + Type=Application + Exec=/home/ec2-user/Jupyter.sh + "/usr/share/applications/rstudio.desktop": + mode: "000755" + owner: "root" + group: "root" + content: !Sub | + [Desktop Entry] + Name=RStudio + Type=Application + Exec= firefox "http://localhost:8787/" + "/home/ec2-user/mount_study.sh": + mode: "000755" + owner: "ec2-user" + group: "ec2-user" + content: !Sub | + #!/bin/sh + set -x + # Adding sleep to avoid mounting failure + sleep 30 + mount_s3.sh 2>&1 >> /home/ec2-user/mount_s3.log + "/home/ec2-user/set_user_token.sh": + mode: "000755" + owner: "ec2-user" + group: "ec2-user" + content: !Sub | + #!/bin/bash + trap '/opt/aws/bin/cfn-signal --exit-code 1 --resource EC2Instance --region ${AWS::Region} --stack ${AWS::StackName}' ERR + region=$(curl -s "http://169.254.169.254/latest/meta-data/placement/region") + instance_id=$(curl -s "http://169.254.169.254/latest/meta-data/instance-id") + session_id="rg-session" + auth_token=`uuidgen` + parameter_name="/RL/RG/nice-dcv/auth-token/$instance_id" + aws ssm put-parameter --name "$parameter_name" --type "String" --value '{"auth_token":"'$auth_token'","session_id":"'$session_id'"}' --region $region --overwrite + echo "User token set successfully" + "/usr/local/bin/start-dcv-session": + mode: "000775" + owner: "root" + group: "root" + content: !Sub | + #!/bin/bash + systemctl isolate multi-user.target + sleep 10 + # Switch to graphical.target to enable graphical operations + systemctl isolate graphical.target + sleep 30 + DISPLAY=:0 dcvxgrantaccess +dcv + # Grant access to the X server + docker kill dcv-custom-auth-svc + sleep 10 + docker run --restart always --name dcv-custom-auth-svc -d --replace -p 0.0.0.0:8445:8445 --network host -e PORT=8445 -e PARAMNAMEPREFIX=/RL/RG/nice-dcv/auth-token/ docker.io/relevancelab/nice-dcv-auth-svc:latest + systemctl start dcvserver + dcv create-session rg-session --name rg-session --user ec2-user --owner ec2-user --type=virtual + dcv list-sessions + date + + + config2: + commands: + 01_set_user_token: + cwd: "/home/ec2-user" + command: "/home/ec2-user/set_user_token.sh" + + Properties: + UserData: + Fn::Base64: !Sub | + #!/usr/bin/env bash + exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 + #trap '/opt/aws/bin/cfn-signal --exit-code 1 --resource EC2Instance --region ${AWS::Region} --stack ${AWS::StackName}' ERR + systemctl enable amazon-ssm-agent + systemctl start amazon-ssm-agent + + systemctl stop firewalld + systemctl disable firewalld + mypassword="TridentDecibel-PassionScenic2025" + + sudo adduser ec2-user sudo + mv /home/rocky/ParaView-5.8.1-MPI-Linux-Python2.7-64bit/ /home/ec2-user/ + chown -R ec2-user:ec2-user ParaView-5.8.1-MPI-Linux-Python2.7-64bit/ + # Permission changes for Python package download + echo "Modifying permissions to enable python package downloads" + chown -R ec2-user:ec2-user /usr/local/lib/python3* + chown -R ec2-user:ec2-user /usr/local/lib64/ + chown -R ec2-user:ec2-user /usr/local/bin/ + alternatives --set python /usr/bin/python3 + ln -s /usr/bin/pip3 /usr/bin/pip + echo 'export PATH="$HOME/.local/bin:$PATH"' >> /home/ec2-user/.bashrc + chown ec2-user:ec2-user /home/ec2-user/.bashrc + + # Copy environment instance files needed for the workspace + aws s3 cp --region "${AWS::Region}" "${EnvironmentInstanceFiles}/get_bootstrap.sh" "/tmp" + chmod 500 "/tmp/get_bootstrap.sh" + /tmp/get_bootstrap.sh "${EnvironmentInstanceFiles}" '${S3Mounts}' "${AWS::Region}" + + # Run init script to create files + /opt/aws/bin/cfn-init --verbose --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region} + + # Route auth request to external authenticator and restart dcv + sed -i -e 's/^#auth-token-verifier/auth-token-verifier/' -e '/auth-token-verifier/ s/8444/8445/' -e '/auth-token-verifier/ s/https/http/' /etc/dcv/dcv.conf + sed -i -e 's/^#create-session/create-session/' -e '/create-session/ s/true/false/' /etc/dcv/dcv.conf + sh "/usr/local/bin/start-dcv-session" + + docker run --restart always -d -e DISABLE_AUTH=true -v /home/ec2-user:/home/ec2-user -p 8787:8787 relevancelab/rstudio_4.2.1:1.0.3 + docker run -d --restart always --name jupyterlab -p 8888:8888 -v /home/ec2-user:/home/ec2-user relevancelab/jupiterlab_3.5.0:1.0.3 + + echo "Rebooting after configuration changes..." + reboot + + # Add command to start on reboot + crontab -l 2>/dev/null > "/tmp/crontab" + echo '@reboot /usr/local/bin/start-dcv-session 2>&1 >> /var/log/start-dcv-session.log' >> "/tmp/crontab" + echo '@reboot /home/ec2-user/set_user_token.sh 2>&1 >> /var/log/set_user_token.log' >> "/tmp/crontab" + crontab "/tmp/crontab" + + # Set password for ec2-user + echo "ec2-user:$mypassword" | sudo chpasswd + echo "User data script complete. Sending cfn-signal" + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region} + InstanceType: !Ref "InstanceType" + SecurityGroups: [!Ref 'InstanceSecurityGroup'] + KeyName: !Ref 'KeyPair' + ImageId: "{{resolve:ssm:/RL/RG/StandardCatalog/rocky-nice-dcv-ami}}" + IamInstanceProfile: !Ref InstanceProfile + BlockDeviceMappings: + - DeviceName: /dev/sda1 + Ebs: + VolumeSize: !Ref EBSVolumeSize + Encrypted: true + + PropagateTagsToVolumeOnCreation: true + Tags: + - Key: Name + Value: !Join ["-", [Ref: Namespace, "ec2-linux"]] + - Key: Description + Value: EC2 workspace instance + - Key: cost_resource + Value: !Sub ${AWS::StackName} + + InstanceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Enable SSH access + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '22' + ToPort: '22' + CidrIp: !Ref 'AllowedIpAddress' + - IpProtocol: tcp + FromPort: '8443' + ToPort: '8443' + CidrIp: !Ref 'AllowedIpAddress' + +Outputs: + InstanceId: + Description: InstanceId of the newly created EC2 instance + Value: !Ref "EC2Instance" + InstanceIPAddress: + Description: IP address of the newly created EC2 instance + Value: !GetAtt [EC2Instance, PublicIp] + InstanceDNSName: + Description: DNS name of the newly created EC2 instance + Value: !GetAtt [EC2Instance, PublicDnsName] + ApplicationPort: + Description: The Port in which the application is running + Value: "8443" + AvailabilityZone: + Description: AvailabilityZone of newly created EC2 instance + Value: !GetAtt [EC2Instance, AvailabilityZone] \ No newline at end of file diff --git a/cft-templates/pcs.yaml b/cft-templates/pcs.yaml new file mode 100644 index 0000000..c2208c0 --- /dev/null +++ b/cft-templates/pcs.yaml @@ -0,0 +1,650 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: AWS PCS "Getting Started" cluster. This template deploys a small HPC cluster with 1 login node and up to 4 compute nodes. Optionally, Slurm accounting can be enabled. It includes an EFS file system for shared storage and an FSx for Lustre file system for high-speed temporary storage. The cluster is deployed in a new VPC with both public and private subnets. It can be accessed via the browser using AWS Systems Manager Session Manager or over the internet via SSH. To access the cluster, check the Outputs tab of this stack for relevant links. + +### Stack metadata +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: PCS Cluster configuration + Parameters: + - AmiId + - SlurmVersion + - SlurmControllerSize + - ManagedAccounting + - AccountingPolicyEnforcement + + - Label: + default: Node Architecture + Parameters: + - NodeArchitecture + + - Label: + default: Login Node Configuration + Parameters: + - KeyName + - ClientIpCidr + - LoginInstanceType + + - Label: + default: Compute Node Configuration + Parameters: + - ComputeInstanceType + - MinInstanceCount + - MaxInstanceCount + - ComputeNodeType + + - Label: + default: File system configuration + Parameters: + - EfsFilesystemId + - FSxLustreFilesystemId + + - Label: + default: Network Configuration + Parameters: + - VPC + - DefaultPrivateSubnet + - SecurityGroup + - DefaultPublicSubnet + + + +Parameters: + NodeArchitecture: + Type: String + Default: x86 + AllowedValues: + - x86 + - Graviton + Description: Processor architecture for the login and compute node instances + + SlurmVersion: + Type: String + Default: 24.11 + Description: Version of Slurm to use + AllowedValues: + - 24.05 + - 24.11 + - 23.11 + SlurmControllerSize: + Type: String + Default: Small + Description: Choose slurm controller size + AllowedValues: + - Small + - Medium + - Large + + ManagedAccounting: + Type: String + Default: 'disabled' + AllowedValues: + - 'enabled' + - 'disabled' + Description: Monitor cluster usage, manage access control, and enforce resource limits with Slurm accounting. Requires Slurm 24.11 or newer. + + AccountingPolicyEnforcement: + Description: Specify which Slurm accounting policies to enforce + Type: String + Default: none + AllowedValues: + - none + - 'associations,limits,safe' + + KeyName: + Description: SSH keypair to log in to the head node + Type: AWS::EC2::KeyPair::KeyName + AllowedPattern: ".+" # Required + + ClientIpCidr: + Description: IP(s) allowed to access the login node over SSH. We recommend that you restrict it with your own IP/subnet (x.x.x.x/32 for your own ip or x.x.x.x/24 for range. Replace x.x.x.x with your own PUBLIC IP. You can get your public IP using tools such as https://ifconfig.co/) + Default: 0.0.0.0/0 + Type: String + AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) + ConstraintDescription: Value must be a valid IP or network range of the form x.x.x.x/x. + + + LoginInstanceType: + Description: Choose the instance type for the Login Node + Type: String + Default: g4dn.2xlarge + AllowedValues: + - t3.2xlarge + - c5.xlarge + - c5.2xlarge + - g4dn.2xlarge + + + ComputeInstanceType: + Description: Choose the instance type for the Compute Nodes + Type: String + Default: g4dn.2xlarge + AllowedValues: + - c5.large + - c5.xlarge + - c5.2xlarge + - g4dn.2xlarge + - p3.2xlarge + + ComputeNodeType: + Type: String + Default: OnDemand + Description: Select whether to use On-Demand or Spot instances for compute nodes + AllowedValues: + - OnDemand + - Spot + + AmiId: + Type: String + Description: AMI ID to use for PCS cluster. + + MinInstanceCount: + Type: Number + Default: 0 + Description: Minimum number of compute nodes to maintain in the compute fleet. + + MaxInstanceCount: + Type: Number + Default: 4 + Description: Maximum number of compute nodes that can run in the compute fleet. This controls the cluster's autoscaling upper limit. + + + VPC: + Description: VPC to launch the Cluster nodes + Type: AWS::EC2::VPC::Id + + DefaultPrivateSubnet: + Description: Private subnet for the PCluster + Type: AWS::EC2::Subnet::Id + + SecurityGroup: + Description: Security group ID from the network template output + Type: AWS::EC2::SecurityGroup::Id + + DefaultPublicSubnet: + Description: Public subnet for the Login node + Type: AWS::EC2::Subnet::Id + + # Parameters for pcs-iip-minimal.yaml + EnableSsm: + Type: String + Default: "True" + Description: "Enable AWS Systems Manager service on instances" + AllowedValues: + - "True" + - "False" + EnableS3ReadOnly: + Type: String + Default: "True" + Description: "Grant instances read-only access to Amazon S3" + AllowedValues: + - "True" + - "False" + EnableCloudwatchAgent: + Type: String + Default: "False" + Description: "Grant instances permissions to use use Amazon CloudWatch Agent" + AllowedValues: + - "True" + - "False" + + # Parameters for cfn-pcs-lt-efs-fsxl.yaml + VpcDefaultSecurityGroupId: + Type: AWS::EC2::SecurityGroup::Id + Description: Cluster VPC 'default' security group. Make sure you choose the one from your cluster VPC! + Default: sg-00db64cee7ba85cb2 # Default from main stack's SecurityGroup param + + EfsFilesystemId: + Type: String + Description: Amazon EFS file system Id + Default: " " # Default from main stack's PCSLaunchTemplate parameters + + EfsFilesystemSecurityGroupId: + Type: String + Description: Security group for EFS filesystem. Choose VPC default if filesysten was created using EFS console quick-start defaults. + Default: " " # Default from main stack's PCSLaunchTemplate parameters + + FSxLustreFilesystemId: + Type: String + Description: Amazon FSx for Lustre file system Id + Default: " " # Default from main stack's PCSLaunchTemplate parameters + + FSxLustreFilesystemSecurityGroupId: + Type: String + Description: Security group for Amazon FSx for Lustre filesystem. Choose VPC default if filesysten was created using FSx console quick-start defaults. + Default: " " # Default from main stack's PCSLaunchTemplate parameters + + FSxLustreFilesystemMountName: + Type: String + Description: Amazon FSx for Lustre mount name + Default: " " # Default from main stack's PCSLaunchTemplate parameters + + # Parameter for pcs-cluster-sg.yaml + CreateInboundSshSecurityGroup: + Description: Create an inbound security group to allow SSH access to nodes. + Type: String + Default: 'True' + AllowedValues: + - 'True' + - 'False' + + ResearcherName: + Type: String + Description: Tags to apply to nested stacks + Default: "Placeholder" + + ProjectName: + Type: String + Description: Project tag to apply to nested stacks + Default: "Placeholder" + + +Conditions: + HasAccountingSupport: !Not [!Or [!Equals [!Ref SlurmVersion, "23.11"], !Equals [!Ref SlurmVersion, "24.05"]]] + IsAccountingEnabled: !Equals [!Ref ManagedAccounting, 'enabled'] + IncludeAccountingConfig: !And [!Condition HasAccountingSupport, !Condition IsAccountingEnabled] + SetAccountingPolicy: !Not [!Equals [!Ref AccountingPolicyEnforcement, 'none']] + EnableSsmCondition: !Equals [!Ref EnableSsm, "True"] + EnableS3ReadOnlyCondition: !Equals [!Ref EnableS3ReadOnly, "True"] + EnableCloudwatchAgentCondition: !Equals [!Ref EnableCloudwatchAgent, "True"] + CreateSshSecGroup: !Equals [!Ref CreateInboundSshSecurityGroup, 'True'] + +Mappings: + Architecture: + AmiArchParameter: + Graviton: arm64 + x86: x86_64 + LoginNodeInstances: + Graviton: c7g.xlarge + x86: g4dn.2xlarge + ComputeNodeInstances: + Graviton: c7g.xlarge + x86: g4dn.2xlarge + +Resources: + # Merged from pcs-cluster-sg.yaml + ClusterSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Supports communications between AWS PCS controller, compute nodes, and client nodes + VpcId: !Ref VPC + GroupName: !Sub 'cluster-${AWS::StackName}' + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: Name + Value: !Sub 'cluster-${AWS::StackName}' + + ClusterAllowAllInboundFromSelf: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: !Ref ClusterSecurityGroup + IpProtocol: '-1' + SourceSecurityGroupId: !Ref ClusterSecurityGroup + + ClusterAllowAllOutboundToSelf: + Type: AWS::EC2::SecurityGroupEgress + Properties: + GroupId: !Ref ClusterSecurityGroup + IpProtocol: '-1' + DestinationSecurityGroupId: !Ref ClusterSecurityGroup + + # This allows all outbound comms, which enables HTTPS calls and connections to networked storage + ClusterAllowAllOutboundToWorld: + Type: AWS::EC2::SecurityGroupEgress + Properties: + GroupId: !Ref ClusterSecurityGroup + IpProtocol: '-1' + CidrIp: 0.0.0.0/0 + + # Attach this to login nodes to enable inbound SSH access. + InboundSshSecurityGroup: + Condition: CreateSshSecGroup + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Allows inbound SSH access + GroupName: !Sub 'inbound-ssh-${AWS::StackName}' + VpcId: !Ref VPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 22 + ToPort: 22 + CidrIp: !Ref ClientIpCidr + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: Name + Value: !Sub 'inbound-ssh-${AWS::StackName}' + + + # Merged from pcs-iip-minimal.yaml + PcsInstanceIamRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub "AWSPCS-${AWS::StackName}-${AWS::Region}-role" # Merged from nested RoleName and main stack's RoleName: !Sub '${AWS::StackName}-${AWS::Region}' + Description: "AWS IAM role for PCS node group instances" + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ec2.amazonaws.com + Version: "2012-10-17" + ManagedPolicyArns: + - !If + - EnableSsmCondition + - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" + - !Ref AWS::NoValue + - !If + - EnableS3ReadOnlyCondition + - "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" + - !Ref AWS::NoValue + - !If + - EnableCloudwatchAgentCondition + - "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy" + - !Ref AWS::NoValue + Policies: + - PolicyDocument: + Version: "2012-10-17" + Statement: + - Action: + - pcs:RegisterComputeNodeGroupInstance + Effect: Allow + Resource: "*" + PolicyName: PcsRegisterInstancePolicy + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: Name + Value: !Sub "AWSPCS-${AWS::StackName}-${AWS::Region}-role" + + PcsInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Roles: + - !Ref PcsInstanceIamRole + InstanceProfileName: !Sub "AWSPCS-${AWS::StackName}-${AWS::Region}" # Merged from nested RoleName and main stack's RoleName: !Sub '${AWS::StackName}-${AWS::Region}' + + + # Merged from cfn-pcs-lt-efs-fsxl.yaml + LoginLaunchTemplate: + Type: AWS::EC2::LaunchTemplate + Properties: + LaunchTemplateName: !Sub 'login-${AWS::StackName}' + LaunchTemplateData: + TagSpecifications: + - ResourceType: instance + Tags: + - Key: HPCRecipes + Value: "true" + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: researcher_name + Value: !Ref ResearcherName + - Key: project_name + Value: !Ref ProjectName + MetadataOptions: + HttpEndpoint: enabled + HttpPutResponseHopLimit: 4 + HttpTokens: required + KeyName: !Ref KeyName + SecurityGroupIds: + - !Ref VpcDefaultSecurityGroupId + - !Ref ClusterSecurityGroup # Changed from !GetAtt [ PCSSecurityGroup, Outputs.ClusterSecurityGroupId ] + - !If + - CreateSshSecGroup # Condition from pcs-cluster-sg + - !Ref InboundSshSecurityGroup # Changed from !GetAtt [ PCSSecurityGroup, Outputs.InboundSshSecurityGroupId ] + - !Ref AWS::NoValue + # - !Ref EfsFilesystemSecurityGroupId # Commented out as in source + # - !Ref FSxLustreFilesystemSecurityGroupId # Commented out as in source + UserData: + Fn::Base64: !Sub | + MIME-Version: 1.0 + Content-Type: multipart/mixed; boundary="==MYBOUNDARY==" + + --==MYBOUNDARY== + Content-Type: text/cloud-config; charset="us-ascii" + MIME-Version: 1.0 + + packages: + - amazon-efs-utils + + runcmd: + # Mount EFS filesystem as /home + # - mkdir -p /tmp/home + # - rsync -aA /home/ /tmp/home + # - echo "${EfsFilesystemId}:/ /home efs tls,_netdev" >> /etc/fstab + # - mount -a -t efs defaults + # - rsync -aA --ignore-existing /tmp/home/ /home + # - rm -rf /tmp/home/ + #!/bin/bash + mkdir -p /var/log/amazon/pcs + exec > >(tee -a /var/log/amazon/pcs/bootstrap.log | logger -t user-data -s 2>/dev/ttyS0) 2>&1 + + mkdir -p /etc/amazon/pcs + echo '{ "cluster": { "version": "Slurm_24.11", "disable_multithreading": true, "scheduler": "slurm", "base_os": "alinux2", "cluster_id": "${AWS::StackName}", "slurm": { "endpoint": "https://pcs.${AWS::Region}.api.aws" }}}' > /etc/amazon/pcs/bootstrap_config.json + + cloud-init-per instance pcs-bootstrap-init /opt/aws/pcs/bin/pcs_bootstrap_init.sh /etc/amazon/pcs/bootstrap_config.json + cloud-init-per instance pcs-bootstrap-config /opt/aws/pcs/bin/pcs_bootstrap_config_per_instance.sh /etc/amazon/pcs/bootstrap_config.json + /opt/aws/pcs/bin/pcs_bootstrap_finalize.sh /etc/amazon/pcs/bootstrap_config.json + + # If provided, mount FSxL filesystem as /shared + # - if [ ! -z "${FSxLustreFilesystemId}" ]; then amazon-linux-extras install -y lustre=latest; mkdir -p /shared; chmod a+rwx /shared; mount -t lustre ${FSxLustreFilesystemId}.fsx.${AWS::Region}.amazonaws.com@tcp:/${FSxLustreFilesystemMountName} /shared; chmod 777 /shared; fi + + --==MYBOUNDARY== + + ComputeLaunchTemplate: + Type: AWS::EC2::LaunchTemplate + Properties: + LaunchTemplateName: !Sub 'compute-${AWS::StackName}' + LaunchTemplateData: + TagSpecifications: + - ResourceType: instance + Tags: + - Key: HPCRecipes + Value: "true" + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: researcher_name + Value: !Ref ResearcherName + - Key: project_name + Value: !Ref ProjectName + MetadataOptions: + HttpEndpoint: enabled + HttpPutResponseHopLimit: 4 + HttpTokens: required + SecurityGroupIds: + - !Ref VpcDefaultSecurityGroupId + - !Ref ClusterSecurityGroup # Changed from !GetAtt [ PCSSecurityGroup, Outputs.ClusterSecurityGroupId ] + # - !Ref EfsFilesystemSecurityGroupId # Commented out as in source + # - !Ref FSxLustreFilesystemSecurityGroupId # Commented out as in source + KeyName: !Ref KeyName + UserData: + Fn::Base64: !Sub | + MIME-Version: 1.0 + Content-Type: multipart/mixed; boundary="==MYBOUNDARY==" + + --==MYBOUNDARY== + Content-Type: text/cloud-config; charset="us-ascii" + MIME-Version: 1.0 + + packages: + - amazon-efs-utils + + runcmd: + # Mount EFS filesystem as /home + # - mkdir -p /tmp/home + # - rsync -aA /home/ /tmp/home + # - echo "${EfsFilesystemId}:/ /home efs tls,_netdev" >> /etc/fstab + # - mount -a -t efs defaults + # - rsync -aA --ignore-existing /tmp/home/ /home + # - rm -rf /tmp/home/ + #!/bin/bash + mkdir -p /var/log/amazon/pcs + exec > >(tee -a /var/log/amazon/pcs/bootstrap.log | logger -t user-data -s 2>/dev/ttyS0) 2>&1 + + mkdir -p /etc/amazon/pcs + echo '{ "cluster": { "version": "Slurm_24.11", "disable_multithreading": true, "scheduler": "slurm", "base_os": "alinux2", "cluster_id": "${AWS::StackName}", "slurm": { "endpoint": "https://pcs.${AWS::Region}.api.aws" }}}' > /etc/amazon/pcs/bootstrap_config.json + + cloud-init-per instance pcs-bootstrap-init /opt/aws/pcs/bin/pcs_bootstrap_init.sh /etc/amazon/pcs/bootstrap_config.json + cloud-init-per instance pcs-bootstrap-config /opt/aws/pcs/bin/pcs_bootstrap_config_per_instance.sh /etc/amazon/pcs/bootstrap_config.json + /opt/aws/pcs/bin/pcs_bootstrap_finalize.sh /etc/amazon/pcs/bootstrap_config.json + + # If provided, mount FSxL filesystem as /shared + # - if [ ! -z "${FSxLustreFilesystemId}" ]; then amazon-linux-extras install -y lustre=latest; mkdir -p /shared; chmod a+rwx /shared; mount -t lustre ${FSxLustreFilesystemId}.fsx.${AWS::Region}.amazonaws.com@tcp:/${FSxLustreFilesystemMountName} /shared; fi + + --==MYBOUNDARY== + + + # Cluster + PCSCluster: + Type: AWS::PCS::Cluster + Properties: + Name: !Sub '${AWS::StackName}' + Size: SMALL + Tags: + cost_resource: !Sub '${AWS::StackName}' + Scheduler: + Type: SLURM + Version: !Ref SlurmVersion + Networking: + SubnetIds: + - !Ref DefaultPrivateSubnet + SecurityGroupIds: + - !Ref ClusterSecurityGroup # Converted from nested stack output + SlurmConfiguration: !If + - IncludeAccountingConfig + - Accounting: + Mode: STANDARD + DefaultPurgeTimeInDays: 30 + SlurmCustomSettings: !If + - SetAccountingPolicy + - - ParameterName: AccountingStorageEnforce + ParameterValue: !Ref AccountingPolicyEnforcement + - [] + - !Ref AWS::NoValue + + # Compute Node groups - Login Nodes + PCSNodeGroupLogin: + Type: AWS::PCS::ComputeNodeGroup + Properties: + Tags: + cost_resource: !Sub '${AWS::StackName}' + ClusterId: !GetAtt [PCSCluster, Id] + Name: login + ScalingConfiguration: + MinInstanceCount: 1 + MaxInstanceCount: 1 + IamInstanceProfileArn: !GetAtt [PcsInstanceProfile, Arn] # Converted from nested stack output + CustomLaunchTemplate: + TemplateId: !Ref LoginLaunchTemplate # Converted from nested stack output + Version: 1 + SubnetIds: + - !Ref DefaultPublicSubnet + AmiId: ami-0bf564070da947c48 + InstanceConfigs: + - InstanceType: !FindInMap [Architecture, LoginNodeInstances, !Ref NodeArchitecture] + + # Compute Node groups - Compute Nodes + PCSNodeGroupCompute: + Type: AWS::PCS::ComputeNodeGroup + Properties: + Tags: + cost_resource: !Sub '${AWS::StackName}' + ClusterId: !GetAtt [PCSCluster, Id] + Name: compute-1 + ScalingConfiguration: + MinInstanceCount: !Ref MinInstanceCount + MaxInstanceCount: !Ref MaxInstanceCount + IamInstanceProfileArn: !GetAtt [PcsInstanceProfile, Arn] # Converted from nested stack output + CustomLaunchTemplate: + TemplateId: !Ref ComputeLaunchTemplate # Converted from nested stack output + Version: 1 + SubnetIds: + - !Ref DefaultPrivateSubnet + AmiId: ami-0bf564070da947c48 + InstanceConfigs: + - InstanceType: !FindInMap [Architecture, ComputeNodeInstances, !Ref NodeArchitecture] + + PCSQueueCompute: + Type: AWS::PCS::Queue + Properties: + Tags: + cost_resource: !Sub '${AWS::StackName}' + ClusterId: !GetAtt [PCSCluster, Id] + Name: demo + ComputeNodeGroupConfigurations: + - ComputeNodeGroupId: !GetAtt [PCSNodeGroupCompute, Id] + + PcsAMILookupRole: + Type: AWS::IAM::Role + Properties: + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: EC2DescribeImages + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ec2:DescribeImages + Resource: '*' + +Outputs: + ClusterId: + Description: The Id of the PCS cluster + Value: !GetAtt [PCSCluster, Id] + PcsConsoleUrl: + Description: URL to access the cluster in the PCS console + Value: !Sub + - https://${ConsoleDomain}/pcs/home?region=${AWS::Region}#/clusters/${ClusterId} + - { ConsoleDomain: !Sub '${AWS::Region}.console.aws.amazon.com', + ClusterId: !GetAtt [PCSCluster, Id] + } + Export: + Name: !Sub ${AWS::StackName}-PcsConsoleUrl + Ec2ConsoleUrl: + Description: URL to access instance(s) in the login node group + Value: !Sub + - https://${ConsoleDomain}/ec2/home?region=${AWS::Region}#Instances:instanceState=running;tag:aws:pcs:compute-node-group-id=${NodeGroupLoginId} + - { ConsoleDomain: !Sub '${AWS::Region}.console.aws.amazon.com', + NodeGroupLoginId: !GetAtt [PCSNodeGroupLogin, Id] + } + Export: + Name: !Sub ${AWS::StackName}-Ec2ConsoleUrl + LoginLaunchTemplateId: + Description: "Login nodes template ID" + Value: !Ref LoginLaunchTemplate + LoginLaunchTemplateName: + Description: "Login nodes template name" + Value: !Sub 'login-${AWS::StackName}' + ComputeLaunchTemplateId: + Description: "Compute nodes template ID" + Value: !Ref ComputeLaunchTemplate + ComputeLaunchTemplateName: + Description: "Compute nodes template name" + Value: !Sub 'compute-${AWS::StackName}' + InstanceProfile: + Value: !Ref PcsInstanceProfile + InstanceProfileArn: + Value: !GetAtt PcsInstanceProfile.Arn + ClusterSecurityGroupId: + Description: Supports communication between PCS controller, compute nodes, and login nodes + Value: !Ref ClusterSecurityGroup + InboundSshSecurityGroupId: + Condition: CreateSshSecGroup + Description: Enables SSH access to login nodes + Value: !Ref InboundSshSecurityGroup \ No newline at end of file diff --git a/cft-templates/pcs_quick_lt.yaml b/cft-templates/pcs_quick_lt.yaml new file mode 100644 index 0000000..4109e35 --- /dev/null +++ b/cft-templates/pcs_quick_lt.yaml @@ -0,0 +1,570 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: AWS PCS "Getting Started" cluster. This template deploys a small HPC cluster with 1 login node and up to 4 compute nodes. Optionally, Slurm accounting can be enabled. It includes an EFS file system for shared storage and an FSx for Lustre file system for high-speed temporary storage. The cluster is deployed in a new VPC with both public and private subnets. It can be accessed via the browser using AWS Systems Manager Session Manager or over the internet via SSH. To access the cluster, check the Outputs tab of this stack for relevant links. + +### Stack metadata +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: PCS Cluster configuration + Parameters: + - SlurmVersion + - ManagedAccounting + - AccountingPolicyEnforcement + - Label: + default: PCS ComputeNodeGroups configuration + Parameters: + - NodeArchitecture + - KeyName + - ClientIpCidr + +Parameters: + NodeArchitecture: + Type: String + Default: x86 + AllowedValues: + - x86 + - Graviton + Description: Processor architecture for the login and compute node instances + + SlurmVersion: + Type: String + Default: 24.11 + Description: Version of Slurm to use + AllowedValues: + - 24.05 + - 24.11 + - 23.11 + + ManagedAccounting: + Type: String + Default: 'disabled' + AllowedValues: + - 'enabled' + - 'disabled' + Description: Monitor cluster usage, manage access control, and enforce resource limits with Slurm accounting. Requires Slurm 24.11 or newer. + + AccountingPolicyEnforcement: + Description: Specify which Slurm accounting policies to enforce + Type: String + Default: none + AllowedValues: + - none + - 'associations,limits,safe' + + KeyName: + Description: SSH keypair to log in to the head node + Type: AWS::EC2::KeyPair::KeyName + AllowedPattern: ".+" # Required + + ClientIpCidr: + Description: IP(s) allowed to access the login node over SSH. We recommend that you restrict it with your own IP/subnet (x.x.x.x/32 for your own ip or x.x.x.x/24 for range. Replace x.x.x.x with your own PUBLIC IP. You can get your public IP using tools such as https://ifconfig.co/) + Default: 0.0.0.0/0 + Type: String + AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) + ConstraintDescription: Value must be a valid IP or network range of the form x.x.x.x/x. + + VPC: + Description: VPC to launch the Cluster nodes + Type: String + Default: vpc-07c351be7a033127f + + DefaultPrivateSubnet: + Description: Private subnet for the PCluster + Type: String + Default: subnet-01d831eb711ef25ec + + SecurityGroup: + Description: Security group ID from the network template output + Type: String + Default: sg-00db64cee7ba85cb2 + + DefaultPublicSubnet: + Description: Private subnet for the PCluster + Type: String + Default: subnet-01d831eb711ef25ec + + # Parameters for pcs-iip-minimal.yaml + EnableSsm: + Type: String + Default: "True" + Description: "Enable AWS Systems Manager service on instances" + AllowedValues: + - "True" + - "False" + EnableS3ReadOnly: + Type: String + Default: "True" + Description: "Grant instances read-only access to Amazon S3" + AllowedValues: + - "True" + - "False" + EnableCloudwatchAgent: + Type: String + Default: "False" + Description: "Grant instances permissions to use use Amazon CloudWatch Agent" + AllowedValues: + - "True" + - "False" + + # Parameters for cfn-pcs-lt-efs-fsxl.yaml + VpcDefaultSecurityGroupId: + Type: AWS::EC2::SecurityGroup::Id + Description: Cluster VPC 'default' security group. Make sure you choose the one from your cluster VPC! + Default: sg-00db64cee7ba85cb2 # Default from main stack's SecurityGroup param + + EfsFilesystemId: + Type: String + Description: Amazon EFS file system Id + Default: " " # Default from main stack's PCSLaunchTemplate parameters + EfsFilesystemSecurityGroupId: + Type: String + Description: Security group for EFS filesystem. Choose VPC default if filesysten was created using EFS console quick-start defaults. + Default: " " # Default from main stack's PCSLaunchTemplate parameters + FSxLustreFilesystemId: + Type: String + Description: Amazon FSx for Lustre file system Id + Default: " " # Default from main stack's PCSLaunchTemplate parameters + FSxLustreFilesystemSecurityGroupId: + Type: String + Description: Security group for Amazon FSx for Lustre filesystem. Choose VPC default if filesysten was created using FSx console quick-start defaults. + Default: " " # Default from main stack's PCSLaunchTemplate parameters + FSxLustreFilesystemMountName: + Type: String + Description: Amazon FSx for Lustre mount name + Default: " " # Default from main stack's PCSLaunchTemplate parameters + + # Parameter for pcs-cluster-sg.yaml + CreateInboundSshSecurityGroup: + Description: Create an inbound security group to allow SSH access to nodes. + Type: String + Default: 'True' + AllowedValues: + - 'True' + - 'False' + + ResearcherName: + Type: String + Description: Tags to apply to nested stacks + Default: "Placeholder" + + + ProjectName: + Type: String + Description: Project tag to apply to nested stacks + Default: "Placeholder" + + +Conditions: + HasAccountingSupport: !Not [!Or [!Equals [!Ref SlurmVersion, "23.11"], !Equals [!Ref SlurmVersion, "24.05"]]] + IsAccountingEnabled: !Equals [!Ref ManagedAccounting, 'enabled'] + IncludeAccountingConfig: !And [!Condition HasAccountingSupport, !Condition IsAccountingEnabled] + SetAccountingPolicy: !Not [!Equals [!Ref AccountingPolicyEnforcement, 'none']] + EnableSsmCondition: !Equals [!Ref EnableSsm, "True"] + EnableS3ReadOnlyCondition: !Equals [!Ref EnableS3ReadOnly, "True"] + EnableCloudwatchAgentCondition: !Equals [!Ref EnableCloudwatchAgent, "True"] + CreateSshSecGroup: !Equals [!Ref CreateInboundSshSecurityGroup, 'True'] + +Mappings: + Architecture: + AmiArchParameter: + Graviton: arm64 + x86: x86_64 + LoginNodeInstances: + Graviton: c7g.xlarge + x86: g4dn.2xlarge + ComputeNodeInstances: + Graviton: c7g.xlarge + x86: g4dn.2xlarge + +Resources: + # Merged from pcs-cluster-sg.yaml + ClusterSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Supports communications between AWS PCS controller, compute nodes, and client nodes + VpcId: !Ref VPC + GroupName: !Sub 'cluster-${AWS::StackName}' + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: Name + Value: !Sub 'cluster-${AWS::StackName}' + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 0 + ToPort: 65535 + CidrIp: 0.0.0.0/0 # Allow all incoming traffic (adjust as needed for security) + + ClusterAllowAllInboundFromSelf: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: !Ref ClusterSecurityGroup + IpProtocol: '-1' + SourceSecurityGroupId: !Ref ClusterSecurityGroup + + ClusterAllowAllOutboundToSelf: + Type: AWS::EC2::SecurityGroupEgress + Properties: + GroupId: !Ref ClusterSecurityGroup + IpProtocol: '-1' + DestinationSecurityGroupId: !Ref ClusterSecurityGroup + + # This allows all outbound comms, which enables HTTPS calls and connections to networked storage + ClusterAllowAllOutboundToWorld: + Type: AWS::EC2::SecurityGroupEgress + Properties: + GroupId: !Ref ClusterSecurityGroup + IpProtocol: '-1' + CidrIp: 0.0.0.0/0 + + # Attach this to login nodes to enable inbound SSH access. + InboundSshSecurityGroup: + Condition: CreateSshSecGroup + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Allows inbound SSH access + GroupName: !Sub 'inbound-ssh-${AWS::StackName}' + VpcId: !Ref VPC + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 22 + ToPort: 22 + CidrIp: !Ref ClientIpCidr + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: Name + Value: !Sub 'inbound-ssh-${AWS::StackName}' + + + # Merged from pcs-iip-minimal.yaml + PcsInstanceIamRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub "AWSPCS-${AWS::StackName}-${AWS::Region}-role" # Merged from nested RoleName and main stack's RoleName: !Sub '${AWS::StackName}-${AWS::Region}' + Description: "AWS IAM role for PCS node group instances" + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: ec2.amazonaws.com + Version: "2012-10-17" + ManagedPolicyArns: + - !If + - EnableSsmCondition + - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" + - !Ref AWS::NoValue + - !If + - EnableS3ReadOnlyCondition + - "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" + - !Ref AWS::NoValue + - !If + - EnableCloudwatchAgentCondition + - "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy" + - !Ref AWS::NoValue + Policies: + - PolicyDocument: + Version: "2012-10-17" + Statement: + - Action: + - pcs:RegisterComputeNodeGroupInstance + Effect: Allow + Resource: "*" + PolicyName: PcsRegisterInstancePolicy + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: Name + Value: !Sub "AWSPCS-${AWS::StackName}-${AWS::Region}-role" + + PcsInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Roles: + - !Ref PcsInstanceIamRole + InstanceProfileName: !Sub "AWSPCS-${AWS::StackName}-${AWS::Region}" # Merged from nested RoleName and main stack's RoleName: !Sub '${AWS::StackName}-${AWS::Region}' + + + # Merged from cfn-pcs-lt-efs-fsxl.yaml + LoginLaunchTemplate: + Type: AWS::EC2::LaunchTemplate + Properties: + LaunchTemplateName: !Sub 'login-${AWS::StackName}' + LaunchTemplateData: + TagSpecifications: + - ResourceType: instance + Tags: + - Key: HPCRecipes + Value: "true" + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: researcher_name + Value: !Ref ResearcherName + - Key: project_name + Value: !Ref ProjectName + MetadataOptions: + HttpEndpoint: enabled + HttpPutResponseHopLimit: 4 + HttpTokens: required + KeyName: !Ref KeyName + SecurityGroupIds: + - !Ref VpcDefaultSecurityGroupId + - !Ref ClusterSecurityGroup # Changed from !GetAtt [ PCSSecurityGroup, Outputs.ClusterSecurityGroupId ] + - !If + - CreateSshSecGroup # Condition from pcs-cluster-sg + - !Ref InboundSshSecurityGroup # Changed from !GetAtt [ PCSSecurityGroup, Outputs.InboundSshSecurityGroupId ] + - !Ref AWS::NoValue + # - !Ref EfsFilesystemSecurityGroupId # Commented out as in source + # - !Ref FSxLustreFilesystemSecurityGroupId # Commented out as in source + UserData: + Fn::Base64: !Sub | + MIME-Version: 1.0 + Content-Type: multipart/mixed; boundary="==MYBOUNDARY==" + + --==MYBOUNDARY== + Content-Type: text/cloud-config; charset="us-ascii" + MIME-Version: 1.0 + + packages: + - amazon-efs-utils + + runcmd: + # Mount EFS filesystem as /home + # - mkdir -p /tmp/home + # - rsync -aA /home/ /tmp/home + # - echo "${EfsFilesystemId}:/ /home efs tls,_netdev" >> /etc/fstab + # - mount -a -t efs defaults + # - rsync -aA --ignore-existing /tmp/home/ /home + # - rm -rf /tmp/home/ + #!/bin/bash + mkdir -p /var/log/amazon/pcs + exec > >(tee -a /var/log/amazon/pcs/bootstrap.log | logger -t user-data -s 2>/dev/ttyS0) 2>&1 + + mkdir -p /etc/amazon/pcs + echo '{ "cluster": { "version": "Slurm_24.11", "disable_multithreading": true, "scheduler": "slurm", "base_os": "alinux2", "cluster_id": "${AWS::StackName}", "slurm": { "endpoint": "https://pcs.${AWS::Region}.api.aws" }}}' > /etc/amazon/pcs/bootstrap_config.json + + cloud-init-per instance pcs-bootstrap-init /opt/aws/pcs/bin/pcs_bootstrap_init.sh /etc/amazon/pcs/bootstrap_config.json + cloud-init-per instance pcs-bootstrap-config /opt/aws/pcs/bin/pcs_bootstrap_config_per_instance.sh /etc/amazon/pcs/bootstrap_config.json + /opt/aws/pcs/bin/pcs_bootstrap_finalize.sh /etc/amazon/pcs/bootstrap_config.json + + # If provided, mount FSxL filesystem as /shared + # - if [ ! -z "${FSxLustreFilesystemId}" ]; then amazon-linux-extras install -y lustre=latest; mkdir -p /shared; chmod a+rwx /shared; mount -t lustre ${FSxLustreFilesystemId}.fsx.${AWS::Region}.amazonaws.com@tcp:/${FSxLustreFilesystemMountName} /shared; chmod 777 /shared; fi + + --==MYBOUNDARY== + + ComputeLaunchTemplate: + Type: AWS::EC2::LaunchTemplate + Properties: + LaunchTemplateName: !Sub 'compute-${AWS::StackName}' + LaunchTemplateData: + TagSpecifications: + - ResourceType: instance + Tags: + - Key: HPCRecipes + Value: "true" + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: researcher_name + Value: !Ref ResearcherName + - Key: project_name + Value: !Ref ProjectName + MetadataOptions: + HttpEndpoint: enabled + HttpPutResponseHopLimit: 4 + HttpTokens: required + SecurityGroupIds: + - !Ref VpcDefaultSecurityGroupId + - !Ref ClusterSecurityGroup # Changed from !GetAtt [ PCSSecurityGroup, Outputs.ClusterSecurityGroupId ] + # - !Ref EfsFilesystemSecurityGroupId # Commented out as in source + # - !Ref FSxLustreFilesystemSecurityGroupId # Commented out as in source + KeyName: !Ref KeyName + UserData: + Fn::Base64: !Sub | + MIME-Version: 1.0 + Content-Type: multipart/mixed; boundary="==MYBOUNDARY==" + + --==MYBOUNDARY== + Content-Type: text/cloud-config; charset="us-ascii" + MIME-Version: 1.0 + + packages: + - amazon-efs-utils + + runcmd: + # Mount EFS filesystem as /home + # - mkdir -p /tmp/home + # - rsync -aA /home/ /tmp/home + # - echo "${EfsFilesystemId}:/ /home efs tls,_netdev" >> /etc/fstab + # - mount -a -t efs defaults + # - rsync -aA --ignore-existing /tmp/home/ /home + # - rm -rf /tmp/home/ + #!/bin/bash + mkdir -p /var/log/amazon/pcs + exec > >(tee -a /var/log/amazon/pcs/bootstrap.log | logger -t user-data -s 2>/dev/ttyS0) 2>&1 + + mkdir -p /etc/amazon/pcs + echo '{ "cluster": { "version": "Slurm_24.11", "disable_multithreading": true, "scheduler": "slurm", "base_os": "alinux2", "cluster_id": "${AWS::StackName}", "slurm": { "endpoint": "https://pcs.${AWS::Region}.api.aws" }}}' > /etc/amazon/pcs/bootstrap_config.json + + cloud-init-per instance pcs-bootstrap-init /opt/aws/pcs/bin/pcs_bootstrap_init.sh /etc/amazon/pcs/bootstrap_config.json + cloud-init-per instance pcs-bootstrap-config /opt/aws/pcs/bin/pcs_bootstrap_config_per_instance.sh /etc/amazon/pcs/bootstrap_config.json + /opt/aws/pcs/bin/pcs_bootstrap_finalize.sh /etc/amazon/pcs/bootstrap_config.json + + # If provided, mount FSxL filesystem as /shared + # - if [ ! -z "${FSxLustreFilesystemId}" ]; then amazon-linux-extras install -y lustre=latest; mkdir -p /shared; chmod a+rwx /shared; mount -t lustre ${FSxLustreFilesystemId}.fsx.${AWS::Region}.amazonaws.com@tcp:/${FSxLustreFilesystemMountName} /shared; fi + + --==MYBOUNDARY== + + + # Cluster + PCSCluster: + Type: AWS::PCS::Cluster + Properties: + Name: !Sub '${AWS::StackName}' + Size: SMALL + Tags: + cost_resource: !Sub '${AWS::StackName}' + Scheduler: + Type: SLURM + Version: !Ref SlurmVersion + Networking: + SubnetIds: + - !Ref DefaultPrivateSubnet + SecurityGroupIds: + - !Ref ClusterSecurityGroup # Converted from nested stack output + SlurmConfiguration: !If + - IncludeAccountingConfig + - Accounting: + Mode: STANDARD + DefaultPurgeTimeInDays: 30 + SlurmCustomSettings: !If + - SetAccountingPolicy + - - ParameterName: AccountingStorageEnforce + ParameterValue: !Ref AccountingPolicyEnforcement + - [] + - !Ref AWS::NoValue + + # Compute Node groups - Login Nodes + PCSNodeGroupLogin: + Type: AWS::PCS::ComputeNodeGroup + Properties: + Tags: + cost_resource: !Sub '${AWS::StackName}' + ClusterId: !GetAtt [PCSCluster, Id] + Name: login + ScalingConfiguration: + MinInstanceCount: 1 + MaxInstanceCount: 1 + IamInstanceProfileArn: !GetAtt [PcsInstanceProfile, Arn] # Converted from nested stack output + CustomLaunchTemplate: + TemplateId: !Ref LoginLaunchTemplate # Converted from nested stack output + Version: 1 + SubnetIds: + - !Ref DefaultPublicSubnet + AmiId: ami-0bf564070da947c48 + InstanceConfigs: + - InstanceType: !FindInMap [Architecture, LoginNodeInstances, !Ref NodeArchitecture] + + # Compute Node groups - Compute Nodes + PCSNodeGroupCompute: + Type: AWS::PCS::ComputeNodeGroup + Properties: + Tags: + cost_resource: !Sub '${AWS::StackName}' + ClusterId: !GetAtt [PCSCluster, Id] + Name: compute-1 + ScalingConfiguration: + MinInstanceCount: 0 + MaxInstanceCount: 4 + IamInstanceProfileArn: !GetAtt [PcsInstanceProfile, Arn] # Converted from nested stack output + CustomLaunchTemplate: + TemplateId: !Ref ComputeLaunchTemplate # Converted from nested stack output + Version: 1 + SubnetIds: + - !Ref DefaultPrivateSubnet + AmiId: ami-0bf564070da947c48 + InstanceConfigs: + - InstanceType: !FindInMap [Architecture, ComputeNodeInstances, !Ref NodeArchitecture] + + PCSQueueCompute: + Type: AWS::PCS::Queue + Properties: + Tags: + cost_resource: !Sub '${AWS::StackName}' + ClusterId: !GetAtt [PCSCluster, Id] + Name: demo + ComputeNodeGroupConfigurations: + - ComputeNodeGroupId: !GetAtt [PCSNodeGroupCompute, Id] + + PcsAMILookupRole: + Type: AWS::IAM::Role + Properties: + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: EC2DescribeImages + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ec2:DescribeImages + Resource: '*' + +Outputs: + ClusterId: + Description: The Id of the PCS cluster + Value: !GetAtt [PCSCluster, Id] + PcsConsoleUrl: + Description: URL to access the cluster in the PCS console + Value: !Sub + - https://${ConsoleDomain}/pcs/home?region=${AWS::Region}#/clusters/${ClusterId} + - { ConsoleDomain: !Sub '${AWS::Region}.console.aws.amazon.com', + ClusterId: !GetAtt [PCSCluster, Id] + } + Export: + Name: !Sub ${AWS::StackName}-PcsConsoleUrl + Ec2ConsoleUrl: + Description: URL to access instance(s) in the login node group + Value: !Sub + - https://${ConsoleDomain}/ec2/home?region=${AWS::Region}#Instances:instanceState=running;tag:aws:pcs:compute-node-group-id=${NodeGroupLoginId} + - { ConsoleDomain: !Sub '${AWS::Region}.console.aws.amazon.com', + NodeGroupLoginId: !GetAtt [PCSNodeGroupLogin, Id] + } + Export: + Name: !Sub ${AWS::StackName}-Ec2ConsoleUrl + LoginLaunchTemplateId: + Description: "Login nodes template ID" + Value: !Ref LoginLaunchTemplate + LoginLaunchTemplateName: + Description: "Login nodes template name" + Value: !Sub 'login-${AWS::StackName}' + ComputeLaunchTemplateId: + Description: "Compute nodes template ID" + Value: !Ref ComputeLaunchTemplate + ComputeLaunchTemplateName: + Description: "Compute nodes template name" + Value: !Sub 'compute-${AWS::StackName}' + InstanceProfile: + Value: !Ref PcsInstanceProfile + InstanceProfileArn: + Value: !GetAtt PcsInstanceProfile.Arn + ClusterSecurityGroupId: + Description: Supports communication between PCS controller, compute nodes, and login nodes + Value: !Ref ClusterSecurityGroup + InboundSshSecurityGroupId: + Condition: CreateSshSecGroup + Description: Enables SSH access to login nodes + Value: !Ref InboundSshSecurityGroup \ No newline at end of file diff --git a/cft-templates/sagemakerUserProfile.yaml b/cft-templates/sagemakerUserProfile.yaml new file mode 100644 index 0000000..a162f8d --- /dev/null +++ b/cft-templates/sagemakerUserProfile.yaml @@ -0,0 +1,497 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: > + Create SageMaker Studio UserProfile and automatically provision a JupyterLab Space + App using a Lambda-backed Custom Resource. +Parameters: + DomainId: + Type: String + Description: Pre-existing SageMaker Studio Domain ID + + UserProfileName: + Type: String + Description: SageMaker Studio User Profile Name + + InstanceType: + Type: String + Description: Instance type for JupyterLab app + Default: ml.t3.medium + AllowedValues: + - ml.t3.medium + - ml.t3.large + - ml.t3.xlarge + - ml.t3.2xlarge + + SpaceName: + Type: String + Description: Space name for JupyterLab + + ResearcherName: + Type: String + Default: abc@example.com + Description: Name of the Researcher (will be added as tag) + + +Resources: + + ############################## + # SageMaker Execution Role + ############################## + SageMakerExecutionRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub "${AWS::StackName}-sagemaker-execution-role" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: sagemaker.amazonaws.com + Action: sts:AssumeRole + - Effect: Allow + Principal: + AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" + Action: + - sts:AssumeRole + - sts:TagSession + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess + - arn:aws:iam::aws:policy/AmazonS3FullAccess + Policies: + - PolicyName: SageMakerExecutionRolePolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "sagemaker:*" + Resource: "*" + - Effect: Allow + Action: + - "bedrock:*" + Resource: "*" + - Effect: Allow + Action: + - "s3:GetObject" + - "s3:PutObject" + - "s3:DeleteObject" + - "s3:ListBucket" + - "s3:GetBucketLocation" + - "s3:ListAllMyBuckets" + - "s3:GetBucketCors" + - "s3:GetBucketVersioning" + Resource: "*" + - Effect: Allow + Action: + - "ec2:CreateNetworkInterface" + - "ec2:CreateNetworkInterfacePermission" + - "ec2:DeleteNetworkInterface" + - "ec2:DeleteNetworkInterfacePermission" + - "ec2:DescribeNetworkInterfaces" + - "ec2:DescribeVpcs" + - "ec2:DescribeSubnets" + - "ec2:DescribeSecurityGroups" + - "ec2:DescribeRouteTables" + - "ec2:DescribeAvailabilityZones" + - "ec2:DescribeDhcpOptions" + - "ec2:DescribeVpcEndpoints" + - "ec2:CreateTags" + Resource: "*" + - Effect: Allow + Action: + - "elasticfilesystem:DescribeFileSystems" + - "elasticfilesystem:DescribeMountTargets" + - "elasticfilesystem:CreateAccessPoint" + - "elasticfilesystem:DescribeAccessPoints" + - "elasticfilesystem:DeleteAccessPoint" + - "elasticfilesystem:ClientMount" + - "elasticfilesystem:ClientWrite" + - "elasticfilesystem:ClientRootAccess" + Resource: "*" + - Effect: Allow + Action: + - "ec2:CreateVolume" + - "ec2:DeleteVolume" + - "ec2:DescribeVolumes" + - "ec2:AttachVolume" + - "ec2:DetachVolume" + - "ec2:ModifyVolume" + - "ec2:CreateSnapshot" + - "ec2:DeleteSnapshot" + - "ec2:DescribeSnapshots" + Resource: "*" + - Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + - "logs:DescribeLogGroups" + - "logs:DescribeLogStreams" + - "logs:GetLogEvents" + Resource: "*" + - Effect: Allow + Action: + - "cloudwatch:PutMetricData" + - "cloudwatch:GetMetricData" + - "cloudwatch:GetMetricStatistics" + - "cloudwatch:ListMetrics" + Resource: "*" + - Effect: Allow + Action: + - "ecr:GetAuthorizationToken" + - "ecr:BatchCheckLayerAvailability" + - "ecr:GetDownloadUrlForLayer" + - "ecr:BatchGetImage" + Resource: "*" + - Effect: Allow + Action: + - "iam:GetRole" + - "iam:PassRole" + Resource: + - !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/AmazonSageMaker-ExecutionRole-*" + - !Sub "arn:aws:iam::${AWS::AccountId}:role/${AWS::StackName}-sagemaker-execution-role" + + ############################## + # Lambda execution role + ############################## + LambdaExecutionRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub "${UserProfileName}-lambda-exec-role" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: SageMakerJupyterLabFullAccessPolicy + PolicyDocument: + Version: "2012-10-17" + Statement: + # Core SageMaker Space and App Operations + - Effect: Allow + Action: + - sagemaker:CreateSpace + - sagemaker:DeleteSpace + - sagemaker:DescribeSpace + - sagemaker:ListSpaces + - sagemaker:UpdateSpace + - sagemaker:CreateApp + - sagemaker:DeleteApp + - sagemaker:DescribeApp + - sagemaker:ListApps + - sagemaker:CreatePresignedDomainUrl + - sagemaker:StartSession + Resource: "*" + + # Domain & UserProfile ops + - Effect: Allow + Action: + - sagemaker:DescribeDomain + - sagemaker:ListDomains + - sagemaker:DescribeUserProfile + - sagemaker:ListUserProfiles + - sagemaker:UpdateUserProfile + Resource: "*" + + # Image operations + - Effect: Allow + Action: + - sagemaker:DescribeImage + - sagemaker:DescribeImageVersion + - sagemaker:ListImages + - sagemaker:ListImageVersions + Resource: "*" + + # Tagging + - Effect: Allow + Action: + - sagemaker:AddTags + - sagemaker:ListTags + - sagemaker:DeleteTags + Resource: "*" + + # IAM PassRole (must be allowed for the SageMaker exec role) + - Effect: Allow + Action: + - iam:PassRole + Resource: + - !GetAtt SageMakerExecutionRole.Arn + - !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/AmazonSageMaker-ExecutionRole-*" + + # EC2 operations (networking / compute) + - Effect: Allow + Action: + - ec2:CreateNetworkInterface + - ec2:CreateNetworkInterfacePermission + - ec2:DeleteNetworkInterface + - ec2:DeleteNetworkInterfacePermission + - ec2:DescribeNetworkInterfaces + - ec2:DescribeVpcs + - ec2:DescribeSubnets + - ec2:DescribeSecurityGroups + - ec2:DescribeRouteTables + - ec2:DescribeAvailabilityZones + - ec2:DescribeDhcpOptions + - ec2:DescribeVpcEndpoints + - ec2:CreateTags + Resource: "*" + + # EFS + - Effect: Allow + Action: + - elasticfilesystem:DescribeFileSystems + - elasticfilesystem:DescribeMountTargets + - elasticfilesystem:CreateAccessPoint + - elasticfilesystem:DescribeAccessPoints + - elasticfilesystem:DeleteAccessPoint + Resource: "*" + + # EBS (volume ops) + - Effect: Allow + Action: + - ec2:CreateVolume + - ec2:DeleteVolume + - ec2:DescribeVolumes + - ec2:AttachVolume + - ec2:DetachVolume + - ec2:ModifyVolume + - ec2:CreateSnapshot + - ec2:DeleteSnapshot + - ec2:DescribeSnapshots + Resource: "*" + + # CloudWatch Logs + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + - logs:DescribeLogGroups + - logs:DescribeLogStreams + Resource: "*" + + # S3 + - Effect: Allow + Action: + - s3:GetObject + - s3:PutObject + - s3:DeleteObject + - s3:ListBucket + - s3:GetBucketLocation + - s3:ListAllMyBuckets + Resource: "*" + + ############################## + # SageMaker UserProfile + ############################## + SageMakerUserProfile: + Type: AWS::SageMaker::UserProfile + Properties: + DomainId: !Ref DomainId + UserProfileName: !Ref UserProfileName + UserSettings: + ExecutionRole: !GetAtt SageMakerExecutionRole.Arn + Tags: + - Key: cost_resource + Value: !Sub '${AWS::StackName}' + - Key: ResearcherName + Value: !Ref ResearcherName + + ############################## + # Lambda function to manage Space/App (idempotent) + ############################## + SageMakerSpaceAppLambda: + Type: AWS::Lambda::Function + Properties: + FunctionName: !Sub "${UserProfileName}-spaceapp-lambda" + Handler: index.lambda_handler + Runtime: python3.9 + Role: !GetAtt LambdaExecutionRole.Arn + Timeout: 900 + MemorySize: 256 + Code: + ZipFile: | + import boto3 + import time + import json + import cfnresponse + from botocore.exceptions import ClientError + + def wait_for_status(describe_fn, status_key, desired, max_wait=600, poll_interval=10, **kwargs): + """Generic waiter for any SageMaker resource status""" + start = time.time() + while time.time() - start < max_wait: + try: + resp = describe_fn(**kwargs) + status = resp[status_key] + print(f"Current {status_key}: {status}") + if status == desired: + return True + if status == "Failed": + raise Exception(f"Resource failed with status 'Failed'") + except ClientError as e: + print(f"Error while waiting: {e}") + time.sleep(poll_interval) + raise Exception(f"Timeout waiting for {status_key}={desired}") + + def lambda_handler(event, context): + print("Event:", json.dumps(event)) + sm = boto3.client("sagemaker") + + try: + props = event["ResourceProperties"] + domain_id = props["DomainId"] + user_profile = props["UserProfileName"] + space_name = props.get("SpaceName") or f"{user_profile}-lab-space" + instance_type = props.get("InstanceType", "ml.t3.medium") + region = props.get("Region") or boto3.session.Session().region_name + researcher_name = props.get("ResearcherName", "UnknownResearcher") + cost_resource = props.get("CostResource", f"{domain_id}-{user_profile}") + + + # Define common tags to apply to all resources + common_tags = [ + {"Key": "cost_resource", "Value": cost_resource}, + {"Key": "ResearcherName", "Value": researcher_name} + ] + + request_type = event["RequestType"] + + if request_type in ("Create", "Update"): + # --- Create Space --- + try: + sm.describe_space(DomainId=domain_id, SpaceName=space_name) + print(f"Space {space_name} already exists") + except ClientError as e: + if e.response["Error"]["Code"] == "ResourceNotFound": + print(f"Creating space {space_name} with tags") + sm.create_space( + DomainId=domain_id, + SpaceName=space_name, + OwnershipSettings={"OwnerUserProfileName": user_profile}, + SpaceSharingSettings={"SharingType": "Private"}, + SpaceSettings={"AppType": "JupyterLab"}, + Tags=common_tags + ) + else: + raise + + wait_for_status( + sm.describe_space, "Status", "InService", + DomainId=domain_id, SpaceName=space_name + ) + + # --- Create App --- + print(f"Creating JupyterLab app 'default' with tags") + sm.create_app( + DomainId=domain_id, + SpaceName=space_name, + AppType="JupyterLab", + AppName="default", + ResourceSpec={ + "InstanceType": instance_type, + "SageMakerImageArn": "arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-distribution-cpu" + }, + Tags=[ + *common_tags, + {"Key": "InstanceType", "Value": instance_type} + ] + ) + + wait_for_status( + sm.describe_app, "Status", "InService", + DomainId=domain_id, SpaceName=space_name, + AppType="JupyterLab", AppName="default" + ) + + response_data = { + "DomainId": domain_id, + "UserProfileName": user_profile, + "SpaceName": space_name + } + physical_id = f"{domain_id}-{space_name}" + cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data, physicalResourceId=physical_id) + + elif request_type == "Delete": + # --- Delete App --- + try: + sm.delete_app( + DomainId=domain_id, + SpaceName=space_name, + AppType="JupyterLab", + AppName="default" + ) + print("App delete requested") + except Exception as e: + print("Delete app error:", e) + + wait_for_status( + sm.describe_app, "Status", "Deleted", + DomainId=domain_id, SpaceName=space_name, + AppType="JupyterLab", AppName="default" + ) + + # --- Delete Space --- + try: + sm.delete_space(DomainId=domain_id, SpaceName=space_name) + print("Space delete requested") + except Exception as e: + print("Delete space error:", e) + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, + physicalResourceId=f"{domain_id}-{space_name}") + + else: + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, + physicalResourceId="noop") + + except Exception as e: + print("Error:", str(e)) + cfnresponse.send(event, context, cfnresponse.FAILED, + {"Error": str(e)}, physicalResourceId="failed") + + ############################## + # Custom Resource + ############################## + SageMakerSpaceAppCustom: + Type: Custom::SageMakerSpaceApp + DependsOn: SageMakerUserProfile + Properties: + ServiceToken: !GetAtt SageMakerSpaceAppLambda.Arn + DomainId: !Ref DomainId + UserProfileName: !Ref UserProfileName + SpaceName: !Ref SpaceName + InstanceType: !Ref InstanceType + Region: !Ref AWS::Region + CostResource: !Sub '${AWS::StackName}' + ResearcherName: !Ref ResearcherName + + +Outputs: + StackName: + Description: Name of the Stack for User Profile + Value: !Sub '${AWS::StackName}' + + UserProfileName: + Description: Name of the SageMaker Studio User Profile + Value: !Ref UserProfileName + + ExecutionRoleArn: + Description: ARN of the execution role for the UserProfile + Value: !GetAtt SageMakerExecutionRole.Arn + + SpaceName: + Description: Name of the created JupyterLab Space (from custom resource) + Value: !GetAtt SageMakerSpaceAppCustom.SpaceName + + DomainId: + Description: Domain ID used for the UserProfile + Value: !GetAtt SageMakerSpaceAppCustom.DomainId + + InstanceType: + Description: Instance type for JupyterLab app for the UserProfile + Value: !Ref InstanceType + \ No newline at end of file diff --git a/cft-templates/windows-remotedesktop.yml b/cft-templates/windows-remotedesktop.yml new file mode 100644 index 0000000..f1470fc --- /dev/null +++ b/cft-templates/windows-remotedesktop.yml @@ -0,0 +1,144 @@ +Metadata: + License: Apache-2.0 +AWSTemplateFormatVersion: "2010-09-09" +Description: "AWS CloudFormation Sample Template EIP_With_Association: This template demonstrates how to associate an Elastic IP address with an Amazon EC2 instance. You can use this same technique to associate an EC2 instance with an Elastic IP address that is not created inside the template by replacing the EIP reference with the IP address of an external EIP." + +Parameters: + Namespace: + Type: String + Description: An environment name that will be prefixed to resource names + Password: + Type: String + NoEcho: True + Description: The administrator password must be at least six characters long and include characters from at least three of the following categories- English uppercase letters, English lowercase letters, base-10 digits and non-alphabetic symbols. + InstanceType: + Description: Choose the instance type for this instance. e.g. t3.small + Type: String + Default: t3.small + AllowedValues: [t3.nano, t3.micro, t3.small, t3.medium] + ConstraintDescription: must be a valid EC2 instance type. + KeyPair: + Description: Name of an existing EC2 KeyPair to enable SSH access to the instance. If no key pairs exist, please create one from the button next to the dropdown. Please contact your Administrator if you are unable to create one. + Type: AWS::EC2::KeyPair::KeyName + ConstraintDescription: must be the name of an existing EC2 KeyPair. + AllowedSSHLocation: + Description: The IP address range that can be used to SSH to the EC2 instances + Type: String + MinLength: "9" + MaxLength: "18" + Default: 0.0.0.0/0 + AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) + ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. + +Resources: + SSMPolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + ManagedPolicyName: !Join ["-", [Ref: Namespace, "SSM-Policy"]] + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - ssm:* + Resource: "*" + + IAMRole: + Type: "AWS::IAM::Role" + Properties: + RoleName: !Join ["-", [Ref: Namespace, "ec2-role"]] + Path: "/" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + Action: + - "sts:AssumeRole" + ManagedPolicyArns: + - Ref: SSMPolicy + + InstanceProfile: + Type: "AWS::IAM::InstanceProfile" + Properties: + InstanceProfileName: !Join ["-", [Ref: Namespace, "ec2-profile"]] + Path: "/" + Roles: + - Ref: IAMRole + + EC2Instance: + Type: AWS::EC2::Instance + Properties: + UserData: + Fn::Base64: !Sub | + + # Redirect stdout and stderr to a log file and the console + $scriptPath = "C:\Users\Administrator\log\user-data.log" + Start-Transcript -Path $scriptPath -Append + + net user Administrator ${Password} + + echo "setting user token for nice-dcv" + C:\Users\Administrator\set_user_token.bat + + echo "signal cft to success/failure" + cfn-signal.exe -e $lastexitcode --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region} + + # End the transcript (stop logging) + Stop-Transcript + + InstanceType: !Ref "InstanceType" + PropagateTagsToVolumeOnCreation: true + SecurityGroups: + - !Ref "InstanceSecurityGroup" + KeyName: !Ref "KeyPair" + ImageId: "{{resolve:ssm:/RL/RG/StandardCatalog/windows-nice-dcv-ami}}" + IamInstanceProfile: !Ref InstanceProfile + Tags: + - Key: Name + Value: !Join ["-", [Ref: AWS::StackName, "windows-server"]] + - Key: Description + Value: windows workspace instance + - Key: cost_resource + Value: !Sub ${AWS::StackName} + + InstanceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Enable SSH access + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: "80" + ToPort: "80" + CidrIp: !Ref "AllowedSSHLocation" + - IpProtocol: tcp + FromPort: "3389" + ToPort: "3389" + CidrIp: !Ref "AllowedSSHLocation" + - IpProtocol: tcp + FromPort: "5986" + ToPort: "5986" + CidrIp: !Ref "AllowedSSHLocation" + - IpProtocol: tcp + FromPort: "8443" + ToPort: "8443" + CidrIp: !Ref "AllowedSSHLocation" + +Outputs: + InstanceId: + Description: InstanceId of the newly created EC2 instance + Value: !Ref "EC2Instance" + InstanceIPAddress: + Description: IP address of the newly created EC2 instance + Value: !GetAtt [EC2Instance, PublicIp] + InstanceDNSName: + Description: DNS name of the newly created EC2 instance + Value: !GetAtt [EC2Instance, PublicDnsName] + AvailabilityZone: + Description: AvailabilityZone of newly created EC2 instance + Value: !GetAtt [EC2Instance, AvailabilityZone] + ApplicationPort: + Description: The Port in which the application is running + Value: "8443" diff --git a/dump/configs.json b/dump/configs.json index 98aab47..e172eca 100644 --- a/dump/configs.json +++ b/dump/configs.json @@ -266,7 +266,7 @@ }, "key": "projectStorage", "value": { - "productList": ["ec2", "rstudio", "nextflow", "cromwell", "ec2-dcv", "sagemaker", "ec2-igv", "ec2-secure-desktop", "ec2-jupyterlab", "ec2-vscode"], + "productList": ["ec2", "rstudio", "nextflow", "cromwell", "ec2-dcv", "sagemaker", "ec2-igv", "ec2-secure-desktop", "ec2-jupyterlab", "ec2-vscode","ec2-remote-desktop","aws-pcs"], "s3Mounts": { "ProjectStorage": { "id": "ProjectStorage", @@ -389,7 +389,7 @@ "projectStorage" : "https://researchgateway.readthedocs.io/en/latest/GettingStarted.html#project-storage", "addProjectLink" : "https://researchgateway.readthedocs.io/en/latest/Features.html#how-to-add-a-new-project" }, - "studySelectionCount" : 2 + "studySelectionCount" : 5 }, { "_id" : { @@ -397,7 +397,7 @@ }, "key" : "usersConfig", "value" : { - "maxBulkUserCount" : 20, + "maxBulkUserCount" : 100, "csvHeaderValues" : [ "email", "first_name", @@ -453,7 +453,8 @@ "ec2-secure-desktop", "ec2-dcv", "ec2-vscode", - "ec2-jupyterlab" + "ec2-jupyterlab", + "ec2-remote-desktop" ] }, @@ -470,9 +471,143 @@ "cromwell", "rstudio", "ec2-dcv", - "nextflow" + "nextflow", + "ec2-remote-desktop", + "ec2-secure-desktop" ] } -} +}, + { + "_id": { + "$oid": "664c7d14fc619e0ba56fb9cc" + }, + "key": "settingCreateSkipUpdateBucketPolicy", + "value": false + }, + { + "_id": { + "$oid": "66cd91a8c5a38d1b21e03775" + }, + "key": "retryConfig", + "value": { + "intervalInSeconds": 6, + "maxTimes": 10 + } + }, + { + "_id": { + "$oid": "67da8c474f09ce27c0236c81" + }, + "key": "s3ThrottleConfig", + "value": { + "limit": 2, + "interval": 3000 + } + }, + { + "_id": { + "$oid": "68664ed41c455cba2ec75a02" + }, + "key": "EVENT_WRITER", + "value": true + }, + { + "_id": { + "$oid": "67b991428574fbf9260f6772" + }, + "key": "numDaysForCostSync", + "value": 10 + }, + { + "_id": { + "$oid": "680f5d794266d6c035d7518d" + }, + "key": "egressReviewersList", + "value": [], + "helpText": [ + "List of reviewers for egress process" + ] + }, + { + "_id": { + "$oid": "66963856fe7568c459062c0c" + }, + "key": "reviewWorkspace", + "value": { + "preferedReviewWorkspace": "Windows Desktop For Secure Research", + "defaultReviewWorkspace": "Secure Research Linux Desktop" + } + }, + { + "_id": { + "$oid": "66ab770d7fbb9d06900fb937" + }, + "key": "egressRequestMails", + "value": [ + { + "key": "data admin", + "value": { + "initiated": "request initiated", + "pending": "Hi,A new egress request, , has been submitted by on in the project, , and needs your approval.Please sign in to the Research Portal and click on the project card. Click on the Egress Requests tab. Find the egress request with the id mentioned above. You can Approve or Reject the request from the context menu (3-dots icon) of the request.To review the files, click on “Review” in the context menu. This action will launch a new workspace in the project. Once the workspaceis active, please connect to it via Remote Desktop. The files submitted in the request will be visible under /home/ec2-user/studies/.Note that all current pending requests are mounted to the same workspace under different folders labelled with the request-Id.You can then review the files using the tool of your choice which will be preinstalled on the machine. Once you review the files, log in to the Research Gateway and approve the request from the Egress Requests tab.The Research Gateway team.", + "approved": "approved by data admin", + "rejected": "rejected by data admin" + } + }, + { + "key": "researcher", + "value": { + "initiated": "requested initiated for researcher", + "pending": "pending for researcher", + "approved": "Hi,The Data Administrator for project has approved your egress request, . You can now download the files from the Egress Store tab of the workspace you submitted the request from. Please note that the Download option will be disabled if you submit a new request.The Research Gateway team.", + "rejected": "rejected for researcher" + } + }, + { + "key": "signature", + "value": "The Research Gateway Team." + } + ] + }, + { + "_id": { + "$oid": "663b604476964689564dc998" + }, + "key": "chatAssistantConfig", + "value": { + "chatAssistantURL": "https://chat.rlcatalyst.com/Documentation_Bot/", + "chatAssistantLogo": "../assets/images/chatAssistant.png" + } + }, + { + "_id": { + "$oid": "67b01bd7dbf6eb46f07fe035" + }, + "key": "deleteLocalProvisionedProductIfNotInSC", + "value": false + }, + { + "_id": { + "$oid": "666a849290cd656dc7d23193" + }, + "key": "s3BucketLimit", + "value": 150 + }, + { + "_id": { + "$oid": "663b604476964689564dc998" + }, + "key": "chatAssistantConfig", + "value": { + "chatAssistantURL": "https://chat.rlcatalyst.com/Documentation_Bot/", + "chatAssistantLogo": "../assets/images/chatAssistant.png" + } + }, + { + "_id": { + "$oid": "663b631f28fd863b08cb6a9d" + }, + "key": "kmsKeys", + "Value": [ ] + } ] diff --git a/dump/standardcatalogitems.json b/dump/standardcatalogitems.json index e488ae3..21ed41b 100644 --- a/dump/standardcatalogitems.json +++ b/dump/standardcatalogitems.json @@ -1638,7 +1638,616 @@ "permission_required" : {}, "cost_resource" : true } +}, +{ + "_id": { + "$oid": "67924553c5811175921b08ec" + }, + "name": "Windows Remote Desktop", + "description": "Amazon Elastic Compute Cloud (Amazon EC2) is a web service that provides secure, resizable compute capacity in the cloud.", + "fileName": "windows-remotedesktop.yml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "10 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://researchgateway.readthedocs.io/en/latest/windows.html" + }, + { + "Key": "Service", + "Value": "EC2-REMOTE-DESKTOP" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + }, + { + "Key": "ALB", + "Value": "true" + }, + { + "Key": "ApplicationPort", + "Value": "8443" + }, + { + "Key": "ApplicationProtocol", + "Value": "HTTPS" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "Namespace", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "EnvironmentInstanceFiles", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "IamPolicyDocument", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + }, + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "isUpdateAvailable": false + } +}, +{ + "_id": { + "$oid": "686e89d00f2e074ec82a7be7" + }, + "name": "AWS PCS Quick Start", + "description": "Launch a basic AWS PCS cluster with 4 nodes (8 vCPUs, 32GB per node). Useful for exploration and test jobs.", + "fileName": "pcs_quick_lt.yaml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "20 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://docs.aws.amazon.com/pcs/latest/userguide/what-is-service.html" + }, + { + "Key": "Service", + "Value": "aws-pcs" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "EnvironmentInstanceFiles", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "IamPolicyDocument", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "Namespace", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "cost_resource": true + } +}, +{ + "_id": { + "$oid": "679b643e1d6d39b5195b063f" + }, + "name": "Rocky 8 with NICE DCV", + "description": "NICE DCV is a high-performance remote display protocol using which the customers can run graphics-intensive applicationsremotely on EC2 instances, and stream their user interface to simpler client machines, eliminating the need for expensive dedicated workstations.The user can connect to the DCV server by using the RG Connect URL button. The user name is ec2-user and password is the Instance ID.", + "fileName": "ec2-rockyLinux.yml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "15 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://researchgateway.readthedocs.io/en/latest/NiceDCV.html" + }, + { + "Key": "Service", + "Value": "EC2-DCV" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + }, + { + "Key": "ALB", + "Value": "true" + }, + { + "Key": "ApplicationPort", + "Value": "8443" + }, + { + "Key": "ApplicationProtocol", + "Value": "HTTPS" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "cost_resource": true, + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "EnvironmentInstanceFiles", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "IamPolicyDocument", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "Namespace", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "code": "AMI_ID_REQUIRED", + "is_ami_required": true, + "ami_id_list": [ + { + "us-west-1": "ami-0ff9ab0ce03edb1d8" + }, + { + "us-east-1": "ami-022718011b0e759ce" + } + ], + "ami_path": "/RL/RG/StandardCatalog/rocky-nice-dcv-ami" + }, + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + }, + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "isUpdateAvailable": true + } +}, +{ + "_id": { + "$oid": "67ad891d56595357b3b12aaf" + }, + "name": "Nginx Web Server", + "description": "Amazon Elastic Compute Cloud (Amazon EC2) is a web service that provides resizable compute capacity in the cloud.", + "fileName": "ec2-nginxWebServer.yml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "15 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://researchgateway.readthedocs.io/en/latest/rstudio.html" + }, + { + "Key": "Service", + "Value": "EC2" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + }, + { + "Key": "ALB", + "Value": "true" + }, + { + "Key": "ApplicationPort", + "Value": "443" + }, + { + "Key": "ApplicationProtocol", + "Value": "HTTPS" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "EnvironmentInstanceFiles", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "IamPolicyDocument", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "Namespace", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + }, + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "cost_resource": true, + "isUpdateAvailable": false + } +}, +{ + "_id": { + "$oid": "68e50cf5913c5717a6389b8f" + }, + "name": "SageMaker AI", + "description": "Amazon SageMaker AI provides a fully managed JupyterLab environment within its Unified Studio, designed to facilitate machine learning (ML) workflows. This integration allows users to leverage the interactive development environment (IDE) of JupyterLab for various tasks, including data integration, analytics, and ML model development.", + "fileName": "sagemakerUserProfile.yaml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "5 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://docs.aws.amazon.com/sagemaker/latest/dg/whatis.html" + }, + { + "Key": "Service", + "Value": "sagemaker-studio" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "DomainId", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "UserProfileName", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "ResearcherName", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "SpaceName", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "cost_resource": true + } +}, +{ + "_id": { + "$oid": "68c06e1ddc3e48f47032b445" + }, + "name": "Sagemaker AI Domain", + "description": "Create a fully managed Amazon SageMaker Domain for this project to enable secure and scalable machine learning environments using JupyterLab. It provides seamless access to SageMaker Studio for building, training, and deploying ML models efficiently.", + "fileName": "awsSagemakerDomainAI.yaml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "2 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://docs.aws.amazon.com/sagemaker/latest/dg/gs-studio-onboard.html" + }, + { + "Key": "Service", + "Value": "sagemaker-ai" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + }, + { + "Key": "rolespecific", + "Value": "0" + }, + { + "Key": "Singleton", + "Value": true + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "EnvironmentInstanceFiles", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "IamPolicyDocument", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "Namespace", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "ProjectId", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "cost_resource": true + } +}, +{ + "_id": { + "$oid": "684bdf8915403b3590625b2a" + }, + "name": "AWS PCS Advanced", + "description": "Create an AWS managed HPC cluster to run and scale your high performance workloads and build scientific and engineering models on AWS using Slurm.", + "fileName": "pcs.yaml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "20 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://docs.aws.amazon.com/pcs/latest/userguide/what-is-service.html" + }, + { + "Key": "Service", + "Value": "aws-pcs" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "EnvironmentInstanceFiles", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "IamPolicyDocument", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "Namespace", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "cost_resource": true + } +}, +{ + "_id": { + "$oid": "68f9f9e7fc40a41a1ed58a05" + }, + "name": "Amazon Bedrock", + "description": "Amazon Bedrock is a comprehensive, secure, and flexible platform for building generative AI applications and agents.", + "fileName": "bedrock.yaml", + "tags": [ + { + "Key": "EstimatedTimeToProvision", + "Value": "5 Minutes" + }, + { + "Key": "DetailsLink", + "Value": "https://aws.amazon.com/bedrock/" + }, + { + "Key": "Service", + "Value": "bedrock" + }, + { + "Key": "TypeOfProduct", + "Value": "Research" + } + ], + "owner": "RL", + "portfolio": "RGPortfolio", + "availableRegions": [], + "assignedOU": [], + "metaData": { + "pre_provisioning": [ + { + "code": "CFT_PARAMS", + "params": [ + { + "name": "UserProfileName", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "S3Mounts", + "type": "RL::SC::PARAM::HD" + }, + { + "name": "SpaceName", + "type": "RL::SC::PARAM::HD" + } + ] + } + ], + "post_provisioning": [], + "checks_before_assigning_product": [ + { + "Key": "projectTypeCompatibility", + "Value": [ + "Standard" + ] + } + ], + "checks_after_assigning_product": [], + "permission_required": {}, + "cost_resource": true + } } - ] From a82eb6f122618b3d17d28c92053abe64d5042a75 Mon Sep 17 00:00:00 2001 From: Anusha-janardhan Date: Fri, 31 Oct 2025 07:44:08 +0000 Subject: [PATCH 3/3] feat(config): add privateSPCert and SNS event trigger URLs to configuration files --- config/config.json | 3 + config/settings-config.json | 268 +++++++++++++++++++----------------- 2 files changed, 142 insertions(+), 129 deletions(-) diff --git a/config/config.json b/config/config.json index aec3106..daaeb2d 100644 --- a/config/config.json +++ b/config/config.json @@ -73,6 +73,7 @@ "path": "/samllogin", "entryPoint": "https://dev-64629994.okta.com/app/dev-64629994_researchgateway_1/exkaoo9k27Z5n8YCc5d7/sso/saml", "issuer": "http://www.okta.com/exkaoo9k27Z5n8YCc5d7", + "privateSPCert": "/rlc/cc/server/app/config/key.pem", "cert": "/rlc/cc/server/app/config/okta.cert", "logoutUrl": "https://enterprise-test1.rlcatalyst.com/logout", "groupToRoleMapping": { @@ -109,6 +110,8 @@ "credentialManagementURL": "http://sp2_cc-3102:3002/authentication", "projectSyncURL": "http://sp2_cc-3102:3002/sync-product", "researchGatewayAPIToken": "REPLACE_WITH_API_TOKEN", + "snsRetryEventTriggerURL": "http://sp2_cc-3102:3002/retrySNSEvent", + "projectEventTriggerURL": "http://sp2_cc-3102:3002/project", "nsUseSecretsManager": true, "thresholdPercentage": 80, "PrincipalArn": "RG-Service-Catalog-Role", diff --git a/config/settings-config.json b/config/settings-config.json index e2833c4..dc53dec 100644 --- a/config/settings-config.json +++ b/config/settings-config.json @@ -68,141 +68,151 @@ ] }, "aws-pcs": { - "actions": { - "running": { - "connect": [ - { - "menu": "SSH Terminal", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": ["ClusterId"] - }, - { - "menu": "Submit Job", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": ["ClusterId"] - } - ], - "action": [ - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png", - "outputsRequired": [] - } - ] - }, - "default": { - "connect": [ - { - "menu": "SSH Terminal", - "imageUrl": "../../assets/images/technology@2x.png", - "outputsRequired": [] - }, - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png", - "outputsRequired": [] - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png", - "outputsRequired": [] - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png", - "outputsRequired": [] - } - ] + "actions": { + "running": { + "connect": [ + { + "menu": "SSH Terminal", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [ + "ClusterId" + ] + }, + { + "menu": "Submit Job", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [ + "ClusterId" + ] + } + ], + "action": [] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png", + "outputsRequired": [] } + ] }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": [ - "running", - "active" - ], - "stopped_states": [ - "stopped" - ], - "terminated_states": [ - "terminated" - ] + "default": { + "connect": [ + { + "menu": "SSH Terminal", + "imageUrl": "../../assets/images/technology@2x.png", + "outputsRequired": [] + }, + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png", + "outputsRequired": [] + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png", + "outputsRequired": [] + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png", + "outputsRequired": [] + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] }, "ec2-remote-desktop": { - "actions": { - "running": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] - }, - "stopped": { - "connect": [], - "action": [ - { - "action": "Start", - "imageUrl": "../../assets/images/play@2x.png" - }, - { - "action": "Instance Type", - "imageUrl": "../../assets/images/pencil.png", - "outputsRequired": [ - "InstanceId" - ] - } - ] - }, - "default": { - "connect": [ - { - "menu": "Remote Desktop", - "imageUrl": "../../assets/images/Screen-icon.png" - } - ], - "action": [ - { - "action": "Stop", - "imageUrl": "../../assets/images/no-stopping@2x.png" - }, - { - "action": "Reboot", - "imageUrl": "../../assets/images/reset@2x.png" - } - ] + "actions": { + "running": { + "connect": [ + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + }, + "stopped": { + "connect": [], + "action": [ + { + "action": "Start", + "imageUrl": "../../assets/images/play@2x.png" + }, + { + "action": "Instance Type", + "imageUrl": "../../assets/images/pencil.png", + "outputsRequired": [ + "InstanceId" + ] } + ] }, - "transient_states": [ - "pending", - "shutting-down", - "stopping", - "deleting" - ], - "active_states": ["running", "active"], - "stopped_states": ["stopped"], - "terminated_states": ["terminated"] + "default": { + "connect": [ + { + "menu": "Remote Desktop", + "imageUrl": "../../assets/images/Screen-icon.png" + } + ], + "action": [ + { + "action": "Stop", + "imageUrl": "../../assets/images/no-stopping@2x.png" + }, + { + "action": "Reboot", + "imageUrl": "../../assets/images/reset@2x.png" + } + ] + } + }, + "transient_states": [ + "pending", + "shutting-down", + "stopping", + "deleting" + ], + "active_states": [ + "running", + "active" + ], + "stopped_states": [ + "stopped" + ], + "terminated_states": [ + "terminated" + ] }, "sagemaker": { "NotebookInstanceLifecycleConfigName": "Research-Portal-Setup",