From e66271a4ccdf7f56b1b4e9d0e8f2f56224db833c Mon Sep 17 00:00:00 2001 From: Sean Celik Date: Wed, 31 Jul 2024 23:56:05 -0700 Subject: [PATCH 01/28] feat: add workspaces UI Service to the docker deployment --- deployments/docker/ai-unlimited.yaml | 24 +++++++++++++++++++++--- deployments/docker/generate_api_key.ps1 | 8 ++++++++ deployments/docker/generate_api_key.sh | 11 +++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 deployments/docker/generate_api_key.ps1 create mode 100644 deployments/docker/generate_api_key.sh diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index 0d623ee..98027bb 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -6,7 +6,7 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces - image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-latest} + image: ${WORKSPACES_IMAGE_NAME:-docker.io/teradata/regulus-workspaces}:latest command: workspaces serve -v restart: unless-stopped ports: @@ -16,10 +16,28 @@ services: environment: accept_license: "Y" TZ: ${AI_UNLIMITED_TZ:-UTC} + TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" volumes: - ${AI_UNLIMITED_HOME:-./volumes/ai-unlimited-workspaces}:/etc/td networks: - ai-unlimited - + ai-unlimited-front-end: + deploy: + replicas: 1 + platform: linux/amd64 + container_name: workspaces-ui + image: ${WORKSPACES_UI_IMAGE_NAME:-teradata/regulus-workspaces-ui}:${WORKSPACES_UI_IMAGE_TAG:-latest} + ports: + - "${TD_VCD_UI_PORT:-80}:80/tcp" + environment: + TD_VCD_UI_BASE_URL: "http://localhost" + TD_VCD_UI_PORT: "${TD_VCD_UI_PORT:-80}" + TD_VCD_API_BASE_URL: "http://localhost" + TD_VCD_API_PORT: "${TD_VCD_API_PORT:-3282}" + TD_VCD_AUTH_PORT: "${TD_VCD_AUTH_PORT:-3000}" + TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" + networks: + - ai-unlimited-network networks: - ai-unlimited: + ai-unlimited-network: + name: ai-unlimited-network \ No newline at end of file diff --git a/deployments/docker/generate_api_key.ps1 b/deployments/docker/generate_api_key.ps1 new file mode 100644 index 0000000..5e494f6 --- /dev/null +++ b/deployments/docker/generate_api_key.ps1 @@ -0,0 +1,8 @@ +Write-Host "Generating API key..." + +# all characters +$API_KEY=(-join ((33..126) | Get-Random -Count 32 | % {[char]$_})) +$env:AI_UNLIMITED_INIT_API_KEY = $API_KEY + +Write-Host "API Key is generated, please export it by running the following command: \n" +Write-Host '$env:AI_UNLIMITED_INIT_API_KEY = $API_KEY' \ No newline at end of file diff --git a/deployments/docker/generate_api_key.sh b/deployments/docker/generate_api_key.sh new file mode 100644 index 0000000..c3c25d0 --- /dev/null +++ b/deployments/docker/generate_api_key.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 Date: Thu, 22 Aug 2024 15:43:01 -0700 Subject: [PATCH 02/28] Add finishing touches --- deployments/docker/ai-unlimited.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index 98027bb..f908805 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -6,33 +6,33 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces - image: ${WORKSPACES_IMAGE_NAME:-docker.io/teradata/regulus-workspaces}:latest + image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.2.23} command: workspaces serve -v restart: unless-stopped ports: - - "443:443/tcp" - - "3000:3000/tcp" - - "3282:3282/tcp" + - "${TD_VCD_AUTH_PORT:-3000}:${TD_VCD_AUTH_PORT:-3000}/tcp" + - "${TD_VCD_API_PORT:-3282}:${TD_VCD_API_PORT:-3282}/tcp" environment: accept_license: "Y" TZ: ${AI_UNLIMITED_TZ:-UTC} + TD_VCD_API_PORT: "${TD_VCD_API_PORT:-3282}" + TD_VCD_AUTH_PORT: "${TD_VCD_AUTH_PORT:-3000}" TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" volumes: - ${AI_UNLIMITED_HOME:-./volumes/ai-unlimited-workspaces}:/etc/td networks: - ai-unlimited - ai-unlimited-front-end: + ai-unlimited-ui: deploy: replicas: 1 platform: linux/amd64 container_name: workspaces-ui - image: ${WORKSPACES_UI_IMAGE_NAME:-teradata/regulus-workspaces-ui}:${WORKSPACES_UI_IMAGE_TAG:-latest} + image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_IMAGE_TAG:-v0.0.3} ports: + - "443:443/tcp" - "${TD_VCD_UI_PORT:-80}:80/tcp" environment: - TD_VCD_UI_BASE_URL: "http://localhost" TD_VCD_UI_PORT: "${TD_VCD_UI_PORT:-80}" - TD_VCD_API_BASE_URL: "http://localhost" TD_VCD_API_PORT: "${TD_VCD_API_PORT:-3282}" TD_VCD_AUTH_PORT: "${TD_VCD_AUTH_PORT:-3000}" TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" From f8fd1c1a9823869a9bfd62ec3eb3ca95e6e9236b Mon Sep 17 00:00:00 2001 From: hc186011 Date: Fri, 23 Aug 2024 12:43:45 -0700 Subject: [PATCH 03/28] Update version --- deployments/docker/ai-unlimited.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index f908805..963acda 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -6,7 +6,7 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces - image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.2.23} + image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.3.0} command: workspaces serve -v restart: unless-stopped ports: From a46d08364ab3f7622e468ae49005c4eadc3c974a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Isaac=20Hern=C3=A1ndez=20Cruz?= <96310311+RisokHdz@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:59:18 -0600 Subject: [PATCH 04/28] Fixing Powershell Code Strings --- deployments/docker/generate_api_key.ps1 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/deployments/docker/generate_api_key.ps1 b/deployments/docker/generate_api_key.ps1 index 5e494f6..e63f678 100644 --- a/deployments/docker/generate_api_key.ps1 +++ b/deployments/docker/generate_api_key.ps1 @@ -1,8 +1,14 @@ Write-Host "Generating API key..." -# all characters -$API_KEY=(-join ((33..126) | Get-Random -Count 32 | % {[char]$_})) +# Define character ranges for alphanumeric characters +$chars = @() +$chars += 48..57 # 0-9 +$chars += 65..90 # A-Z +$chars += 97..122 # a-z + +# Generate API key +$API_KEY = -join ($chars | Get-Random -Count 64 | ForEach-Object { [char]$_ }) $env:AI_UNLIMITED_INIT_API_KEY = $API_KEY -Write-Host "API Key is generated, please export it by running the following command: \n" -Write-Host '$env:AI_UNLIMITED_INIT_API_KEY = $API_KEY' \ No newline at end of file +Write-Host "API Key is generated, please export it by running the following command: `n" +Write-Host '$env:AI_UNLIMITED_INIT_API_KEY = $API_KEY' From 5377c871ff6a69759cc4d4f5278311d84ed7ecb1 Mon Sep 17 00:00:00 2001 From: RisokHdz Date: Wed, 28 Aug 2024 16:13:16 -0600 Subject: [PATCH 05/28] Using v0.0.5 tag for workspaces UI image --- deployments/docker/ai-unlimited.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index 963acda..4d70be7 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -27,7 +27,7 @@ services: replicas: 1 platform: linux/amd64 container_name: workspaces-ui - image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_IMAGE_TAG:-v0.0.3} + image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_IMAGE_TAG:-v0.0.5} ports: - "443:443/tcp" - "${TD_VCD_UI_PORT:-80}:80/tcp" From 7c08ce0d2b74f58a36ab74813df6ad526c8e90c3 Mon Sep 17 00:00:00 2001 From: RisokHdz Date: Thu, 19 Sep 2024 20:14:18 -0600 Subject: [PATCH 06/28] fixing some docker-compose required fileds --- deployments/docker/ai-unlimited.yaml | 10 ++++------ deployments/docker/jupyter.yaml | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index dbb1b63..9f444d8 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -6,11 +6,7 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces -<<<<<<< HEAD image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.3.0} -======= - image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.2.23} ->>>>>>> develop command: workspaces serve -v restart: unless-stopped ports: @@ -25,13 +21,14 @@ services: volumes: - ${AI_UNLIMITED_HOME:-./volumes/ai-unlimited-workspaces}:/etc/td networks: - - ai-unlimited + - ai-unlimited-network + ai-unlimited-ui: deploy: replicas: 1 platform: linux/amd64 container_name: workspaces-ui - image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_IMAGE_TAG:-v0.0.5} + image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_IMAGE_TAG:-v0.0.1} ports: - "443:443/tcp" - "${TD_VCD_UI_PORT:-80}:80/tcp" @@ -42,6 +39,7 @@ services: TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" networks: - ai-unlimited-network + networks: ai-unlimited-network: name: ai-unlimited-network \ No newline at end of file diff --git a/deployments/docker/jupyter.yaml b/deployments/docker/jupyter.yaml index 655557d..e09d939 100644 --- a/deployments/docker/jupyter.yaml +++ b/deployments/docker/jupyter.yaml @@ -14,7 +14,8 @@ services: volumes: - ${JUPYTER_HOME:-./volumes/jupyter}:/home/jovyan/JupyterLabRoot/userdata networks: - - ai-unlimited + - ai-unlimited-network networks: - ai-unlimited: + ai-unlimited-network: + name: ai-unlimited-network \ No newline at end of file From 3bb0854bedf09bb1855b97cb7129a2c43ee518a4 Mon Sep 17 00:00:00 2001 From: hc186011 Date: Tue, 24 Sep 2024 09:48:09 -0700 Subject: [PATCH 07/28] Update Readme --- deployments/docker/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deployments/docker/README.md b/deployments/docker/README.md index 1eaf259..971df83 100644 --- a/deployments/docker/README.md +++ b/deployments/docker/README.md @@ -2,6 +2,20 @@ ## AI Unlimited +### Pre-requisite Steps +An initial API Key Environment Variable is required to start the Docker Compose Stack. You can generate one by doing the following: + +#### On OSX/Linux + +``` +source generate_api_key.sh +``` +#### On Windows + +``` +./generate_api_key.ps1 +``` +Follow the instructions from the scripts output. ### With AWS ``` From bb6e44741b652b211a143ac229cb0e379f3c6c1c Mon Sep 17 00:00:00 2001 From: Aopanis Date: Wed, 30 Oct 2024 11:32:16 -0700 Subject: [PATCH 08/28] Add workspaces UI to templates (#41) * Added new unit file for ui container, added relevant network and nlb rules, and removed || true pattern in favor of - prefix. * Removed acr login from testing. * Regenerate templates after rebase. * Reformating cloud-init data. * Fixed rebase error. * Renamed http to auth for port 3000. * Fix output from template for private ip. * Regenerate arm templates. * Changed default version for UI docker image to v0.0.5 and regenerated templates. * adding workspaces-ui to aws templates * rolling back alb changes to develop * adding specific version instead pointed to latest * changing name of the ui from workspaces-ui to ai-unlimited-ui * changing name of the ui from workspaces-ui to ai-unlimited-ui * renaming the image name * updated the ui default version * deleted alb templates from aws deployments * Feat/bastion azure (#46) * Added public-key deployment script, added private keys to keyvault, removed public ssh firewall and output strings, hardcoded/updated version strings, and added secrets write permission to resource declaration. * Missed hardcoded version for jupyter. --------- Co-authored-by: Anton Panis * added permissions to support static ip * Moved the init api key to /etc/td/ai-unlimited/init_api_key.txt, and changed the environment file location to reflect this. Additionally updated UI version to v0.0.5. (#48) Co-authored-by: Anton Panis --------- Co-authored-by: Anton Panis Co-authored-by: surendra alokam --- .../aws/parameters/ai-unlimited-with-alb.json | 114 -- .../aws/parameters/all-in-one-with-alb.json | 118 -- .../aws/parameters/jupyter-with-alb.json | 114 -- ...rkspaces-without-iam-role-permissions.json | 5 +- .../aws/policies/ai-unlimited-workspaces.json | 5 +- .../ai-unlimited/ai-unlimited-with-alb.yaml | 1247 --------------- .../ai-unlimited/ai-unlimited-with-nlb.yaml | 187 ++- .../ai-unlimited/ai-unlimited-without-lb.yaml | 133 +- .../all-in-one/all-in-one-with-alb.yaml | 1407 ----------------- .../all-in-one/all-in-one-with-nlb.yaml | 187 ++- .../all-in-one/all-in-one-without-lb.yaml | 139 +- .../templates/jupyter/jupyter-with-alb.yaml | 815 ---------- .../scripts/ai-unlimited-scheduler.service | 4 +- .../azure/scripts/ai-unlimited-ui.service | 28 + .../azure/scripts/ai-unlimited.cloudinit.yaml | 11 +- .../azure/scripts/ai-unlimited.service | 6 +- .../azure/scripts/all-in-one.cloudinit.yaml | 9 + deployments/azure/scripts/jupyter.service | 4 +- .../ai-unlimited/ai-unlimited-with-nlb.json | 272 +++- .../ai-unlimited/ai-unlimited-without-lb.json | 251 ++- .../arm/all-in-one/all-in-one-with-nlb.json | 277 +++- .../arm/all-in-one/all-in-one-without-lb.json | 256 ++- .../azure/templates/arm/init/resources.json | 11 +- .../arm/jupyter/jupyter-with-nlb.json | 82 +- .../arm/jupyter/jupyter-without-lb.json | 62 +- .../ai-unlimited/ai-unlimited-with-nlb.bicep | 59 +- .../ai-unlimited-with-nlb.bicepparam | 7 +- .../ai-unlimited-without-lb.bicep | 55 +- .../ai-unlimited-without-lb.bicepparam | 8 +- .../all-in-one/all-in-one-with-nlb.bicep | 64 +- .../all-in-one/all-in-one-with-nlb.bicepparam | 10 +- .../all-in-one/all-in-one-without-lb.bicep | 61 +- .../all-in-one-without-lb.bicepparam | 10 +- .../templates/bicep/modules/firewall.bicep | 36 +- .../azure/templates/bicep/modules/nlb.bicep | 66 +- .../templates/bicep/modules/public-key.bicep | 70 + .../azure/templates/init/resources.bicep | 1 + 37 files changed, 2001 insertions(+), 4190 deletions(-) delete mode 100644 deployments/aws/parameters/ai-unlimited-with-alb.json delete mode 100644 deployments/aws/parameters/all-in-one-with-alb.json delete mode 100644 deployments/aws/parameters/jupyter-with-alb.json delete mode 100644 deployments/aws/templates/ai-unlimited/ai-unlimited-with-alb.yaml delete mode 100644 deployments/aws/templates/all-in-one/all-in-one-with-alb.yaml delete mode 100644 deployments/aws/templates/jupyter/jupyter-with-alb.yaml create mode 100644 deployments/azure/scripts/ai-unlimited-ui.service create mode 100644 deployments/azure/templates/bicep/modules/public-key.bicep diff --git a/deployments/aws/parameters/ai-unlimited-with-alb.json b/deployments/aws/parameters/ai-unlimited-with-alb.json deleted file mode 100644 index c705d68..0000000 --- a/deployments/aws/parameters/ai-unlimited-with-alb.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "ParameterKey": "AiUnlimitedName", - "ParameterValue": "test-unlimited" - }, - { - "ParameterKey": "InstanceType", - "ParameterValue": "t3.small" - }, - { - "ParameterKey": "RootVolumeSize", - "ParameterValue": "20" - }, - { - "ParameterKey": "TerminationProtection", - "ParameterValue": "false" - }, - { - "ParameterKey": "IamRole", - "ParameterValue": "New" - }, - { - "ParameterKey": "IamRoleName", - "ParameterValue": "" - }, - { - "ParameterKey": "IamPermissionsBoundary", - "ParameterValue": "" - }, - { - "ParameterKey": "AvailabilityZone", - "ParameterValue": "" - }, - { - "ParameterKey": "LoadBalancerScheme", - "ParameterValue": "internet-facing" - }, - { - "ParameterKey": "LoadBalancerSubnetOne", - "ParameterValue": "" - }, - { - "ParameterKey": "LoadBalancerSubnetTwo", - "ParameterValue": "" - }, - { - "ParameterKey": "Private", - "ParameterValue": "true" - }, - { - "ParameterKey": "Session", - "ParameterValue": "true" - }, - { - "ParameterKey": "Vpc", - "ParameterValue": "" - }, - { - "ParameterKey": "Subnet", - "ParameterValue": "" - }, - { - "ParameterKey": "KeyName", - "ParameterValue": "" - }, - { - "ParameterKey": "AccessCIDR", - "ParameterValue": "" - }, - { - "ParameterKey": "PrefixList", - "ParameterValue": "" - }, - { - "ParameterKey": "SecurityGroup", - "ParameterValue": "" - }, - { - "ParameterKey": "AiUnlimitedHttpPort", - "ParameterValue": "3000" - }, - { - "ParameterKey": "AiUnlimitedGrpcPort", - "ParameterValue": "3282" - }, - { - "ParameterKey": "AiUnlimitedVersion", - "ParameterValue": "v0.2.23" - }, - { - "ParameterKey": "UsePersistentVolume", - "ParameterValue": "New" - }, - { - "ParameterKey": "PersistentVolumeSize", - "ParameterValue": "20" - }, - { - "ParameterKey": "ExistingPersistentVolumeId", - "ParameterValue": "" - }, - { - "ParameterKey": "PersistentVolumeDeletionPolicy", - "ParameterValue": "Delete" - }, - { - "ParameterKey": "HostedZoneId", - "ParameterValue": "" - }, - { - "ParameterKey": "DnsName", - "ParameterValue": "example.domain.com" - } -] \ No newline at end of file diff --git a/deployments/aws/parameters/all-in-one-with-alb.json b/deployments/aws/parameters/all-in-one-with-alb.json deleted file mode 100644 index 89c0042..0000000 --- a/deployments/aws/parameters/all-in-one-with-alb.json +++ /dev/null @@ -1,118 +0,0 @@ - [ - { - "ParameterKey": "AiUnlimitedName", - "ParameterValue": "test-unlimited" - }, - { - "ParameterKey": "JupyterToken", - "ParameterValue": "usealongSIMPLEtokenwithoutSPECIALchars" - }, - { - "ParameterKey": "InstanceType", - "ParameterValue": "t3.small" - }, - { - "ParameterKey": "RootVolumeSize", - "ParameterValue": "20" - }, - { - "ParameterKey": "TerminationProtection", - "ParameterValue": "false" - }, - { - "ParameterKey": "IamRole", - "ParameterValue": "New" - }, - { - "ParameterKey": "IamRoleName", - "ParameterValue": "" - }, - { - "ParameterKey": "IamPermissionsBoundary", - "ParameterValue": "" - }, - { - "ParameterKey": "AvailabilityZone", - "ParameterValue": "" - }, - { - "ParameterKey": "LoadBalancerScheme", - "ParameterValue": "internet-facing" - }, - { - "ParameterKey": "LoadBalancerSubnetOne", - "ParameterValue": "" - }, - { - "ParameterKey": "LoadBalancerSubnetTwo", - "ParameterValue": "" - }, - { - "ParameterKey": "Private", - "ParameterValue": "true" - }, - { - "ParameterKey": "Session", - "ParameterValue": "true" - }, - { - "ParameterKey": "Vpc", - "ParameterValue": "" - }, - { - "ParameterKey": "Subnet", - "ParameterValue": "" - }, - { - "ParameterKey": "KeyName", - "ParameterValue": "" - }, - { - "ParameterKey": "AccessCIDR", - "ParameterValue": "" - }, - { - "ParameterKey": "PrefixList", - "ParameterValue": "" - }, - { - "ParameterKey": "SecurityGroup", - "ParameterValue": "" - }, - { - "ParameterKey": "AiUnlimitedHttpPort", - "ParameterValue": "3000" - }, - { - "ParameterKey": "AiUnlimitedGrpcPort", - "ParameterValue": "3282" - }, - { - "ParameterKey": "AiUnlimitedVersion", - "ParameterValue": "v0.2.23" - }, - { - "ParameterKey": "UsePersistentVolume", - "ParameterValue": "New" - }, - { - "ParameterKey": "PersistentVolumeSize", - "ParameterValue": "20" - }, - { - "ParameterKey": "ExistingPersistentVolumeId", - "ParameterValue": "" - }, - { - "ParameterKey": "PersistentVolumeDeletionPolicy", - "ParameterValue": "Delete" - }, - { - "ParameterKey": "HostedZoneId", - "ParameterValue": "" - }, - { - "ParameterKey": "DnsName", - "ParameterValue": "example.domain.com" - } - ] \ No newline at end of file diff --git a/deployments/aws/parameters/jupyter-with-alb.json b/deployments/aws/parameters/jupyter-with-alb.json deleted file mode 100644 index 0a5a1a1..0000000 --- a/deployments/aws/parameters/jupyter-with-alb.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "ParameterKey": "JupyterName", - "ParameterValue": "test-unlimited" - }, - { - "ParameterKey": "JupyterToken", - "ParameterValue": "usealongSIMPLEtokenwithoutSPECIALchars" - }, - { - "ParameterKey": "InstanceType", - "ParameterValue": "t3.small" - }, - { - "ParameterKey": "RootVolumeSize", - "ParameterValue": "20" - }, - { - "ParameterKey": "TerminationProtection", - "ParameterValue": "false" - }, - { - "ParameterKey": "IamRole", - "ParameterValue": "New" - }, - { - "ParameterKey": "IamRoleName", - "ParameterValue": "" - }, - { - "ParameterKey": "IamPermissionsBoundary", - "ParameterValue": "" - }, - { - "ParameterKey": "AvailabilityZone", - "ParameterValue": "" - }, - { - "ParameterKey": "LoadBalancerScheme", - "ParameterValue": "internet-facing" - }, - { - "ParameterKey": "LoadBalancerSubnetOne", - "ParameterValue": "" - }, - { - "ParameterKey": "LoadBalancerSubnetTwo", - "ParameterValue": "" - }, - { - "ParameterKey": "Private", - "ParameterValue": "true" - }, - { - "ParameterKey": "Session", - "ParameterValue": "true" - }, - { - "ParameterKey": "Vpc", - "ParameterValue": "" - }, - { - "ParameterKey": "Subnet", - "ParameterValue": "" - }, - { - "ParameterKey": "KeyName", - "ParameterValue": "" - }, - { - "ParameterKey": "AccessCIDR", - "ParameterValue": "" - }, - { - "ParameterKey": "PrefixList", - "ParameterValue": "" - }, - { - "ParameterKey": "SecurityGroup", - "ParameterValue": "" - }, - { - "ParameterKey": "JupyterHttpPort", - "ParameterValue": "3000" - }, - { - "ParameterKey": "JupyterVersion", - "ParameterValue": "latest" - }, - { - "ParameterKey": "UsePersistentVolume", - "ParameterValue": "New" - }, - { - "ParameterKey": "PersistentVolumeSize", - "ParameterValue": "20" - }, - { - "ParameterKey": "ExistingPersistentVolumeId", - "ParameterValue": "" - }, - { - "ParameterKey": "PersistentVolumeDeletionPolicy", - "ParameterValue": "Delete" - }, - { - "ParameterKey": "HostedZoneId", - "ParameterValue": "" - }, - { - "ParameterKey": "DnsName", - "ParameterValue": "example.domain.com" - } -] \ No newline at end of file diff --git a/deployments/aws/policies/ai-unlimited-workspaces-without-iam-role-permissions.json b/deployments/aws/policies/ai-unlimited-workspaces-without-iam-role-permissions.json index 3e0476d..26c9caa 100644 --- a/deployments/aws/policies/ai-unlimited-workspaces-without-iam-role-permissions.json +++ b/deployments/aws/policies/ai-unlimited-workspaces-without-iam-role-permissions.json @@ -92,7 +92,10 @@ "ec2:AssociateRouteTable", "ec2:CreateRoute", "ec2:DisassociateRouteTable", - "ec2:DeleteRoute" + "ec2:DeleteRoute", + "ec2:DescribeAddresses", + "ec2:AssociateAddress", + "ec2:DisassociateAddress" ], "Resource": "*", "Effect": "Allow" diff --git a/deployments/aws/policies/ai-unlimited-workspaces.json b/deployments/aws/policies/ai-unlimited-workspaces.json index 7cdbe22..46aaae3 100644 --- a/deployments/aws/policies/ai-unlimited-workspaces.json +++ b/deployments/aws/policies/ai-unlimited-workspaces.json @@ -95,7 +95,10 @@ "ec2:AssociateRouteTable", "ec2:CreateRoute", "ec2:DisassociateRouteTable", - "ec2:DeleteRoute" + "ec2:DeleteRoute", + "ec2:DescribeAddresses", + "ec2:AssociateAddress", + "ec2:DisassociateAddress" ], "Resource": "*", "Effect": "Allow" diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-alb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-alb.yaml deleted file mode 100644 index 5650191..0000000 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-alb.yaml +++ /dev/null @@ -1,1247 +0,0 @@ -AWSTemplateFormatVersion: "2010-09-09" - -Description: 'AWS CloudFormation Template AI Unlimited: AI Unlimited is a instance based service for deploying and suspending clusters of AI Unlimited compute engines, and managing project lifecycles. Note: You will be billed for the AWS resources used if you create a stack from this template.' - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AI Unlimited - Parameters: - - AiUnlimitedName - - InstanceType - - RootVolumeSize - - TerminationProtection - - IamRole - - IamRoleName - - IamPermissionsBoundary - - Label: - default: AI Unlimited connection - Parameters: - - AvailabilityZone - - LoadBalancerScheme - - LoadBalancerSubnetOne - - LoadBalancerSubnetTwo - - HostedZoneId - - DnsName - - Private - - Session - - Vpc - - Subnet - - KeyName - - AccessCIDR - - PrefixList - - SecurityGroup - - AiUnlimitedHttpPort - - AiUnlimitedGrpcPort - - AiUnlimitedVersion - - AiUnlimitedSchedulerVersion - - AiUnlimitedSchedulerHttpPort - - AiUnlimitedSchedulerGrpcPort - - Label: - default: Persistent volume - Parameters: - - UsePersistentVolume - - PersistentVolumeSize - - ExistingPersistentVolumeId - - PersistentVolumeDeletionPolicy - -Parameters: - LatestAmiId: - Type: AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 - - AiUnlimitedName: - Description: The AI Unlimited instance name - Type: String - Default: ai-unlimited - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "20" - MinLength: "1" - - Private: - Description: Will AI Unlimited be deployed in a private network without public IPs? - Type: String - AllowedValues: - - true - - false - Default: false - - LoadBalancerScheme: - Description: "If using a LoadBalancer, will it be internal or internet-facing? \nThe DNS name of an Internet-facing load balancer is publicly resolvable to the public IP addresses of the nodes.\nTherefore, Internet-facing load balancers can route requests from clients over the internet. The nodes of an \ninternal load balancer have only private IP addresses. The DNS name of an internal load balancer is publicly\nresolvable to the private IP addresses of the nodes. Therefore, internal load balancers can route requests only\nfrom clients with access to the VPC for the load balancer.\n" - Type: String - AllowedValues: - - internal - - internet-facing - Default: internet-facing - - Session: - Description: Should AI Unlimited be accessible via AWS Session Manager? - Type: String - AllowedValues: - - true - - false - Default: false - - Vpc: - Description: Network to deploy the AI Unlimited to. - Type: AWS::EC2::VPC::Id - ConstraintDescription: must be the name of an existing vpc. - - Subnet: - Description: Subnetwork to deploy the AI Unlimited to. - Type: AWS::EC2::Subnet::Id - ConstraintDescription: must be the name of a existing subnet. - - AvailabilityZone: - Description: "Availability zone to deploy the AI Unlimited to.\nThis must match the subnet, the zone of any pre existing volumes if used, \nand the instance type must be available in the selected zone.\n" - Type: AWS::EC2::AvailabilityZone::Name - ConstraintDescription: must be the name of a existing subnet. - - LoadBalancerSubnetOne: - Description: First subnetwork to deploy the Application Load Balancer to. - Type: AWS::EC2::Subnet::Id - - LoadBalancerSubnetTwo: - Description: Second subnetwork to deploy the Application Load Balancer to. - Type: AWS::EC2::Subnet::Id - - HostedZoneId: - Description: Zone ID of an existing Route 53 zone to add an entry for the Application Load Balancer to. - Type: AWS::Route53::HostedZone::Id - - DnsName: - Description: | - Name for Load Balancer DNS Entry, must fit as subdomain in the provides Route 53 Hosted Zone ID. - Example: unlimited.yourhostedzonedomainname.com - Type: String - - AiUnlimitedHttpPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 3000 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerHttpPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50061 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerGrpcPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50051 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedGrpcPort: - Description: port to access the AI Unlimited API. - Type: Number - Default: 3282 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedVersion: - Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.2.23 - - AiUnlimitedSchedulerVersion: - Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" - Type: String - Default: latest - - RootVolumeSize: - Description: size of the root disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - UsePersistentVolume: - Description: Should we use a new or existing volume for persistent data on the AI Unlimited server. - Type: String - AllowedValues: - - New - - Existing - Default: New - ConstraintDescription: Specify if you are using a a new persistent volume, an existing one, or none. - - PersistentVolumeSize: - Description: size of the optional persistent disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - ExistingPersistentVolumeId: - Description: Id of the existing persistent volume to attach. Must be int the same availability zone as the AI Unlimited server. - Type: String - Default: None - - PersistentVolumeDeletionPolicy: - Description: Behavior for the Persistent Volume when deleting the cloudformations deployment. - Type: String - AllowedValues: - - Delete - - Retain - - RetainExceptOnCreate - - Snapshot - Default: Retain - - TerminationProtection: - Description: Enable instance termination protection. - Type: String - AllowedValues: - - true - - false - Default: false - - InstanceType: - Description: AI Unlimited EC2 instance type - Type: String - AllowedValues: - - t3.nano - - t3.micro - - t3.small - - t3.medium - - t3.large - - m3.medium - - m3.large - - m3.xlarge - - m3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - c3.large - - c3.xlarge - - c3.2xlarge - - c3.4xlarge - - c3.8xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - i2.xlarge - - i2.2xlarge - - i2.4xlarge - - i2.8xlarge - Default: t3.micro - ConstraintDescription: must be a valid EC2 instance type. - - KeyName: - Description: Name of an existing EC2 KeyPair to enable SSH access to the AI Unlimited instance, leave empty if no ssh keys should be included - Type: String - - IamRole: - Description: | - Create a new IAM role for AI Unlimited or use an exiting one. - Requires CAPABILITY_IAM if creating a new IAM Role - Type: String - AllowedValues: - - New - - Existing - Default: New - - IamRoleName: - Description: | - Name of an existing IAM Role to assign to AI Unlimited, - or the name to give to the newly created role. - Leave blank to use an autogenerated name. - Requires CAPABILITY_NAMED_IAM if naming a new IAM Role. - Type: String - - IamPermissionsBoundary: - Description: | - Optional: Arn of a permissions boundary to pass to the IAM Role assigned to AI Unlimited. - Type: String - - AccessCIDR: - Description: The IP address range that can be used to communicate with the AI Unlimited instance. - Type: String - 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. - - PrefixList: - Description: The PrefixList that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid prefixlist - - SecurityGroup: - Description: The SecurityGroup that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid securityGroup ID - -Rules: - subnetsInVpc: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - - instanceTypeInZone: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - -Conditions: - NEEDSROLE: !Equals - - !Ref IamRole - - New - - HASPUBLICIP: !Not - - !Equals - - !Ref Private - - "true" - - HASKEY: !Not - - !Equals - - !Ref KeyName - - "" - - HASCIDR: !Not - - !Equals - - !Ref AccessCIDR - - "" - - HASPREFIXLIST: !Not - - !Equals - - !Ref PrefixList - - "" - - HASSECURITYGROUP: !Not - - !Equals - - !Ref SecurityGroup - - "" - - HASCIDRORPREFIXLIST: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - HASCIDRORPREFIXLISTORSECGROUP: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - !Condition HASSECURITYGROUP - - USESESSIONMANAGER: !Equals - - !Ref Session - - "true" - - NEEDSROLEANDSESSIONMANAGER: !And - - !Condition NEEDSROLE - - !Condition USESESSIONMANAGER - - HASKEYANDPUBLIC: !And - - !Condition HASKEY - - !Condition HASPUBLICIP - - HASKEYANDCIDRORPREFIXLISTORSECGROUP: !And - - !Condition HASKEY - - !Condition HASCIDRORPREFIXLISTORSECGROUP - - USENEWPERSISTENTVOLUME: !Equals - - !Ref UsePersistentVolume - - New - - HASIAMPERMISSIONSBOUNDARY: !Not - - !Equals - - !Ref IamPermissionsBoundary - - "" - - HASIAMROLENAME: !Not - - !Equals - - !Ref IamRoleName - - "" - -Resources: - AiUnlimitedVolume: - DeletionPolicy: !Ref PersistentVolumeDeletionPolicy - Type: AWS::EC2::Volume - Properties: - AvailabilityZone: !Ref AvailabilityZone - Size: !Ref PersistentVolumeSize - Encrypted: true - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - Key: Usage - Value: persistent storage - Condition: USENEWPERSISTENTVOLUME - - AiUnlimitedServer: - CreationPolicy: - ResourceSignal: - Timeout: PT15M - Type: AWS::EC2::Instance - Metadata: - AWS::CloudFormation::Init: - configSets: - ai_unlimited_install: - - prepare_directory - - !If - - USENEWPERSISTENTVOLUME - - prepare_new_storage - - !Ref AWS::NoValue - - bind_storage - - mount_storage - - install_docker - - configure_ai_unlimited_service - - start_ai_unlimited_service - - configure_ai_unlimited_scheduler_service - - start_ai_unlimited_scheduler_service - prepare_directory: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - mkdir -p /etc/td - prepare_new_storage: - commands: - mkfs: - command: !Sub | - #!/bin/bash -xe - /usr/sbin/mkfs -t ext4 /dev/nvme1n1 - bind_storage: - commands: - fstab: - command: !Sub | - #!/bin/bash -xe - /usr/bin/echo "/dev/nvme1n1 /etc/td ext4 defaults 0 2" >> /etc/fstab - mount_storage: - commands: - mount: - command: !Sub | - #!/bin/bash -xe - /usr/bin/mount -a - install_docker: - files: - /usr/lib/systemd/system/docker-install.service: - content: !Sub | - [Unit] - Description=Install docker - - [Service] - Type=oneshot - ExecStart=/bin/bash -c "while ! dnf update; do sleep 2; done && while ! dnf install -y docker; do sleep 2; done" - RemainAfterExit=yes - - [Install] - WantedBy=multi-user.target - commands: - verify_docker: - command: !Sub | - #!/bin/bash -xe - systemctl start docker-install - systemctl start docker - systemctl enable docker - services: - systemd: - docker: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_service: - files: - /usr/lib/systemd/system/ai-unlimited.service: - content: !Sub | - [Unit] - Description=AI Unlimited - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ - -v /etc/td/ai-unlimited:/etc/td \ - -p ${ AiUnlimitedHttpPort }:3000 \ - -p ${ AiUnlimitedGrpcPort }:3282 \ - --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v - - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_service: - services: - systemd: - ai-unlimited: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_scheduler_service: - files: - /usr/lib/systemd/system/ai-unlimited-scheduler.service: - content: !Sub | - [Unit] - Description=AI Unlimited Scheduler - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:latest - ExecStart=/usr/bin/docker run \ - --network ai_unlimited \ - -p ${ AiUnlimitedSchedulerGrpcPort }:50051 \ - -p ${ AiUnlimitedSchedulerHttpPort }:50061 \ - -v /etc/td/ai-unlimited:/etc/td \ - -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \ - -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \ - -e TD_WSSCHED_POL_INTERVAL=60 \ - -e TD_WS_CONTAINER_NAME=ai-unlimited.service \ - --rm --name %n teradata/ai-unlimited-scheduler:latest workspace-event-scheduler serve - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_scheduler_service: - services: - systemd: - ai-unlimited-scheduler: - enabled: "true" - ensureRunning: "true" - Properties: - PropagateTagsToVolumeOnCreation: true - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - VolumeSize: !Ref RootVolumeSize - Encrypted: true - NetworkInterfaces: - - DeviceIndex: 0 - SubnetId: !Ref Subnet - GroupSet: - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - AssociatePublicIpAddress: !If - - HASPUBLICIP - - true - - !Ref AWS::NoValue - ImageId: !Ref LatestAmiId - InstanceType: !Ref InstanceType - KeyName: !If - - HASKEY - - !Ref KeyName - - !Ref AWS::NoValue - DisableApiTermination: !Ref TerminationProtection - IamInstanceProfile: !Ref AiUnlimitedInstanceProfile - Volumes: - - Device: /dev/xvdb - VolumeId: !If - - USENEWPERSISTENTVOLUME - - !Ref AiUnlimitedVolume - - !Ref ExistingPersistentVolumeId - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - UserData: !Base64 - Fn::Sub: | - #!/bin/bash -xe - yum update -y - yum update -y aws-cfn-bootstrap - /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource AiUnlimitedServer --configsets ai_unlimited_install --region ${AWS::Region} - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource AiUnlimitedServer --region ${AWS::Region} - - LoadBalancerAiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedHttpPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancerSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedSchedulerHttpPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Scheme: !Ref LoadBalancerScheme - Subnets: - - !Ref LoadBalancerSubnetOne - - !Ref LoadBalancerSubnetTwo - SecurityGroups: - - !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - Type: application - - AiUnlimitedHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedHttpPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedGRPCListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedGRPCTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedGrpcPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedSchedulerHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedSchedulerHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedSchedulerHttpPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedSchedulerGRPCListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedSchedulerGRPCTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedSchedulerGrpcPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - ui - - http - Port: !Ref AiUnlimitedHttpPort - Protocol: HTTP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDWUNLIMITEDHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedHttpPort - VpcId: !Ref Vpc - - AiUnlimitedGRPCTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTPS - HealthCheckTimeoutSeconds: 15 - HealthyThresholdCount: 5 - Matcher: - GrpcCode: "0" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - api - - grpc - Port: !Ref AiUnlimitedGrpcPort - Protocol: HTTP - ProtocolVersion: GRPC - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDUNLIMITEDSGRPCSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedGrpcPort - VpcId: !Ref Vpc - - AiUnlimitedSchedulerHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - HealthCheckPath: /healthcheck - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - aisch - - ui - - http - Port: !Ref AiUnlimitedSchedulerHttpPort - Protocol: HTTPS - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDWUNLIMITEDHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedSchedulerHttpPort - VpcId: !Ref Vpc - - AiUnlimitedSchedulerGRPCTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTPS - HealthCheckTimeoutSeconds: 15 - Matcher: - GrpcCode: "0" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - aisch - - api - - grpc - Port: !Ref AiUnlimitedSchedulerGrpcPort - Protocol: HTTPS - ProtocolVersion: GRPC - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDWUNLIMITEDHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedSchedulerGrpcPort - VpcId: !Ref Vpc - - AiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedGrpcPort - ToPort: !Ref AiUnlimitedGrpcPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedGrpcPort - ToPort: !Ref AiUnlimitedGrpcPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - AiUnlimitedSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - SourceSecurityGroupId: !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerHttpPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerHttpPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - SecurityGroupIngress: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !GetAtt AiUnlimitedSecurityGroup.GroupId - FromPort: 22 - IpProtocol: tcp - ToPort: 22 - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASKEYANDCIDRORPREFIXLISTORSECGROUP - - AiUnlimitedRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - Path: / - RoleName: !If - - HASIAMROLENAME - - !Ref IamRoleName - - !Ref AWS::NoValue - PermissionsBoundary: !If - - HASIAMPERMISSIONSBOUNDARY - - !Ref IamPermissionsBoundary - - !Ref AWS::NoValue - Condition: NEEDSROLE - - SessionManagerPolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - session - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ssm:DescribeAssociation - - ssm:GetDeployablePatchSnapshotForInstance - - ssm:GetDocument - - ssm:DescribeDocument - - ssm:GetManifest - - ssm:ListAssociations - - ssm:ListInstanceAssociations - - ssm:PutInventory - - ssm:PutComplianceItems - - ssm:PutConfigurePackageResult - - ssm:UpdateAssociationStatus - - ssm:UpdateInstanceAssociationStatus - - ssm:UpdateInstanceInformation - Resource: '*' - - Effect: Allow - Action: - - ssmmessages:CreateControlChannel - - ssmmessages:CreateDataChannel - - ssmmessages:OpenControlChannel - - ssmmessages:OpenDataChannel - Resource: '*' - - Effect: Allow - Action: - - ec2messages:AcknowledgeMessage - - ec2messages:DeleteMessage - - ec2messages:FailMessage - - ec2messages:GetEndpoint - - ec2messages:GetMessages - - ec2messages:SendReply - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLEANDSESSIONMANAGER - - AiUnlimitedRolePolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - deploy - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - iam:PassRole - - iam:AddRoleToInstanceProfile - - iam:CreateInstanceProfile - - iam:CreateRole - - iam:DeleteInstanceProfile - - iam:DeleteRole - - iam:DeleteRolePolicy - - iam:GetInstanceProfile - - iam:GetRole - - iam:GetRolePolicy - - iam:ListAttachedRolePolicies - - iam:ListInstanceProfilesForRole - - iam:ListRolePolicies - - iam:PutRolePolicy - - iam:RemoveRoleFromInstanceProfile - - iam:TagRole - - iam:TagInstanceProfile - - ec2:TerminateInstances - - ec2:RunInstances - - ec2:RevokeSecurityGroupEgress - - ec2:ModifyInstanceAttribute - - ec2:ImportKeyPair - - ec2:DescribeVpcs - - ec2:DescribeVolumes - - ec2:DescribeTags - - ec2:DescribeSubnets - - ec2:DescribeSecurityGroups - - ec2:DescribePlacementGroups - - ec2:DescribeNetworkInterfaces - - ec2:DescribeLaunchTemplates - - ec2:DescribeLaunchTemplateVersions - - ec2:DescribeKeyPairs - - ec2:DescribeInstanceTypes - - ec2:DescribeInstanceTypeOfferings - - ec2:DescribeInstances - - ec2:DescribeInstanceAttribute - - ec2:DescribeImages - - ec2:DescribeAccountAttributes - - ec2:DescribeAvailabilityZones - - ec2:DescribeManagedPrefixLists - - ec2:DescribeVpcAttribute - - ec2:DeleteSecurityGroup - - ec2:DeletePlacementGroup - - ec2:DeleteLaunchTemplate - - ec2:DeleteKeyPair - - ec2:CreateTags - - ec2:CreateSecurityGroup - - ec2:CreatePlacementGroup - - ec2:CreateLaunchTemplateVersion - - ec2:CreateLaunchTemplate - - ec2:AuthorizeSecurityGroupIngress - - ec2:AuthorizeSecurityGroupEgress - - secretsmanager:CreateSecret - - secretsmanager:DeleteSecret - - secretsmanager:DescribeSecret - - secretsmanager:GetResourcePolicy - - secretsmanager:GetSecretValue - - secretsmanager:PutSecretValue - - secretsmanager:TagResource - - s3:CreateBucket - - s3:DeleteBucket - - s3:PutObject - - s3:GetObject - - s3:DeleteObject - - cloudformation:CreateStack - - cloudformation:DeleteStack - - cloudformation:DescribeStacks - - cloudformation:ListStacks - - cloudformation:DescribeStackEvents - - ssm:PutParameter - - ssm:GetParameter - - ssm:DeleteParameter - - ec2:RevokeSecurityGroupIngress - - ec2:CreateInternetGateway - - ec2:CreateVpc - - ec2:DescribeInternetGateways - - ec2:DeleteVpc - - ec2:ModifyVpcAttribute - - ec2:DeleteInternetGateway - - ec2:CreateSubnet - - ec2:CreateRouteTable - - ec2:DescribeRouteTables - - ec2:DeleteSubnet - - ec2:DeleteRouteTable - - ec2:AttachInternetGateway - - ec2:ModifySubnetAttribute - - ec2:DetachInternetGateway - - ec2:AssociateRouteTable - - ec2:CreateRoute - - ec2:DisassociateRouteTable - - ec2:DeleteRoute - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLE - - AiUnlimitedInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: !If - - NEEDSROLE - - - !Ref AiUnlimitedRole - - - !Ref IamRoleName - - ACMCertificate: - Type: AWS::CertificateManager::Certificate - Properties: - DomainName: !Ref DnsName - DomainValidationOptions: - - DomainName: !Ref DnsName - HostedZoneId: !Ref HostedZoneId - ValidationMethod: DNS - - LoadBalancerDNS: - Type: AWS::Route53::RecordSetGroup - Properties: - HostedZoneId: !Ref HostedZoneId - RecordSets: - - Name: !Ref DnsName - Type: A - AliasTarget: - HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID - DNSName: !GetAtt LoadBalancer.DNSName - -Outputs: - PublicIP: - Description: EC2 public IP - Value: !GetAtt AiUnlimitedServer.PublicIp - Condition: HASPUBLICIP - - PrivateIP: - Description: EC2 private IP - Value: !GetAtt AiUnlimitedServer.PrivateIp - - AiUnlimitedUiAccess: - Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !Sub https://${ DnsName }:${ AiUnlimitedHttpPort } - - AiUnlimitedApiAccess: - Description: Loadbalancer access endpoint for AI Unlimited API Access - Value: !Sub ${ DnsName }:${ AiUnlimitedGrpcPort } - - InstanceSecurityGroups: - Description: AI Unlimited Security Group - Value: !Join - - ', ' - - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - LoadBalancerSecurityGroups: - Description: AI Unlimited Load Balancer Security Group - Value: !Join - - ', ' - - - !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - PublicSshConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PublicIp } - Condition: HASKEYANDPUBLIC - - PrivateSshConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PrivateIp } - Condition: HASKEY - - PersistentVolumeId: - Description: Id of the new persistent volume created for AI Unlimited - Value: !Ref AiUnlimitedVolume - Condition: USENEWPERSISTENTVOLUME diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index 7248148..b36648d 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -29,12 +29,14 @@ Metadata: - AccessCIDR - PrefixList - SecurityGroup - - AiUnlimitedHttpPort + - AiUnlimitedAuthPort - AiUnlimitedGrpcPort - AiUnlimitedVersion - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiVersion - Label: default: Persistent volume Parameters: @@ -101,7 +103,7 @@ Parameters: Type: AWS::EC2::AvailabilityZone::Name ConstraintDescription: must be the name of a existing subnet. - AiUnlimitedHttpPort: + AiUnlimitedAuthPort: Description: port to access the AI Unlimited UI. Type: Number Default: 3000 @@ -125,6 +127,14 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedGrpcPort: Description: port to access the AI Unlimited API. Type: Number @@ -136,7 +146,12 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.2.23 + Default: v0.3.0 + + AiUnlimitedUiVersion: + Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" + Type: String + Default: v0.0.5 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -364,6 +379,8 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -406,8 +423,12 @@ Resources: - !Ref AWS::NoValue - bind_storage - mount_storage + - create_ai_unlimited_folder + - create_init_api_key - install_docker + - configure_ai_unlimited_ui_service - configure_ai_unlimited_service + - start_ai_unlimited_ui_service - start_ai_unlimited_service - configure_ai_unlimited_scheduler_service - start_ai_unlimited_scheduler_service @@ -435,6 +456,18 @@ Resources: command: !Sub | #!/bin/bash -xe /usr/bin/mount -a + create_ai_unlimited_folder: + commands: + run_command: + command: !Sub | + #!/bin/bash -xe + /usr/bin/mkdir -p /etc/td/ai-unlimited + create_init_api_key: + commands: + run_command: + command: !Sub | + #!/bin/bash -xe + echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt install_docker: files: /usr/lib/systemd/system/docker-install.service: @@ -461,6 +494,49 @@ Resources: docker: enabled: "true" ensureRunning: "true" + configure_ai_unlimited_ui_service: + files: + /usr/lib/systemd/system/ai-unlimited-ui.service: + content: !Sub | + [Unit] + Description=ai-unlimited-ui + After=docker.service + Requires=docker.service + StartLimitInterval=200 + StartLimitBurst=10 + + [Service] + TimeoutStartSec=0 + Restart=always + RestartSec=2 + + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' + ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true + ExecStartPre=-/usr/bin/docker rm %n || true + ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + ExecStart=/usr/bin/docker run \ + -e accept_license=Y \ + -e PLATFORM=aws \ + -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ + -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ + -e TD_VCD_INIT_API_KEY \ + -p ${ AiUnlimitedUiPort }:80 \ + --network ai_unlimited \ + --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + [Install] + WantedBy=multi-user.target + group: root + mode: "000400" + owner: root + start_ai_unlimited_ui_service: + services: + systemd: + ai-unlimited-ui: + enabled: "true" + ensureRunning: "true" configure_ai_unlimited_service: files: /usr/lib/systemd/system/ai-unlimited.service: @@ -477,15 +553,16 @@ Resources: Restart=always RestartSec=2 ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - ExecStartPre=-/usr/bin/docker exec %n stop || true + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ + -e TD_VCD_INIT_API_KEY \ -v /etc/td/ai-unlimited:/etc/td \ - -p ${ AiUnlimitedHttpPort }:3000 \ + -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v @@ -516,7 +593,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - ExecStartPre=-/usr/bin/docker exec %n stop || true + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:latest ExecStart=/usr/bin/docker run \ @@ -599,9 +676,9 @@ Resources: VpcId: !Ref Vpc GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedHttpPort + - FromPort: !Ref AiUnlimitedAuthPort IpProtocol: tcp - ToPort: !Ref AiUnlimitedHttpPort + ToPort: !Ref AiUnlimitedAuthPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -625,6 +702,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + - FromPort: !Ref AiUnlimitedUiPort + IpProtocol: tcp + ToPort: !Ref AiUnlimitedUiPort + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue Condition: HASCIDRORPREFIXLISTORSECGROUP LoadBalancerSchedulerSecurityGroup: @@ -679,7 +771,7 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedHTTPTargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedHttpPort + Port: !Ref AiUnlimitedAuthPort Protocol: TCP AiUnlimitedGRPCListener: @@ -692,6 +784,16 @@ Resources: Port: !Ref AiUnlimitedGrpcPort Protocol: TCP + AiUnlimitedUIListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref AiUnlimitedUITargetGroup + LoadBalancerArn: !Ref LoadBalancer + Port: !Ref AiUnlimitedUiPort + Protocol: TCP + AiUnlimitedSchedulerHTTPListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: @@ -732,7 +834,7 @@ Resources: - td-aiu - ui - http - Port: !Ref AiUnlimitedHttpPort + Port: !Ref AiUnlimitedAuthPort Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -743,7 +845,41 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedHttpPort + Port: !Ref AiUnlimitedAuthPort + VpcId: !Ref Vpc + + AiUnlimitedUITargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckProtocol: HTTP + HealthCheckTimeoutSeconds: 15 + Name: !Join + - '-' + - - !Select + - 4 + - !Split + - '-' + - !Select + - 2 + - !Split + - / + - !Ref AWS::StackId + - td-aiu + - ui + - api + Port: !Ref AiUnlimitedUiPort + Protocol: TCP + TargetGroupAttributes: + - Key: stickiness.enabled + Value: true + - Key: stickiness.type + Value: source_ip + - Key: deregistration_delay.timeout_seconds + Value: "20" + Targets: + - Id: !Ref AiUnlimitedServer + Port: !Ref AiUnlimitedUiPort VpcId: !Ref Vpc AiUnlimitedGRPCTargetGroup: @@ -859,18 +995,22 @@ Resources: GroupDescription: Enable access to AI Unlimited server over http and grpc SecurityGroupIngress: - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort + FromPort: !Ref AiUnlimitedAuthPort + ToPort: !Ref AiUnlimitedAuthPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp FromPort: !Ref AiUnlimitedGrpcPort ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId + - IpProtocol: tcp + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort + SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort + FromPort: !Ref AiUnlimitedAuthPort + ToPort: !Ref AiUnlimitedAuthPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue - !If @@ -880,6 +1020,13 @@ Resources: ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue + - !If + - HASSECURITYGROUP + - IpProtocol: tcp + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort + SourceSecurityGroupId: !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup @@ -1123,6 +1270,9 @@ Resources: - ec2:CreateRoute - ec2:DisassociateRouteTable - ec2:DeleteRoute + - ec2:DescribeAddresses + - ec2:AssociateAddress + - ec2:DisassociateAddress Resource: '*' Roles: - !Ref AiUnlimitedRole @@ -1149,7 +1299,10 @@ Outputs: AiUnlimitedUiAccess: Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedHttpPort } + Value: !If + - PortIsNotEighty + - !Sub "http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck" + - !Sub "http://${ LoadBalancer.DNSName }" AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index ee7796c..73ebed5 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -27,12 +27,14 @@ Metadata: - AccessCIDR - PrefixList - SecurityGroup - - AiUnlimitedHttpPort + - AiUnlimitedAuthPort - AiUnlimitedGrpcPort - AiUnlimitedVersion - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiVersion - Label: default: Persistent volume Parameters: @@ -86,7 +88,7 @@ Parameters: Type: AWS::EC2::AvailabilityZone::Name ConstraintDescription: must be the name of a existing subnet. - AiUnlimitedHttpPort: + AiUnlimitedAuthPort: Description: port to access the AI Unlimited UI. Type: Number Default: 3000 @@ -118,16 +120,29 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.2.23 + Default: v0.3.0 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" Type: String Default: latest + AiUnlimitedUiVersion: + Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" + Type: String + Default: v0.0.5 + RootVolumeSize: Description: size of the root disk to the AI Unlimited server. Type: Number @@ -349,6 +364,19 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEightyAndHasPublicIp: + !And + - !Not + - !Equals + - !Ref Private + - "true" + - !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + + PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -391,8 +419,12 @@ Resources: - !Ref AWS::NoValue - bind_storage - mount_storage + - create_ai_unlimited_folder + - create_init_api_key - install_docker + - configure_ai_unlimited_ui_service - configure_ai_unlimited_service + - start_ai_unlimited_ui_service - start_ai_unlimited_service - configure_ai_unlimited_scheduler_service - start_ai_unlimited_scheduler_service @@ -420,6 +452,18 @@ Resources: command: !Sub | #!/bin/bash -xe /usr/bin/mount -a + create_ai_unlimited_folder: + commands: + mkdir: + command: !Sub | + #!/bin/bash -xe + mkdir -p /etc/td/ai-unlimited + create_init_api_key: + commands: + run_command: + command: !Sub | + #!/bin/bash -xe + echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt install_docker: files: /usr/lib/systemd/system/docker-install.service: @@ -446,6 +490,51 @@ Resources: docker: enabled: "true" ensureRunning: "true" + + configure_ai_unlimited_ui_service: + files: + /usr/lib/systemd/system/ai-unlimited-ui.service: + content: !Sub | + [Unit] + Description=ai-unlimited-ui + After=docker.service + Requires=docker.service + StartLimitInterval=200 + StartLimitBurst=10 + + [Service] + TimeoutStartSec=0 + Restart=always + RestartSec=2 + + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' + ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true + ExecStartPre=-/usr/bin/docker rm %n || true + ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + ExecStart=/usr/bin/docker run \ + -e accept_license=Y \ + -e PLATFORM=aws \ + -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ + -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ + -e TD_VCD_INIT_API_KEY \ + -p ${ AiUnlimitedUiPort }:80 \ + --network ai_unlimited \ + --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + [Install] + WantedBy=multi-user.target + group: root + mode: "000400" + owner: root + start_ai_unlimited_ui_service: + services: + systemd: + ai-unlimited-ui: + enabled: "true" + ensureRunning: "true" + configure_ai_unlimited_service: files: /usr/lib/systemd/system/ai-unlimited.service: @@ -462,15 +551,16 @@ Resources: Restart=always RestartSec=2 ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - ExecStartPre=-/usr/bin/docker exec %n stop || true + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ + -e TD_VCD_INIT_API_KEY \ -v /etc/td/ai-unlimited:/etc/td \ - -p ${ AiUnlimitedHttpPort }:3000 \ + -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v @@ -585,9 +675,9 @@ Resources: VpcId: !Ref Vpc GroupDescription: Enable access to AI Unlimited server over http and grpc SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedHttpPort + - FromPort: !Ref AiUnlimitedAuthPort IpProtocol: tcp - ToPort: !Ref AiUnlimitedHttpPort + ToPort: !Ref AiUnlimitedAuthPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -615,6 +705,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + - FromPort: !Ref AiUnlimitedUiPort + IpProtocol: tcp + ToPort: !Ref AiUnlimitedUiPort + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup @@ -863,6 +968,9 @@ Resources: - ec2:CreateRoute - ec2:DisassociateRouteTable - ec2:DeleteRoute + - ec2:DescribeAddresses + - ec2:AssociateAddress + - ec2:DisassociateAddress Resource: '*' Roles: - !Ref AiUnlimitedRole @@ -889,12 +997,17 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !Sub http://${AiUnlimitedServer.PublicDnsName}:${ AiUnlimitedHttpPort } + Value: !If [ PortIsNotEightyAndHasPublicIp, + !Sub "http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck", + !Sub "http://${AiUnlimitedServer.PublicDnsName}" ] Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access - Value: !Sub http://${AiUnlimitedServer.PrivateDnsName}:${ AiUnlimitedHttpPort } + Value: !If + - PortIsNotEighty + - !Sub "http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck" + - !Sub "http://${AiUnlimitedServer.PrivateDnsName}" AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-alb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-alb.yaml deleted file mode 100644 index dc060cf..0000000 --- a/deployments/aws/templates/all-in-one/all-in-one-with-alb.yaml +++ /dev/null @@ -1,1407 +0,0 @@ -AWSTemplateFormatVersion: "2010-09-09" - -Description: 'AWS CloudFormation Template with AI Unlimited with Jupyter: AI Unlimited is a instance based service for deploying and suspending ai-unlimited clusters, and managing project lifecycles. This template also includes a Jupyter Lab service running on the same host, suitable for demonstration environments. Note: You will be billed for the AWS resources used if you create a stack from this template.' - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AI Unlimited - Parameters: - - AiUnlimitedName - - InstanceType - - RootVolumeSize - - TerminationProtection - - IamRole - - IamRoleName - - IamPermissionsBoundary - - Label: - default: AI Unlimited connection - Parameters: - - AvailabilityZone - - LoadBalancerScheme - - LoadBalancerSubnetOne - - LoadBalancerSubnetTwo - - HostedZoneId - - DnsName - - Private - - Session - - Vpc - - Subnet - - KeyName - - AccessCIDR - - PrefixList - - SecurityGroup - - AiUnlimitedHttpPort - - AiUnlimitedGrpcPort - - AiUnlimitedVersion - - AiUnlimitedSchedulerVersion - - AiUnlimitedSchedulerHttpPort - - AiUnlimitedSchedulerGrpcPort - - Label: - default: Persistent volume - Parameters: - - UsePersistentVolume - - PersistentVolumeSize - - ExistingPersistentVolumeId - - PersistentVolumeDeletionPolicy - - Label: - default: Jupyter connection - Parameters: - - JupyterToken - - JupyterHttpPort - - JupyterVersion - -Parameters: - LatestAmiId: - Type: AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 - - AiUnlimitedName: - Description: The AI Unlimited instance name - Type: String - Default: ai-unlimited - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "20" - MinLength: "1" - - JupyterToken: - Description: The token or password equivalent used to access Jupyter. - Type: String - NoEcho: true - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "64" - - Private: - Description: Will AI Unlimited be deployed in a private network without public IPs? - Type: String - AllowedValues: - - true - - false - Default: false - - LoadBalancerScheme: - Description: "If using a LoadBalancer, will it be internal or internet-facing? \nThe DNS name of an Internet-facing load balancer is publicly resolvable to the public IP addresses of the nodes.\nTherefore, Internet-facing load balancers can route requests from clients over the internet. The nodes of an \ninternal load balancer have only private IP addresses. The DNS name of an internal load balancer is publicly\nresolvable to the private IP addresses of the nodes. Therefore, internal load balancers can route requests only\nfrom clients with access to the VPC for the load balancer.\n" - Type: String - AllowedValues: - - internal - - internet-facing - Default: internet-facing - - Session: - Description: Should AI Unlimited be accessible via AWS Session Manager? - Type: String - AllowedValues: - - true - - false - Default: false - - Vpc: - Description: Network to deploy the AI Unlimited to. - Type: AWS::EC2::VPC::Id - ConstraintDescription: must be the name of an existing vpc. - - Subnet: - Description: Subnetwork to deploy the AI Unlimited to. - Type: AWS::EC2::Subnet::Id - ConstraintDescription: must be the name of a existing subnet. - - AvailabilityZone: - Description: "Availability zone to deploy the AI Unlimited to.\nThis must match the subnet, the zone of any pre existing volumes if used, \nand the instance type must be available in the selected zone.\n" - Type: AWS::EC2::AvailabilityZone::Name - ConstraintDescription: must be the name of a existing subnet. - - LoadBalancerSubnetOne: - Description: First subnetwork to deploy the Application Load Balancer to. - Type: AWS::EC2::Subnet::Id - - LoadBalancerSubnetTwo: - Description: Second subnetwork to deploy the Application Load Balancer to. - Type: AWS::EC2::Subnet::Id - - HostedZoneId: - Description: Zone ID of an existing Route 53 zone to add an entry for the Application Load Balancer to. - Type: AWS::Route53::HostedZone::Id - - DnsName: - Description: | - Name for Load Balancer DNS Entry, must fit as subdomain in the provides Route 53 Hosted Zone ID. - Example: unlimited.yourhostedzonedomainname.com - Type: String - - AiUnlimitedHttpPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 3000 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedGrpcPort: - Description: port to access the AI Unlimited API. - Type: Number - Default: 3282 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerHttpPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50061 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerGrpcPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50051 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedVersion: - Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.2.23 - - AiUnlimitedSchedulerVersion: - Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" - Type: String - Default: latest - - JupyterHttpPort: - Description: port to access the Jupyter UI. - Type: Number - Default: 8888 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - JupyterVersion: - Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" - Type: String - Default: latest - - RootVolumeSize: - Description: size of the root disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - UsePersistentVolume: - Description: Should we use a new or existing volume for persistent data on the AI Unlimited server. - Type: String - AllowedValues: - - New - - Existing - Default: New - ConstraintDescription: Specify if you are using a a new persistent volume, an existing one, or none. - - PersistentVolumeSize: - Description: size of the optional persistent disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - ExistingPersistentVolumeId: - Description: Id of the existing persistent volume to attach. Must be in the same availability zone as the AI Unlimited instance. - Type: String - Default: None - - PersistentVolumeDeletionPolicy: - Description: Behavior for the Persistent Volume when deleting the cloudformations deployment. - Type: String - AllowedValues: - - Delete - - Retain - - RetainExceptOnCreate - - Snapshot - Default: Retain - - TerminationProtection: - Description: Enable instance termination protection. - Type: String - AllowedValues: - - true - - false - Default: false - - InstanceType: - Description: AI Unlimited EC2 instance type - Type: String - AllowedValues: - - t3.small - - t3.medium - - t3.large - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - i2.xlarge - - i2.2xlarge - - i2.4xlarge - - i2.8xlarge - Default: t3.small - ConstraintDescription: must be a valid EC2 instance type. - - KeyName: - Description: Name of an existing EC2 KeyPair to enable SSH access to the AI Unlimited instance, leave empty if no ssh keys should be included - Type: String - - IamRole: - Description: | - Create a new IAM role for AI Unlimited or use an exiting one. - Requires CAPABILITY_IAM if creating a new IAM Role - Type: String - AllowedValues: - - New - - Existing - Default: New - - IamRoleName: - Description: | - Name of an existing IAM Role to assign to AI Unlimited, - or the name to give to the newly created role. - Leave blank to use an autogenerated name. - Requires CAPABILITY_NAMED_IAM if naming a new IAM Role. - Type: String - - IamPermissionsBoundary: - Description: | - Optional: Arn of a permissions boundary to pass to the IAM Role assigned to AI Unlimited. - Type: String - - AccessCIDR: - Description: The IP address range that can be used to communicate with the AI Unlimited instance. - Type: String - 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. - - PrefixList: - Description: The PrefixList that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid prefixlist - - SecurityGroup: - Description: The SecurityGroup that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid securityGroup ID - -Rules: - subnetsInVpc: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - - instanceTypeInZone: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - -Conditions: - NEEDSROLE: !Equals - - !Ref IamRole - - New - - HASPUBLICIP: !Not - - !Equals - - !Ref Private - - "true" - - HASKEY: !Not - - !Equals - - !Ref KeyName - - "" - - HASCIDR: !Not - - !Equals - - !Ref AccessCIDR - - "" - - HASPREFIXLIST: !Not - - !Equals - - !Ref PrefixList - - "" - - HASSECURITYGROUP: !Not - - !Equals - - !Ref SecurityGroup - - "" - - HASCIDRORPREFIXLIST: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - HASCIDRORPREFIXLISTORSECGROUP: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - !Condition HASSECURITYGROUP - - USESESSIONMANAGER: !Equals - - !Ref Session - - "true" - - NEEDSROLEANDSESSIONMANAGER: !And - - !Condition NEEDSROLE - - !Condition USESESSIONMANAGER - - HASKEYANDPUBLIC: !And - - !Condition HASKEY - - !Condition HASPUBLICIP - - HASKEYANDCIDRORPREFIXLISTORSECGROUP: !And - - !Condition HASKEY - - !Condition HASCIDRORPREFIXLISTORSECGROUP - - USENEWPERSISTENTVOLUME: !Equals - - !Ref UsePersistentVolume - - New - - HASIAMPERMISSIONSBOUNDARY: !Not - - !Equals - - !Ref IamPermissionsBoundary - - "" - - HASIAMROLENAME: !Not - - !Equals - - !Ref IamRoleName - - "" - -Resources: - AiUnlimitedVolume: - DeletionPolicy: !Ref PersistentVolumeDeletionPolicy - Type: AWS::EC2::Volume - Properties: - AvailabilityZone: !Ref AvailabilityZone - Size: !Ref PersistentVolumeSize - Encrypted: true - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - Key: Usage - Value: persistent storage - Condition: USENEWPERSISTENTVOLUME - - AiUnlimitedServer: - CreationPolicy: - ResourceSignal: - Timeout: PT15M - Type: AWS::EC2::Instance - Metadata: - AWS::CloudFormation::Init: - configSets: - ai_unlimited_install: - - prepare_directory - - !If - - USENEWPERSISTENTVOLUME - - prepare_new_storage - - !Ref AWS::NoValue - - bind_storage - - mount_storage - - install_docker - - configure_ai_unlimited_service - - configure_jupyter_service - - start_ai_unlimited_service - - configure_ai_unlimited_scheduler_service - - start_ai_unlimited_scheduler_service - - start_jupyter_service - prepare_directory: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - mkdir -p /etc/td - prepare_new_storage: - commands: - mkfs: - command: !Sub | - #!/bin/bash -xe - /usr/sbin/mkfs -t ext4 /dev/nvme1n1 - bind_storage: - commands: - fstab: - command: !Sub | - #!/bin/bash -xe - /usr/bin/echo "/dev/nvme1n1 /etc/td ext4 defaults 0 2" >> /etc/fstab - mount_storage: - commands: - mount: - command: !Sub | - #!/bin/bash -xe - /usr/bin/mount -a - install_docker: - files: - /usr/lib/systemd/system/docker-install.service: - content: !Sub | - [Unit] - Description=Install docker - - [Service] - Type=oneshot - ExecStart=/bin/bash -c "while ! dnf update; do sleep 2; done && while ! dnf install -y docker; do sleep 2; done" - RemainAfterExit=yes - - [Install] - WantedBy=multi-user.target - commands: - verify_docker: - command: !Sub | - #!/bin/bash -xe - systemctl start docker-install - systemctl start docker - systemctl enable docker - services: - systemd: - docker: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_service: - files: - /usr/lib/systemd/system/ai-unlimited.service: - content: !Sub | - [Unit] - Description=AI Unlimited - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' - ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ - -v /etc/td/ai-unlimited:/etc/td \ - -p ${ AiUnlimitedHttpPort }:3000 \ - -p ${ AiUnlimitedGrpcPort }:3282 \ - --network ai_unlimited \ - --net-alias ${ DnsName } \ - --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_service: - services: - systemd: - ai-unlimited: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_scheduler_service: - files: - /usr/lib/systemd/system/ai-unlimited-scheduler.service: - content: !Sub | - [Unit] - Description=AI Unlimited Scheduler - After=ai-unlimited.service - Requires=ai-unlimited.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:latest - ExecStart=/usr/bin/docker run \ - --network ai_unlimited \ - -p ${ AiUnlimitedSchedulerGrpcPort }:50051 \ - -p ${ AiUnlimitedSchedulerHttpPort }:50061 \ - -v /etc/td/ai-unlimited:/etc/td \ - -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \ - -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \ - -e TD_WSSCHED_POL_INTERVAL=2 \ - -e TD_WS_CONTAINER_NAME=ai-unlimited.service \ - --rm --name %n teradata/ai-unlimited-scheduler:latest workspace-event-scheduler serve - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_scheduler_service: - services: - systemd: - ai-unlimited-scheduler: - enabled: "true" - ensureRunning: "true" - configure_jupyter_service: - files: - /usr/lib/systemd/system/jupyter.service: - content: !Sub | - [Unit] - Description=jupyter - After=ai-unlimited.service - Requires=ai-unlimited.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited - ExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{userdata,ipython} - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-jupyter:${ JupyterVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e JUPYTER_TOKEN=${ JupyterToken } \ - -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \ - -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \ - -p ${ JupyterHttpPort }:8888 \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-jupyter:${ JupyterVersion } - - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_jupyter_service: - services: - systemd: - jupyter: - enabled: "true" - ensureRunning: "true" - Properties: - PropagateTagsToVolumeOnCreation: true - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - VolumeSize: !Ref RootVolumeSize - Encrypted: true - NetworkInterfaces: - - DeviceIndex: 0 - SubnetId: !Ref Subnet - GroupSet: - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - !GetAtt JupyterSecurityGroup.GroupId - AssociatePublicIpAddress: !If - - HASPUBLICIP - - true - - !Ref AWS::NoValue - ImageId: !Ref LatestAmiId - InstanceType: !Ref InstanceType - KeyName: !If - - HASKEY - - !Ref KeyName - - !Ref AWS::NoValue - DisableApiTermination: !Ref TerminationProtection - IamInstanceProfile: !Ref AiUnlimitedInstanceProfile - Volumes: - - Device: /dev/xvdb - VolumeId: !If - - USENEWPERSISTENTVOLUME - - !Ref AiUnlimitedVolume - - !Ref ExistingPersistentVolumeId - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - UserData: !Base64 - Fn::Sub: | - #!/bin/bash -xe - yum update -y - yum update -y aws-cfn-bootstrap - /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource AiUnlimitedServer --configsets ai_unlimited_install --region ${AWS::Region} - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource AiUnlimitedServer --region ${AWS::Region} - - LoadBalancerAiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedHttpPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancerSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedSchedulerHttpPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancerJupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref JupyterHttpPort - IpProtocol: tcp - ToPort: !Ref JupyterHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Scheme: !Ref LoadBalancerScheme - Subnets: - - !Ref LoadBalancerSubnetOne - - !Ref LoadBalancerSubnetTwo - SecurityGroups: - - !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - Type: application - - AiUnlimitedHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedHttpPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - JupyterHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref JupyterHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref JupyterHttpPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedSchedulerHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedSchedulerHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedSchedulerHttpPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedSchedulerGRPCListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedSchedulerGRPCTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedSchedulerGrpcPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - AiUnlimitedSchedulerHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTPS - HealthCheckTimeoutSeconds: 15 - HealthCheckPath: /healthcheck - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - aisch - - ui - - http - Port: !Ref AiUnlimitedSchedulerHttpPort - Protocol: HTTP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDWUNLIMITEDHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedSchedulerHttpPort - VpcId: !Ref Vpc - - AiUnlimitedSchedulerGRPCTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTPS - HealthCheckTimeoutSeconds: 15 - Matcher: - GrpcCode: "0" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - aisch - - api - - grpc - Port: !Ref AiUnlimitedSchedulerGrpcPort - Protocol: HTTPS - ProtocolVersion: GRPC - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDWUNLIMITEDHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedSchedulerGrpcPort - VpcId: !Ref Vpc - - AiUnlimitedHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - ui - - http - Port: !Ref AiUnlimitedHttpPort - Protocol: HTTP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDWUNLIMITEDHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedHttpPort - VpcId: !Ref Vpc - - JupyterHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - jupyter - - ui - - http - Port: !Ref JupyterHttpPort - Protocol: HTTP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDJUPYTERHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref JupyterHttpPort - VpcId: !Ref Vpc - - AiUnlimitedGRPCTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTPS - HealthCheckTimeoutSeconds: 15 - HealthyThresholdCount: 5 - Matcher: - GrpcCode: "0" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - api - - grpc - Port: !Ref AiUnlimitedGrpcPort - Protocol: HTTP - ProtocolVersion: GRPC - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDUNLIMITEDSGRPCSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedGrpcPort - VpcId: !Ref Vpc - - AiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedGrpcPort - ToPort: !Ref AiUnlimitedGrpcPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedGrpcPort - ToPort: !Ref AiUnlimitedGrpcPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - AiUnlimitedSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - SourceSecurityGroupId: !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerHttpPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerHttpPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - JupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to jupyter server over http - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref JupyterHttpPort - ToPort: !Ref JupyterHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - - FromPort: !Ref JupyterHttpPort - IpProtocol: tcp - ToPort: !Ref JupyterHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - SecurityGroupIngress: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !GetAtt AiUnlimitedSecurityGroup.GroupId - FromPort: 22 - IpProtocol: tcp - ToPort: 22 - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASKEYANDCIDRORPREFIXLISTORSECGROUP - - AiUnlimitedRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - Path: / - RoleName: !If - - HASIAMROLENAME - - !Ref IamRoleName - - !Ref AWS::NoValue - PermissionsBoundary: !If - - HASIAMPERMISSIONSBOUNDARY - - !Ref IamPermissionsBoundary - - !Ref AWS::NoValue - Condition: NEEDSROLE - - SessionManagerPolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - session - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ssm:DescribeAssociation - - ssm:GetDeployablePatchSnapshotForInstance - - ssm:GetDocument - - ssm:DescribeDocument - - ssm:GetManifest - - ssm:ListAssociations - - ssm:ListInstanceAssociations - - ssm:PutInventory - - ssm:PutComplianceItems - - ssm:PutConfigurePackageResult - - ssm:UpdateAssociationStatus - - ssm:UpdateInstanceAssociationStatus - - ssm:UpdateInstanceInformation - Resource: '*' - - Effect: Allow - Action: - - ssmmessages:CreateControlChannel - - ssmmessages:CreateDataChannel - - ssmmessages:OpenControlChannel - - ssmmessages:OpenDataChannel - Resource: '*' - - Effect: Allow - Action: - - ec2messages:AcknowledgeMessage - - ec2messages:DeleteMessage - - ec2messages:FailMessage - - ec2messages:GetEndpoint - - ec2messages:GetMessages - - ec2messages:SendReply - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLEANDSESSIONMANAGER - - AiUnlimitedRolePolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - deploy - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - iam:PassRole - - iam:AddRoleToInstanceProfile - - iam:CreateInstanceProfile - - iam:CreateRole - - iam:DeleteInstanceProfile - - iam:DeleteRole - - iam:DeleteRolePolicy - - iam:GetInstanceProfile - - iam:GetRole - - iam:GetRolePolicy - - iam:ListAttachedRolePolicies - - iam:ListInstanceProfilesForRole - - iam:ListRolePolicies - - iam:PutRolePolicy - - iam:RemoveRoleFromInstanceProfile - - iam:TagRole - - iam:TagInstanceProfile - - ec2:TerminateInstances - - ec2:RunInstances - - ec2:RevokeSecurityGroupEgress - - ec2:ModifyInstanceAttribute - - ec2:ImportKeyPair - - ec2:DescribeVpcs - - ec2:DescribeVolumes - - ec2:DescribeTags - - ec2:DescribeSubnets - - ec2:DescribeSecurityGroups - - ec2:DescribePlacementGroups - - ec2:DescribeNetworkInterfaces - - ec2:DescribeLaunchTemplates - - ec2:DescribeLaunchTemplateVersions - - ec2:DescribeKeyPairs - - ec2:DescribeInstanceTypes - - ec2:DescribeInstanceTypeOfferings - - ec2:DescribeInstances - - ec2:DescribeInstanceAttribute - - ec2:DescribeImages - - ec2:DescribeAccountAttributes - - ec2:DescribeAvailabilityZones - - ec2:DescribeManagedPrefixLists - - ec2:DescribeVpcAttribute - - ec2:DeleteTags - - ec2:DeleteSecurityGroup - - ec2:DeletePlacementGroup - - ec2:DeleteLaunchTemplate - - ec2:DeleteLaunchTemplateVersions - - ec2:DeleteKeyPair - - ec2:CreateTags - - ec2:CreateSecurityGroup - - ec2:CreatePlacementGroup - - ec2:CreateLaunchTemplateVersion - - ec2:CreateLaunchTemplate - - ec2:AuthorizeSecurityGroupIngress - - ec2:AuthorizeSecurityGroupEgress - - secretsmanager:CreateSecret - - secretsmanager:DeleteSecret - - secretsmanager:DescribeSecret - - secretsmanager:GetResourcePolicy - - secretsmanager:GetSecretValue - - secretsmanager:PutSecretValue - - secretsmanager:TagResource - - s3:CreateBucket - - s3:DeleteBucket - - s3:PutObject - - s3:GetObject - - s3:DeleteObject - - cloudformation:CreateStack - - cloudformation:DeleteStack - - cloudformation:DescribeStacks - - cloudformation:ListStacks - - cloudformation:DescribeStackEvents - - ssm:PutParameter - - ssm:GetParameter - - ssm:DeleteParameter - - ec2:RevokeSecurityGroupIngress - - ec2:CreateInternetGateway - - ec2:CreateVpc - - ec2:DescribeInternetGateways - - ec2:DeleteVpc - - ec2:ModifyVpcAttribute - - ec2:DeleteInternetGateway - - ec2:CreateSubnet - - ec2:CreateRouteTable - - ec2:DescribeRouteTables - - ec2:DeleteSubnet - - ec2:DeleteRouteTable - - ec2:AttachInternetGateway - - ec2:ModifySubnetAttribute - - ec2:DetachInternetGateway - - ec2:AssociateRouteTable - - ec2:CreateRoute - - ec2:DisassociateRouteTable - - ec2:DeleteRoute - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLE - - AiUnlimitedInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: !If - - NEEDSROLE - - - !Ref AiUnlimitedRole - - - !Ref IamRoleName - - ACMCertificate: - Type: AWS::CertificateManager::Certificate - Properties: - DomainName: !Ref DnsName - DomainValidationOptions: - - DomainName: !Ref DnsName - HostedZoneId: !Ref HostedZoneId - ValidationMethod: DNS - - LoadBalancerDNS: - Type: AWS::Route53::RecordSetGroup - Properties: - HostedZoneId: !Ref HostedZoneId - RecordSets: - - Name: !Ref DnsName - Type: A - AliasTarget: - HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID - DNSName: !GetAtt LoadBalancer.DNSName - -Outputs: - PublicIP: - Description: EC2 public IP - Value: !GetAtt AiUnlimitedServer.PublicIp - Condition: HASPUBLICIP - - PrivateIP: - Description: EC2 private IP - Value: !GetAtt AiUnlimitedServer.PrivateIp - - AiUnlimitedUiAccess: - Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !Sub https://${ DnsName }:${ AiUnlimitedHttpPort } - - AiUnlimitedApiAccess: - Description: Loadbalancer access endpoint for AI Unlimited API Access - Value: !Sub ${ DnsName }:${ AiUnlimitedGrpcPort } - - InstanceSecurityGroups: - Description: AI Unlimited Security Group - Value: !Join - - ', ' - - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - !GetAtt JupyterSecurityGroup.GroupId - - LoadBalancerSecurityGroups: - Description: AI Unlimited Load Balancer Security Group - Value: !Join - - ', ' - - - !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - - PublicSshConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PublicIp } - Condition: HASKEYANDPUBLIC - - PrivateSshConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PrivateIp } - Condition: HASKEY - - PersistentVolumeId: - Description: Id of the new persistent volume created for AI Unlimited - Value: !Ref AiUnlimitedVolume - Condition: USENEWPERSISTENTVOLUME - - JupyterUIAccess: - Description: Loadbalancer access endpoint for API Access - Value: !Sub https://${ DnsName }:${ JupyterHttpPort }?token=${ JupyterToken } - - JupyterInternalAccessToAiUnlimited: - Description: AI Unlimited endpoint for local Jupyter access - Value: !Sub ai-unlimited.service:${ AiUnlimitedGrpcPort } diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 911e914..283c19b 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -29,12 +29,14 @@ Metadata: - AccessCIDR - PrefixList - SecurityGroup - - AiUnlimitedHttpPort + - AiUnlimitedAuthPort - AiUnlimitedGrpcPort - AiUnlimitedVersion - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiVersion - Label: default: Persistent volume Parameters: @@ -115,7 +117,7 @@ Parameters: Type: AWS::EC2::AvailabilityZone::Name ConstraintDescription: must be the name of a existing subnet. - AiUnlimitedHttpPort: + AiUnlimitedAuthPort: Description: port to access the AI Unlimited UI. Type: Number Default: 3000 @@ -147,10 +149,23 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.2.23 + Default: v0.3.0 + + AiUnlimitedUiVersion: + Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" + Type: String + Default: v0.0.5 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -380,6 +395,8 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -422,9 +439,13 @@ Resources: - !Ref AWS::NoValue - bind_storage - mount_storage + - create_ai_unlimited_folder + - create_init_api_key - install_docker + - configure_ai_unlimited_ui_service - configure_ai_unlimited_service - configure_jupyter_service + - start_ai_unlimited_ui_service - start_ai_unlimited_service - configure_ai_unlimited_scheduler_service - start_ai_unlimited_scheduler_service @@ -453,6 +474,18 @@ Resources: command: !Sub | #!/bin/bash -xe /usr/bin/mount -a + create_ai_unlimited_folder: + commands: + mkdir: + command: !Sub | + #!/bin/bash -xe + mkdir -p /etc/td/ai-unlimited + create_init_api_key: + commands: + run_command: + command: !Sub | + #!/bin/bash -xe + echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt install_docker: files: /usr/lib/systemd/system/docker-install.service: @@ -479,6 +512,49 @@ Resources: docker: enabled: "true" ensureRunning: "true" + configure_ai_unlimited_ui_service: + files: + /usr/lib/systemd/system/ai-unlimited-ui.service: + content: !Sub | + [Unit] + Description=ai-unlimited-ui + After=docker.service + Requires=docker.service + StartLimitInterval=200 + StartLimitBurst=10 + + [Service] + TimeoutStartSec=0 + Restart=always + RestartSec=2 + + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' + ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true + ExecStartPre=-/usr/bin/docker rm %n || true + ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + ExecStart=/usr/bin/docker run \ + -e accept_license=Y \ + -e PLATFORM=aws \ + -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_API_PORT=3282 \ + -e TD_VCD_AUTH_PORT=3000 \ + -e TD_VCD_INIT_API_KEY \ + -p ${ AiUnlimitedUiPort }:80 \ + --network ai_unlimited \ + --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + [Install] + WantedBy=multi-user.target + group: root + mode: "000400" + owner: root + start_ai_unlimited_ui_service: + services: + systemd: + ai-unlimited-ui: + enabled: "true" + ensureRunning: "true" configure_ai_unlimited_service: files: /usr/lib/systemd/system/ai-unlimited.service: @@ -494,16 +570,17 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - ExecStartPre=-/usr/bin/docker exec %n stop || true + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ + -e TD_VCD_INIT_API_KEY \ -v /etc/td/ai-unlimited:/etc/td \ - -p ${ AiUnlimitedHttpPort }:3000 \ + -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ --network ai_unlimited \ --net-alias ${ LoadBalancer.DNSName } \ @@ -534,7 +611,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - ExecStartPre=-/usr/bin/docker exec %n stop || true + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:${ AiUnlimitedSchedulerVersion } ExecStart=/usr/bin/docker run \ @@ -658,9 +735,9 @@ Resources: VpcId: !Ref Vpc GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedHttpPort + - FromPort: !Ref AiUnlimitedAuthPort IpProtocol: tcp - ToPort: !Ref AiUnlimitedHttpPort + ToPort: !Ref AiUnlimitedAuthPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -684,6 +761,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + - FromPort: !Ref AiUnlimitedUiPort + IpProtocol: tcp + ToPort: !Ref AiUnlimitedUiPort + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue Condition: HASCIDRORPREFIXLISTORSECGROUP LoadBalancerSchedulerSecurityGroup: @@ -762,7 +854,17 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedHTTPTargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedHttpPort + Port: !Ref AiUnlimitedAuthPort + Protocol: TCP + + AiUnlimitedUIListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref AiUnlimitedUITargetGroup + LoadBalancerArn: !Ref LoadBalancer + Port: !Ref AiUnlimitedUiPort Protocol: TCP JupyterHTTPListener: @@ -825,7 +927,41 @@ Resources: - td-aiu - ui - http - Port: !Ref AiUnlimitedHttpPort + Port: !Ref AiUnlimitedAuthPort + Protocol: TCP + TargetGroupAttributes: + - Key: stickiness.enabled + Value: true + - Key: stickiness.type + Value: source_ip + - Key: deregistration_delay.timeout_seconds + Value: "20" + Targets: + - Id: !Ref AiUnlimitedServer + Port: !Ref AiUnlimitedAuthPort + VpcId: !Ref Vpc + + AiUnlimitedUITargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckProtocol: HTTP + HealthCheckTimeoutSeconds: 15 + Name: !Join + - '-' + - - !Select + - 4 + - !Split + - '-' + - !Select + - 2 + - !Split + - / + - !Ref AWS::StackId + - td-aiu + - ui + - api + Port: !Ref AiUnlimitedUiPort Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -836,7 +972,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedHttpPort + Port: !Ref AiUnlimitedUiPort VpcId: !Ref Vpc JupyterHTTPTargetGroup: @@ -986,18 +1122,22 @@ Resources: GroupDescription: Enable access to AI Unlimited server over http and grpc SecurityGroupIngress: - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort + FromPort: !Ref AiUnlimitedAuthPort + ToPort: !Ref AiUnlimitedAuthPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp FromPort: !Ref AiUnlimitedGrpcPort ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId + - IpProtocol: tcp + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort + SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: !Ref AiUnlimitedHttpPort - ToPort: !Ref AiUnlimitedHttpPort + FromPort: !Ref AiUnlimitedAuthPort + ToPort: !Ref AiUnlimitedAuthPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue - !If @@ -1007,6 +1147,13 @@ Resources: ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue + - !If + - HASSECURITYGROUP + - IpProtocol: tcp + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort + SourceSecurityGroupId: !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup @@ -1276,6 +1423,9 @@ Resources: - ec2:CreateRoute - ec2:DisassociateRouteTable - ec2:DeleteRoute + - ec2:DescribeAddresses + - ec2:AssociateAddress + - ec2:DisassociateAddress Resource: '*' Roles: - !Ref AiUnlimitedRole @@ -1302,7 +1452,10 @@ Outputs: AiUnlimitedUiAccess: Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedHttpPort } + Value: !If + - PortIsNotEighty + - !Sub "http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck" + - !Sub "http://${ LoadBalancer.DNSName }" AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index bfd0ea9..7a2df95 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -27,12 +27,14 @@ Metadata: - AccessCIDR - PrefixList - SecurityGroup - - AiUnlimitedHttpPort + - AiUnlimitedAuthPort - AiUnlimitedGrpcPort - AiUnlimitedVersion - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiVersion - Label: default: Persistent volume Parameters: @@ -100,8 +102,8 @@ Parameters: Type: AWS::EC2::AvailabilityZone::Name ConstraintDescription: must be the name of a existing subnet. - AiUnlimitedHttpPort: - Description: port to access the AI Unlimited UI. + AiUnlimitedAuthPort: + Description: port to access the AI Unlimited Authentication Service. Type: Number Default: 3000 ConstraintDescription: must be a valid ununsed port between 0 and 65535. @@ -132,16 +134,29 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.2.23 + Default: v0.3.0 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" Type: String Default: latest + AiUnlimitedUiVersion: + Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" + Type: String + Default: v0.0.5 + JupyterHttpPort: Description: port to access the Jupyter UI. Type: Number @@ -365,6 +380,19 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEightyAndHasPublicIp: + !And + - !Not + - !Equals + - !Ref Private + - "true" + - !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + + PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -407,10 +435,14 @@ Resources: - !Ref AWS::NoValue - bind_storage - mount_storage + - create_ai_unlimited_folder + - create_init_api_key - install_docker + - configure_ai_unlimited_ui_service - configure_ai_unlimited_service - - configure_jupyter_service + - start_ai_unlimited_ui_service - start_ai_unlimited_service + - configure_jupyter_service - configure_ai_unlimited_scheduler_service - start_ai_unlimited_scheduler_service - start_jupyter_service @@ -438,6 +470,18 @@ Resources: command: !Sub | #!/bin/bash -xe /usr/bin/mount -a + create_ai_unlimited_folder: + commands: + mkdir: + command: !Sub | + #!/bin/bash -xe + mkdir -p /etc/td/ai-unlimited + create_init_api_key: + commands: + run_command: + command: !Sub | + #!/bin/bash -xe + echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt install_docker: files: /usr/lib/systemd/system/docker-install.service: @@ -464,6 +508,49 @@ Resources: docker: enabled: "true" ensureRunning: "true" + configure_ai_unlimited_ui_service: + files: + /usr/lib/systemd/system/ai-unlimited-ui.service: + content: !Sub | + [Unit] + Description=ai-unlimited-ui + After=docker.service + Requires=docker.service + StartLimitInterval=200 + StartLimitBurst=10 + + [Service] + TimeoutStartSec=0 + Restart=always + RestartSec=2 + + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' + ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true + ExecStartPre=-/usr/bin/docker rm %n || true + ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + ExecStart=/usr/bin/docker run \ + -e accept_license=Y \ + -e PLATFORM=aws \ + -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ + -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ + -e TD_VCD_INIT_API_KEY \ + -p ${ AiUnlimitedUiPort }:80 \ + --network ai_unlimited \ + --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } + [Install] + WantedBy=multi-user.target + group: root + mode: "000400" + owner: root + start_ai_unlimited_ui_service: + services: + systemd: + ai-unlimited-ui: + enabled: "true" + ensureRunning: "true" configure_ai_unlimited_service: files: /usr/lib/systemd/system/ai-unlimited.service: @@ -479,16 +566,17 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - ExecStartPre=-/usr/bin/docker exec %n stop || true + EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ + -e TD_VCD_INIT_API_KEY \ -v /etc/td/ai-unlimited:/etc/td \ - -p ${ AiUnlimitedHttpPort }:3000 \ + -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v @@ -518,7 +606,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - ExecStartPre=-/usr/bin/docker exec %n stop || true + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:latest ExecStart=/usr/bin/docker run \ @@ -558,7 +646,7 @@ Resources: Restart=always RestartSec=2 ExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{userdata,ipython} - ExecStartPre=-/usr/bin/docker exec %n stop || true + ExecStartPre=-/usr/bin/docker stop %n || true ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-jupyter:${ JupyterVersion } ExecStart=/usr/bin/docker run \ @@ -641,9 +729,9 @@ Resources: VpcId: !Ref Vpc GroupDescription: Enable access to AI Unlimited server over http and grpc SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedHttpPort + - FromPort: !Ref AiUnlimitedAuthPort IpProtocol: tcp - ToPort: !Ref AiUnlimitedHttpPort + ToPort: !Ref AiUnlimitedAuthPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -671,6 +759,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + - FromPort: !Ref AiUnlimitedUiPort + IpProtocol: tcp + ToPort: !Ref AiUnlimitedUiPort + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup @@ -945,6 +1048,9 @@ Resources: - ec2:CreateRoute - ec2:DisassociateRouteTable - ec2:DeleteRoute + - ec2:DescribeAddresses + - ec2:AssociateAddress + - ec2:DisassociateAddress Resource: '*' Roles: - !Ref AiUnlimitedRole @@ -971,12 +1077,17 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !Sub http://${AiUnlimitedServer.PublicDnsName}:${ AiUnlimitedHttpPort } + Value: !If [ PortIsNotEightyAndHasPublicIp, + !Sub "http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck", + !Sub "http://${AiUnlimitedServer.PublicDnsName}" ] Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access - Value: !Sub http://${AiUnlimitedServer.PrivateDnsName}:${ AiUnlimitedHttpPort } + Value: !If + - PortIsNotEighty + - !Sub "http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck" + - !Sub "http://${AiUnlimitedServer.PrivateDnsName}" AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access diff --git a/deployments/aws/templates/jupyter/jupyter-with-alb.yaml b/deployments/aws/templates/jupyter/jupyter-with-alb.yaml deleted file mode 100644 index 200cf11..0000000 --- a/deployments/aws/templates/jupyter/jupyter-with-alb.yaml +++ /dev/null @@ -1,815 +0,0 @@ -AWSTemplateFormatVersion: "2010-09-09" - -Description: 'AWS CloudFormation Template jupyter: a jupyter instance configured with the ai-unlimited kernel. Note: You will be billed for the AWS resources used if you create a stack from this template.' - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: Jupyter - Parameters: - - JupyterName - - InstanceType - - RootVolumeSize - - TerminationProtection - - JupyterToken - - IamRole - - IamRoleName - - IamPermissionsBoundary - - Label: - default: Jupyter connection - Parameters: - - AvailabilityZone - - LoadBalancerScheme - - LoadBalancerSubnetOne - - LoadBalancerSubnetTwo - - Private - - Session - - Vpc - - Subnet - - KeyName - - AccessCIDR - - PrefixList - - SecurityGroup - - JupyterToken - - JupyterHttpPort - - JupyterVersion - - Label: - default: Persistent volume - Parameters: - - UsePersistentVolume - - PersistentVolumeSize - - ExistingPersistentVolumeId - - PersistentVolumeDeletionPolicy - -Parameters: - LatestAmiId: - Type: AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 - - JupyterName: - Description: The jupyter service instance name - Type: String - Default: jupyter - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "20" - MinLength: "1" - - JupyterToken: - Description: The token or password equivalent used to access Jupyter. - Type: String - NoEcho: true - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "64" - - Private: - Description: Will Jupyter be deployed in a private network without public IPs? - Type: String - AllowedValues: - - true - - false - Default: false - - LoadBalancerScheme: - Description: "If using a LoadBalancer, will it be internal or internet-facing? \nThe DNS name of an Internet-facing load balancer is publicly resolvable to the public IP addresses of the nodes.\nTherefore, Internet-facing load balancers can route requests from clients over the internet. The nodes of an \ninternal load balancer have only private IP addresses. The DNS name of an internal load balancer is publicly\nresolvable to the private IP addresses of the nodes. Therefore, internal load balancers can route requests only\nfrom clients with access to the VPC for the load balancer.\n" - Type: String - AllowedValues: - - internal - - internet-facing - Default: internet-facing - - Session: - Description: Should Jupyter be accessible via AWS Session Manager? - Type: String - AllowedValues: - - true - - false - Default: false - - Vpc: - Description: Network to deploy the jupyter service to. - Type: AWS::EC2::VPC::Id - ConstraintDescription: must be the name of an existing vpc. - - Subnet: - Description: Subnetwork to deploy the Jupyter service to. - Type: AWS::EC2::Subnet::Id - ConstraintDescription: must be the name of a existing subnet. - - AvailabilityZone: - Description: "Availability zone to deploy the Jupyter service to.\nThis must match the subnet, the zone of any pre existing volumes if used, \nand the instance type must be available in the selected zone.\n" - Type: AWS::EC2::AvailabilityZone::Name - ConstraintDescription: must be the name of a existing subnet. - - LoadBalancerSubnetOne: - Description: First subnetwork to deploy the Application Load Balancer to. - Type: AWS::EC2::Subnet::Id - - LoadBalancerSubnetTwo: - Description: Second subnetwork to deploy the Application Load Balancer to. - Type: AWS::EC2::Subnet::Id - - HostedZoneId: - Description: Zone ID of an existing Route 53 zone to add an entry for the Application Load Balancer to. - Type: AWS::Route53::HostedZone::Id - - DnsName: - Description: | - Name for Load Balancer DNS Entry, must fit as subdomain in the provides Route 53 Hosted Zone ID. - Example: jupyter.yourhostedzonedomainname.com - Type: String - - JupyterHttpPort: - Description: port to access the jupyter service ui. - Type: Number - Default: 8888 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - JupyterVersion: - Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" - Type: String - Default: latest - - RootVolumeSize: - Description: size of the root disk to the jupyter server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - UsePersistentVolume: - Description: Should we use a new or existing volume for persistent data on the jupyter server. - Type: String - AllowedValues: - - New - - Existing - Default: New - ConstraintDescription: Specify if you are using a a new persistent volume, an existing one, or none. - - PersistentVolumeSize: - Description: size of the optional persistent disk to the jupyter server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - ExistingPersistentVolumeId: - Description: Id of the existing persistent volume to attach. Must be int the same availability zone as the Jupyter instance. - Type: String - Default: None - - PersistentVolumeDeletionPolicy: - Description: Behavior for the Persistent Volume when deleting the cloudformations deployment. - Type: String - AllowedValues: - - Delete - - Retain - - RetainExceptOnCreate - - Snapshot - Default: Retain - - TerminationProtection: - Description: Enable instance termination protection. - Type: String - AllowedValues: - - true - - false - Default: false - - InstanceType: - Description: jupyter EC2 instance type - Type: String - AllowedValues: - - t3.nano - - t3.micro - - t3.small - - t3.medium - - t3.large - - m3.medium - - m3.large - - m3.xlarge - - m3.2xlarge - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - c3.large - - c3.xlarge - - c3.2xlarge - - c3.4xlarge - - c3.8xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - i2.xlarge - - i2.2xlarge - - i2.4xlarge - - i2.8xlarge - Default: t3.micro - ConstraintDescription: must be a valid EC2 instance type. - - KeyName: - Description: Name of an existing EC2 KeyPair to enable SSH access to the instances, leave empty if no ssh keys should be included - Type: String - - IamRole: - Description: | - Create a new IAM role for jupyter or use an exiting one. - Requires CAPABILITY_IAM if creating a new IAM Role - Type: String - AllowedValues: - - None - - New - - Existing - Default: New - - IamRoleName: - Description: | - Name of an existing IAM Role to assign to Jupyter, - or the name to give to the newly created role. - Leave blank to use an autogenerated name. - Requires CAPABILITY_NAMED_IAM if naming a new IAM Role. - Type: String - - IamPermissionsBoundary: - Description: | - Optional: Arn of a permissions boundary to pass to the IAM Role assigned to Jupyter. - Type: String - - AccessCIDR: - Description: The IP address range that can be used to communicate with the juptyer instance. - Type: String - 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. - - PrefixList: - Description: The PrefixList that can be used to communicate with the jupyter instance. - Type: String - ConstraintDescription: must be a valid prefixlist - - SecurityGroup: - Description: The SecurityGroup that can be used to communicate with the Jupyter instance. - Type: String - ConstraintDescription: must be a valid securityGroup ID - -Rules: - subnetsInVpc: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - - instanceTypeInZone: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - -Conditions: - NEEDSROLE: !Equals - - !Ref IamRole - - New - - HASPUBLICIP: !Not - - !Equals - - !Ref Private - - "true" - - HASKEY: !Not - - !Equals - - !Ref KeyName - - "" - - HASCIDR: !Not - - !Equals - - !Ref AccessCIDR - - "" - - HASPREFIXLIST: !Not - - !Equals - - !Ref PrefixList - - "" - - HASSECURITYGROUP: !Not - - !Equals - - !Ref SecurityGroup - - "" - - HASCIDRORPREFIXLIST: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - HASCIDRORPREFIXLISTORSECGROUP: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - !Condition HASSECURITYGROUP - - USESESSIONMANAGER: !Equals - - !Ref Session - - "true" - - NEEDSROLEANDSESSIONMANAGER: !And - - !Condition NEEDSROLE - - !Condition USESESSIONMANAGER - - NEEDINSTANCEPROFILE: !Or - - !Not - - !Condition NEEDSROLE - - !Condition NEEDSROLEANDSESSIONMANAGER - - HASKEYANDPUBLIC: !And - - !Condition HASKEY - - !Condition HASPUBLICIP - - HASKEYANDCIDRORPREFIXLISTORSECGROUP: !And - - !Condition HASKEY - - !Condition HASCIDRORPREFIXLISTORSECGROUP - - USENEWPERSISTENTVOLUME: !Equals - - !Ref UsePersistentVolume - - New - - HASIAMPERMISSIONSBOUNDARY: !Not - - !Equals - - !Ref IamPermissionsBoundary - - "" - - HASIAMROLENAME: !Not - - !Equals - - !Ref IamRoleName - - "" - -Resources: - JupyterVolume: - DeletionPolicy: !Ref PersistentVolumeDeletionPolicy - Type: AWS::EC2::Volume - Properties: - AvailabilityZone: !Ref AvailabilityZone - Size: !Ref PersistentVolumeSize - Encrypted: true - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref JupyterName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - Key: Usage - Value: persistent storage - Condition: USENEWPERSISTENTVOLUME - - JupyterServer: - CreationPolicy: - ResourceSignal: - Timeout: PT15M - Type: AWS::EC2::Instance - Metadata: - AWS::CloudFormation::Init: - configSets: - jupyter_install: - - prepare_directory - - !If - - USENEWPERSISTENTVOLUME - - prepare_new_storage - - !Ref AWS::NoValue - - bind_storage - - mount_storage - - install_docker - - configure_jupyter_service - - start_jupyter_service - prepare_directory: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - /usr/bin/mkdir -p /etc/td - prepare_new_storage: - commands: - mkfs: - command: !Sub | - #!/bin/bash -xe - /usr/sbin/mkfs -t ext4 /dev/nvme1n1 - bind_storage: - commands: - fstab: - command: !Sub | - #!/bin/bash -xe - /usr/bin/echo "/dev/nvme1n1 /etc/td ext4 defaults 0 2" >> /etc/fstab - mount_storage: - commands: - mount: - command: !Sub | - #!/bin/bash -xe - /usr/bin/mount -a - install_docker: - files: - /usr/lib/systemd/system/docker-install.service: - content: !Sub | - [Unit] - Description=Install docker - - [Service] - Type=oneshot - ExecStart=/bin/bash -c "while ! dnf update; do sleep 2; done && while ! dnf install -y docker; do sleep 2; done" - RemainAfterExit=yes - - [Install] - WantedBy=multi-user.target - commands: - verify_docker: - command: !Sub | - #!/bin/bash -xe - systemctl start docker-install - systemctl start docker - systemctl enable docker - services: - systemd: - docker: - enabled: "true" - ensureRunning: "true" - configure_jupyter_service: - files: - /usr/lib/systemd/system/jupyter.service: - content: !Sub | - [Unit] - Description=jupyter - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited - ExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{userdata,ipython} - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-jupyter:${ JupyterVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e JUPYTER_TOKEN=${ JupyterToken } \ - -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \ - -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \ - -p ${ JupyterHttpPort }:8888 \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-jupyter:${ JupyterVersion } - - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_jupyter_service: - services: - systemd: - jupyter: - enabled: "true" - ensureRunning: "true" - Properties: - PropagateTagsToVolumeOnCreation: true - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - VolumeSize: !Ref RootVolumeSize - Encrypted: true - NetworkInterfaces: - - DeviceIndex: 0 - SubnetId: !Ref Subnet - GroupSet: - - !GetAtt JupyterSecurityGroup.GroupId - AssociatePublicIpAddress: !If - - HASPUBLICIP - - true - - !Ref AWS::NoValue - ImageId: !Ref LatestAmiId - InstanceType: !Ref InstanceType - KeyName: !If - - HASKEY - - !Ref KeyName - - !Ref AWS::NoValue - DisableApiTermination: !Ref TerminationProtection - IamInstanceProfile: !If - - NEEDINSTANCEPROFILE - - !Ref JupyterInstanceProfile - - !Ref AWS::NoValue - Volumes: - - Device: /dev/xvdb - VolumeId: !If - - USENEWPERSISTENTVOLUME - - !Ref JupyterVolume - - !Ref ExistingPersistentVolumeId - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref JupyterName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - UserData: !Base64 - Fn::Sub: | - #!/bin/bash -xe - yum update -y - yum update -y aws-cfn-bootstrap - /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource JupyterServer --configsets jupyter_install --region ${AWS::Region} - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource JupyterServer --region ${AWS::Region} - - LoadBalancerJupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to Jupyter server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref JupyterHttpPort - IpProtocol: tcp - ToPort: !Ref JupyterHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Scheme: !Ref LoadBalancerScheme - Subnets: - - !Ref LoadBalancerSubnetOne - - !Ref LoadBalancerSubnetTwo - SecurityGroups: - - !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - Type: application - - JupyterHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref JupyterHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref JupyterHttpPort - Protocol: HTTPS - Certificates: - - CertificateArn: !Ref ACMCertificate - - JupyterHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - jupyter - - ui - - http - Port: !Ref JupyterHttpPort - Protocol: HTTP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: app_cookie - - Key: stickiness.app_cookie.cookie_name - Value: TDJUPYTERHTTPSSESSION - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref JupyterServer - Port: !Ref JupyterHttpPort - VpcId: !Ref Vpc - - JupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to jupyter server over http - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref JupyterHttpPort - ToPort: !Ref JupyterHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref JupyterHttpPort - ToPort: !Ref JupyterHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - SecurityGroupIngress: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !GetAtt JupyterSecurityGroup.GroupId - FromPort: 22 - IpProtocol: tcp - ToPort: 22 - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASKEYANDCIDRORPREFIXLISTORSECGROUP - - JupyterRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - Path: / - Condition: NEEDSROLEANDSESSIONMANAGER - - SessionManagerPolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - jupyter - - session - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ssm:DescribeAssociation - - ssm:GetDeployablePatchSnapshotForInstance - - ssm:GetDocument - - ssm:DescribeDocument - - ssm:GetManifest - - ssm:ListAssociations - - ssm:ListInstanceAssociations - - ssm:PutInventory - - ssm:PutComplianceItems - - ssm:PutConfigurePackageResult - - ssm:UpdateAssociationStatus - - ssm:UpdateInstanceAssociationStatus - - ssm:UpdateInstanceInformation - Resource: '*' - - Effect: Allow - Action: - - ssmmessages:CreateControlChannel - - ssmmessages:CreateDataChannel - - ssmmessages:OpenControlChannel - - ssmmessages:OpenDataChannel - Resource: '*' - - Effect: Allow - Action: - - ec2messages:AcknowledgeMessage - - ec2messages:DeleteMessage - - ec2messages:FailMessage - - ec2messages:GetEndpoint - - ec2messages:GetMessages - - ec2messages:SendReply - Resource: '*' - Roles: - - !Ref JupyterRole - Condition: NEEDSROLEANDSESSIONMANAGER - - JupyterInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: !If - - NEEDSROLEANDSESSIONMANAGER - - - !Ref JupyterRole - - - !Ref IamRoleName - Condition: NEEDINSTANCEPROFILE - - ACMCertificate: - Type: AWS::CertificateManager::Certificate - Properties: - DomainName: !Ref DnsName - DomainValidationOptions: - - DomainName: !Ref DnsName - HostedZoneId: !Ref HostedZoneId - ValidationMethod: DNS - - LoadBalancerDNS: - Type: AWS::Route53::RecordSetGroup - Properties: - HostedZoneId: !Ref HostedZoneId - RecordSets: - - Name: !Ref DnsName - Type: A - AliasTarget: - HostedZoneId: !GetAtt LoadBalancer.CanonicalHostedZoneID - DNSName: !GetAtt LoadBalancer.DNSName - -Outputs: - PublicIP: - Description: EC2 public IP - Value: !GetAtt JupyterServer.PublicIp - Condition: HASPUBLICIP - - PrivateIP: - Description: EC2 private IP - Value: !GetAtt JupyterServer.PrivateIp - - LoadBalancerJupyterUIAccess: - Description: Loadbalancer access endpoint for API Access - Value: !Sub https://${ DnsName }:${ JupyterHttpPort }?token=${ JupyterToken } - - InstanceSecurityGroups: - Description: AI Unlimited Security Group - Value: !GetAtt JupyterSecurityGroup.GroupId - - - LoadBalancerSecurityGroups: - Description: AI Unlimited Load Balancer Security Group - Value: !Join - - ', ' - - - !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - - PublicSSHConeection: - Description: Jupyter ssh connnection string - Value: !Sub ssh ec2-user@${ JupyterServer.PublicIp } - Condition: HASKEYANDPUBLIC - - PrivateSSHConeection: - Description: jupyter ssh connnection string - Value: !Sub ssh ec2-user@${ JupyterServer.PrivateIp } - Condition: HASKEY - - PersistentVolumeId: - Description: Id of the new persistent volume created for Jupyter - Value: !Ref JupyterVolume - Condition: USENEWPERSISTENTVOLUME diff --git a/deployments/azure/scripts/ai-unlimited-scheduler.service b/deployments/azure/scripts/ai-unlimited-scheduler.service index 9df39b5..9a315b9 100644 --- a/deployments/azure/scripts/ai-unlimited-scheduler.service +++ b/deployments/azure/scripts/ai-unlimited-scheduler.service @@ -9,8 +9,8 @@ StartLimitBurst=10 TimeoutStartSec=0 Restart=always RestartSec=2 -ExecStartPre=-/usr/bin/docker exec %n stop || true -ExecStartPre=-/usr/bin/docker rm %n || true +ExecStartPre=-/usr/bin/docker stop %n +ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull {0}/{1}:{2} ExecStart=/usr/bin/docker run \ --network ai_unlimited \ diff --git a/deployments/azure/scripts/ai-unlimited-ui.service b/deployments/azure/scripts/ai-unlimited-ui.service new file mode 100644 index 0000000..95cd599 --- /dev/null +++ b/deployments/azure/scripts/ai-unlimited-ui.service @@ -0,0 +1,28 @@ +[Unit] +Description=AI Unlimited UI +After=ai-unlimited.service +Requires=ai-unlimited.service +StartLimitInterval=200 +StartLimitBurst=10 + +[Service] +TimeoutStartSec=0 +Restart=always +RestartSec=2 +EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt +ExecStartPre=-/usr/bin/docker stop %n +ExecStartPre=-/usr/bin/docker rm %n +ExecStartPre=/usr/bin/docker pull {0}/{1}:{2} + +ExecStart=/usr/bin/docker run \ + -e TD_VCD_UI_PORT={3} \ + -e TD_VCD_AUTH_PORT={4}\ + -e TD_VCD_API_PORT={5}\ + -e TD_VCD_INIT_API_KEY \ + -v /etc/td/ai-unlimited:/etc/td \ + -p {3}:80 \ + --network ai_unlimited {6} \ + --rm --name %n {0}/{1}:{2} + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/deployments/azure/scripts/ai-unlimited.cloudinit.yaml b/deployments/azure/scripts/ai-unlimited.cloudinit.yaml index 8146cb5..98facc2 100644 --- a/deployments/azure/scripts/ai-unlimited.cloudinit.yaml +++ b/deployments/azure/scripts/ai-unlimited.cloudinit.yaml @@ -10,17 +10,26 @@ write_files: owner: root:root path: /usr/lib/systemd/system/ai-unlimited-scheduler.service permissions: '0640' +- encoding: b64 + content: "{2}" + owner: root:root + path: /usr/lib/systemd/system/ai-unlimited-ui.service + permissions: '0640' runcmd: -- mkdir -p /etc/td +- mkdir -p /etc/td - | export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}'); if [ -n "${{PERMDISK}}" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi /usr/bin/echo "LABEL=WORKSPACES /etc/td ext4 defaults 0 2" >> /etc/fstab /usr/bin/mount -a - while [ $(systemctl status docker | grep "active (running)" | wc -l) -lt 1 ]; do sleep 5; done +- mkdir -p /etc/td/ai-unlimited +- echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt - sleep 60 - systemctl enable ai-unlimited.service - systemctl start ai-unlimited.service - systemctl enable ai-unlimited-scheduler.service - systemctl start ai-unlimited-scheduler.service +- systemctl enable ai-unlimited-ui.service +- systemctl start ai-unlimited-ui.service diff --git a/deployments/azure/scripts/ai-unlimited.service b/deployments/azure/scripts/ai-unlimited.service index f7d100a..b9bed57 100644 --- a/deployments/azure/scripts/ai-unlimited.service +++ b/deployments/azure/scripts/ai-unlimited.service @@ -9,10 +9,11 @@ StartLimitBurst=10 TimeoutStartSec=0 Restart=always RestartSec=2 +EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt ExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited -ExecStartPre=-/usr/bin/docker exec %n stop || true -ExecStartPre=-/usr/bin/docker rm %n || true +ExecStartPre=-/usr/bin/docker stop %n +ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull {0}/{1}:{2} ExecStart=/usr/bin/docker run \ @@ -21,6 +22,7 @@ ExecStart=/usr/bin/docker run \ -e ARM_USE_MSI=true \ -e ARM_SUBSCRIPTION_ID={5} \ -e ARM_TENANT_ID={6} \ + -e TD_VCD_INIT_API_KEY \ -v /etc/td/ai-unlimited:/etc/td \ -p {3}:3000 \ -p {4}:3282 \ diff --git a/deployments/azure/scripts/all-in-one.cloudinit.yaml b/deployments/azure/scripts/all-in-one.cloudinit.yaml index 0343087..237e870 100644 --- a/deployments/azure/scripts/all-in-one.cloudinit.yaml +++ b/deployments/azure/scripts/all-in-one.cloudinit.yaml @@ -15,6 +15,11 @@ write_files: owner: root:root path: /usr/lib/systemd/system/ai-unlimited-scheduler.service permissions: '0640' +- encoding: b64 + content: "{3}" + owner: root:root + path: /usr/lib/systemd/system/ai-unlimited-ui.service + permissions: '0640' runcmd: - mkdir -p /etc/td @@ -24,6 +29,8 @@ runcmd: /usr/bin/echo "LABEL=WORKSPACES /etc/td ext4 defaults 0 2" >> /etc/fstab /usr/bin/mount -a - while [ $(systemctl status docker | grep "active (running)" | wc -l) -lt 1 ]; do sleep 5; done +- mkdir -p /etc/td/ai-unlimited +- echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt - sleep 60 - systemctl enable ai-unlimited.service - systemctl start ai-unlimited.service @@ -31,3 +38,5 @@ runcmd: - systemctl start jupyter.service - systemctl enable ai-unlimited-scheduler.service - systemctl start ai-unlimited-scheduler.service +- systemctl enable ai-unlimited-ui.service +- systemctl start ai-unlimited-ui.service diff --git a/deployments/azure/scripts/jupyter.service b/deployments/azure/scripts/jupyter.service index 2fe6cd7..f9b4da7 100644 --- a/deployments/azure/scripts/jupyter.service +++ b/deployments/azure/scripts/jupyter.service @@ -11,8 +11,8 @@ Restart=always RestartSec=2 ExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited ExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}} -ExecStartPre=-/usr/bin/docker exec %n stop || true -ExecStartPre=-/usr/bin/docker rm %n || true +ExecStartPre=-/usr/bin/docker stop %n +ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull {0}/{1}:{2} ExecStart=/usr/bin/docker run \ diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json index 53cb6b3..5da992d 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10962030278510784556" + "templateHash": "11962177184326515391" } }, "parameters": { @@ -22,12 +22,6 @@ "description": "Name for the AI Unlimited service's virtual machine." } }, - "PublicKey": { - "type": "securestring", - "metadata": { - "description": "SSH public key value" - } - }, "OSVersion": { "type": "string", "defaultValue": "Ubuntu-2004", @@ -75,11 +69,11 @@ "description": "The CIDR ranges that can be used to communicate with the AI Unlimited service instance." } }, - "AiUnlimitedHttpPort": { + "AiUnlimitedAuthPort": { "type": "int", "defaultValue": 3000, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited auth service." } }, "AiUnlimitedGrpcPort": { @@ -89,6 +83,13 @@ "description": "port to access the AI Unlimited service api." } }, + "AiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "port to access the AI Unlimited service UI." + } + }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -109,13 +110,6 @@ "description": "GUID of the AI Unlimited Role" } }, - "AllowPublicSSH": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "allow access the AI Unlimited ssh port from the access cidr." - } - }, "UseKeyVault": { "type": "string", "defaultValue": "New", @@ -154,11 +148,18 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.2.23", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, + "AiUnlimitedUIVersion": { + "type": "string", + "defaultValue": "v0.0.5", + "metadata": { + "description": "Container Version of the AI Unlimited UI service" + } + }, "Tags": { "type": "object", "defaultValue": {}, @@ -168,9 +169,10 @@ } }, "variables": { - "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", - "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", + "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td\n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", + "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -179,7 +181,8 @@ "nlbDnsLabelPrefix": "[format('td{0}-nlb', variables('dnsId'))]", "registry": "teradata", "workspaceRepository": "ai-unlimited-workspaces", - "workspaceSchedulerRepository": "ai-unlimited-scheduler" + "workspaceSchedulerRepository": "ai-unlimited-scheduler", + "workspaceUIRepository": "ai-unlimited-workspaces-ui" }, "resources": [ { @@ -395,8 +398,8 @@ "accessCidrs": { "value": "[parameters('AccessCIDRs')]" }, - "aiUnlimitedHttpPort": { - "value": "[parameters('AiUnlimitedHttpPort')]" + "aiUnlimitedAuthPort": { + "value": "[parameters('AiUnlimitedAuthPort')]" }, "aiUnlimitedGrpcPort": { "value": "[parameters('AiUnlimitedGrpcPort')]" @@ -404,6 +407,9 @@ "aiUnlimitedSchedulerHttpPort": { "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, + "aiUnlimitedUIHttpPort": { + "value": "[parameters('AiUnlimitedUIHttpPort')]" + }, "sourceAppSecGroups": { "value": "[parameters('SourceAppSecGroups')]" }, @@ -411,7 +417,7 @@ "value": "[parameters('detinationAppSecGroups')]" }, "sshAccess": { - "value": "[parameters('AllowPublicSSH')]" + "value": false }, "tags": { "value": "[parameters('Tags')]" @@ -424,7 +430,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "3577307217619354540" + "templateHash": "17204210556751390284" } }, "parameters": { @@ -450,7 +456,7 @@ "type": "bool", "defaultValue": false }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -462,6 +468,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -527,10 +537,10 @@ ] }, { - "condition": "[not(equals(parameters('aiUnlimitedHttpPort'), 0))]", + "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-http-allow', variables('uniqueSecurityGroupName')))]", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", "properties": { "copy": [ { @@ -553,7 +563,7 @@ "access": "Allow", "description": "allow http to the workspace instance", "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedHttpPort'))]", + "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", "direction": "Inbound", "priority": 701, "protocol": "Tcp", @@ -677,6 +687,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow http to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", + "direction": "Inbound", + "priority": 705, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -708,8 +756,8 @@ "location": { "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" }, - "aiUnlimitedHttpPort": { - "value": "[parameters('AiUnlimitedHttpPort')]" + "aiUnlimitedAuthPort": { + "value": "[parameters('AiUnlimitedAuthPort')]" }, "aiUnlimitedGrpcPort": { "value": "[parameters('AiUnlimitedGrpcPort')]" @@ -717,6 +765,9 @@ "aiUnlimitedSchedulerHttpPort": { "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, + "aiUnlimitedUIHttpPort": { + "value": "[parameters('AiUnlimitedUIHttpPort')]" + }, "tags": { "value": "[parameters('Tags')]" } @@ -728,7 +779,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14601682444932366115" + "templateHash": "1616678944691212739" } }, "parameters": { @@ -741,7 +792,7 @@ "dnsPrefix": { "type": "string" }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -757,6 +808,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "tags": { "type": "object", "defaultValue": {} @@ -798,8 +853,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedHttpPort'), 'backendPort', parameters('aiUnlimitedHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedAuthPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", @@ -1032,7 +1087,7 @@ "value": "azureuser" }, "sshPublicKey": { - "value": "[parameters('PublicKey')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key'), '2022-09-01').outputs.PublicKey.value]" }, "dnsLabelPrefix": { "value": "[variables('dnsLabelPrefix')]" @@ -1050,7 +1105,7 @@ "value": "[parameters('OSVersion')]" }, "cloudInitData": { - "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedHttpPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort')))))]" + "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" }, "usePersistentVolume": { "value": "[parameters('UsePersistentVolume')]" @@ -1433,7 +1488,140 @@ }, "dependsOn": [ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer')]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer')]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "Public-Key", + "resourceGroup": "[parameters('ResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "Name": { + "value": "[parameters('AiUnlimitedName')]" + }, + "Location": { + "value": "[deployment().location]" + }, + "VaultName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" + }, + "RoleID": { + "value": "[parameters('RoleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2861565763492996333" + } + }, + "parameters": { + "Location": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "VaultName": { + "type": "string" + }, + "RoleID": { + "type": "string" + }, + "Uuid": { + "type": "string", + "defaultValue": "[newGuid()]" + } + }, + "variables": { + "SecretName": "[format('{0}-PrivateKey', parameters('Name'))]", + "ScriptName": "[format('{0}-createKeys', parameters('Name'))]", + "IdentityName": "[format('{0}-scratch', parameters('Name'))]", + "RoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleID'))]", + "RoleDefinitionName": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), variables('RoleDefinitionId'), resourceGroup().id)]" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('IdentityName')]", + "location": "[parameters('Location')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[variables('RoleDefinitionName')]", + "properties": { + "roleDefinitionId": "[variables('RoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('ScriptName')]", + "location": "[parameters('Location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')))]": {} + } + }, + "kind": "AzureCLI", + "properties": { + "forceUpdateTag": "[parameters('Uuid')]", + "azCliVersion": "2.0.80", + "timeout": "PT30M", + "retentionInterval": "P1D", + "cleanupPreference": "OnSuccess", + "scriptContent": " #/bin/bash -e\n\n echo -e 'y' | ssh-keygen -f scratch\n\n privateKey=$(cat scratch)\n publicKey=$(cat 'scratch.pub')\n\n json=\"{\\\"keyinfo\\\":{\\\"privateKey\\\":\\\"$privateKey\\\",\\\"publicKey\\\":\\\"$publicKey\\\"}}\"\n\n echo \"$json\" > $AZ_SCRIPTS_OUTPUT_PATH\n " + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]", + "[resourceId('Microsoft.Authorization/roleAssignments', variables('RoleDefinitionName'))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('VaultName'), variables('SecretName'))]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.privateKey]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName'))]" + ] + } + ], + "outputs": { + "PublicKey": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.publicKey]" + }, + "Status": { + "type": "object", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').status]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" ] } ], @@ -1448,11 +1636,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", @@ -1462,10 +1650,6 @@ "type": "string", "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedGrpcPort'))]" }, - "sshCommand": { - "type": "string", - "value": "[format('ssh azureuser@{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value)]" - }, "KeyVaultName": { "type": "string", "value": "[if(equals(parameters('UseKeyVault'), 'New'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value, '')]" diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json index 566a740..a37a9d5 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7331097313669370218" + "templateHash": "10042357043303845085" } }, "parameters": { @@ -22,12 +22,6 @@ "description": "Name for the AI Unlimited service's virtual machine." } }, - "PublicKey": { - "type": "securestring", - "metadata": { - "description": "SSH public key value" - } - }, "OSVersion": { "type": "string", "defaultValue": "Ubuntu-2004", @@ -75,11 +69,11 @@ "description": "The CIDR ranges that can be used to communicate with the AI Unlimited service instance." } }, - "AiUnlimitedHttpPort": { + "AiUnlimitedAuthPort": { "type": "int", "defaultValue": 3000, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited auth service." } }, "AiUnlimitedGrpcPort": { @@ -89,6 +83,13 @@ "description": "port to access the AI Unlimited service api." } }, + "AiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "port to access the AI Unlimited service UI." + } + }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -109,13 +110,6 @@ "description": "GUID of the AI Unlimited Role" } }, - "AllowPublicSSH": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "allow access the AI Unlimited ssh port from the access cidr." - } - }, "UseKeyVault": { "type": "string", "defaultValue": "New", @@ -154,11 +148,18 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.2.23", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, + "AiUnlimitedUIVersion": { + "type": "string", + "defaultValue": "v0.0.5", + "metadata": { + "description": "Container Version of the AI Unlimited UI service" + } + }, "Tags": { "type": "object", "defaultValue": {}, @@ -168,9 +169,10 @@ } }, "variables": { - "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", - "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", + "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td\n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", + "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -178,7 +180,8 @@ "registry": "teradata", "workspaceRepository": "ai-unlimited-workspaces", "workspaceSchedulerRepository": "ai-unlimited-scheduler", - "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedHttpPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort')))))]" + "workspaceUIRepository": "ai-unlimited-workspaces-ui", + "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" }, "resources": [ { @@ -395,10 +398,10 @@ "value": "[parameters('AccessCIDRs')]" }, "sshAccess": { - "value": "[parameters('AllowPublicSSH')]" + "value": false }, - "aiUnlimitedHttpPort": { - "value": "[parameters('AiUnlimitedHttpPort')]" + "aiUnlimitedAuthPort": { + "value": "[parameters('AiUnlimitedAuthPort')]" }, "aiUnlimitedGrpcPort": { "value": "[parameters('AiUnlimitedGrpcPort')]" @@ -406,6 +409,9 @@ "aiUnlimitedSchedulerHttpPort": { "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, + "aiUnlimitedUIHttpPort": { + "value": "[parameters('AiUnlimitedUIHttpPort')]" + }, "sourceAppSecGroups": { "value": "[parameters('SourceAppSecGroups')]" }, @@ -423,7 +429,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "3577307217619354540" + "templateHash": "17204210556751390284" } }, "parameters": { @@ -449,7 +455,7 @@ "type": "bool", "defaultValue": false }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -461,6 +467,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -526,10 +536,10 @@ ] }, { - "condition": "[not(equals(parameters('aiUnlimitedHttpPort'), 0))]", + "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-http-allow', variables('uniqueSecurityGroupName')))]", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", "properties": { "copy": [ { @@ -552,7 +562,7 @@ "access": "Allow", "description": "allow http to the workspace instance", "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedHttpPort'))]", + "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", "direction": "Inbound", "priority": 701, "protocol": "Tcp", @@ -676,6 +686,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow http to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", + "direction": "Inbound", + "priority": 705, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -708,7 +756,7 @@ "value": "azureuser" }, "sshPublicKey": { - "value": "[parameters('PublicKey')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key'), '2022-09-01').outputs.PublicKey.value]" }, "dnsLabelPrefix": { "value": "[variables('dnsLabelPrefix')]" @@ -1102,7 +1150,140 @@ } }, "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "Public-Key", + "resourceGroup": "[parameters('ResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "Name": { + "value": "[parameters('AiUnlimitedName')]" + }, + "Location": { + "value": "[deployment().location]" + }, + "VaultName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" + }, + "RoleID": { + "value": "[parameters('RoleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2861565763492996333" + } + }, + "parameters": { + "Location": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "VaultName": { + "type": "string" + }, + "RoleID": { + "type": "string" + }, + "Uuid": { + "type": "string", + "defaultValue": "[newGuid()]" + } + }, + "variables": { + "SecretName": "[format('{0}-PrivateKey', parameters('Name'))]", + "ScriptName": "[format('{0}-createKeys', parameters('Name'))]", + "IdentityName": "[format('{0}-scratch', parameters('Name'))]", + "RoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleID'))]", + "RoleDefinitionName": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), variables('RoleDefinitionId'), resourceGroup().id)]" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('IdentityName')]", + "location": "[parameters('Location')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[variables('RoleDefinitionName')]", + "properties": { + "roleDefinitionId": "[variables('RoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('ScriptName')]", + "location": "[parameters('Location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')))]": {} + } + }, + "kind": "AzureCLI", + "properties": { + "forceUpdateTag": "[parameters('Uuid')]", + "azCliVersion": "2.0.80", + "timeout": "PT30M", + "retentionInterval": "P1D", + "cleanupPreference": "OnSuccess", + "scriptContent": " #/bin/bash -e\n\n echo -e 'y' | ssh-keygen -f scratch\n\n privateKey=$(cat scratch)\n publicKey=$(cat 'scratch.pub')\n\n json=\"{\\\"keyinfo\\\":{\\\"privateKey\\\":\\\"$privateKey\\\",\\\"publicKey\\\":\\\"$publicKey\\\"}}\"\n\n echo \"$json\" > $AZ_SCRIPTS_OUTPUT_PATH\n " + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]", + "[resourceId('Microsoft.Authorization/roleAssignments', variables('RoleDefinitionName'))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('VaultName'), variables('SecretName'))]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.privateKey]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName'))]" + ] + } + ], + "outputs": { + "PublicKey": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.publicKey]" + }, + "Status": { + "type": "object", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').status]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" ] } ], @@ -1117,11 +1298,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", @@ -1131,10 +1312,6 @@ "type": "string", "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedGrpcPort'))]" }, - "sshCommand": { - "type": "string", - "value": "[format('ssh azureuser@{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value)]" - }, "KeyVaultName": { "type": "string", "value": "[if(equals(parameters('UseKeyVault'), 'New'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value, '')]" diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json index 1007dc0..d0b204d 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "12094445056991366561" + "templateHash": "1860230839229358162" } }, "parameters": { @@ -22,12 +22,6 @@ "description": "Name for the Workspace service's virtual machine." } }, - "PublicKey": { - "type": "securestring", - "metadata": { - "description": "SSH public key value" - } - }, "OSVersion": { "type": "string", "defaultValue": "Ubuntu-2004", @@ -82,11 +76,11 @@ "description": "port to access the Jupyter Labs UI." } }, - "AiUnlimitedHttpPort": { + "AiUnlimitedAuthPort": { "type": "int", "defaultValue": 3000, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited auth service." } }, "AiUnlimitedGrpcPort": { @@ -96,6 +90,13 @@ "description": "port to access the AI Unlimited service api." } }, + "AiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "port to access the AI Unlimited service UI." + } + }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -116,13 +117,6 @@ "description": "GUID of the AI Unlimited Role" } }, - "AllowPublicSSH": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "allow access the AI Unlimited ssh port from the access cidr." - } - }, "UseKeyVault": { "type": "string", "defaultValue": "New", @@ -161,14 +155,21 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.2.23", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, + "AiUnlimitedUIVersion": { + "type": "string", + "defaultValue": "v0.0.5", + "metadata": { + "description": "Container Version of the AI Unlimited UI service" + } + }, "JupyterVersion": { "type": "string", - "defaultValue": "latest", + "defaultValue": "v0.0.43", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -188,11 +189,11 @@ } }, "variables": { - "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", - "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", - "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "AiUnlimitedSchedulerGrpcPort": 50051, + "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{3}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", + "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", + "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -202,7 +203,8 @@ "registry": "teradata", "workspaceRepository": "ai-unlimited-workspaces", "jupyterRepository": "ai-unlimited-jupyter", - "workspaceSchedulerRepository": "ai-unlimited-scheduler" + "workspaceSchedulerRepository": "ai-unlimited-scheduler", + "workspaceUIRepository": "ai-unlimited-workspaces-ui" }, "resources": [ { @@ -419,10 +421,10 @@ "value": "[parameters('AccessCIDRs')]" }, "sshAccess": { - "value": "[parameters('AllowPublicSSH')]" + "value": false }, - "aiUnlimitedHttpPort": { - "value": "[parameters('AiUnlimitedHttpPort')]" + "aiUnlimitedAuthPort": { + "value": "[parameters('AiUnlimitedAuthPort')]" }, "aiUnlimitedGrpcPort": { "value": "[parameters('AiUnlimitedGrpcPort')]" @@ -430,6 +432,9 @@ "aiUnlimitedSchedulerHttpPort": { "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, + "aiUnlimitedUIHttpPort": { + "value": "[parameters('AiUnlimitedUIHttpPort')]" + }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" }, @@ -450,7 +455,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "3577307217619354540" + "templateHash": "17204210556751390284" } }, "parameters": { @@ -476,7 +481,7 @@ "type": "bool", "defaultValue": false }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -488,6 +493,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -553,10 +562,10 @@ ] }, { - "condition": "[not(equals(parameters('aiUnlimitedHttpPort'), 0))]", + "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-http-allow', variables('uniqueSecurityGroupName')))]", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", "properties": { "copy": [ { @@ -579,7 +588,7 @@ "access": "Allow", "description": "allow http to the workspace instance", "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedHttpPort'))]", + "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", "direction": "Inbound", "priority": 701, "protocol": "Tcp", @@ -703,6 +712,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow http to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", + "direction": "Inbound", + "priority": 705, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -734,8 +781,8 @@ "dnsPrefix": { "value": "[variables('dnsLabelPrefix')]" }, - "aiUnlimitedHttpPort": { - "value": "[parameters('AiUnlimitedHttpPort')]" + "aiUnlimitedAuthPort": { + "value": "[parameters('AiUnlimitedAuthPort')]" }, "aiUnlimitedGrpcPort": { "value": "[parameters('AiUnlimitedGrpcPort')]" @@ -743,6 +790,9 @@ "aiUnlimitedSchedulerHttpPort": { "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, + "aiUnlimitedUIHttpPort": { + "value": "[parameters('AiUnlimitedUIHttpPort')]" + }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" }, @@ -757,7 +807,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14601682444932366115" + "templateHash": "1616678944691212739" } }, "parameters": { @@ -770,7 +820,7 @@ "dnsPrefix": { "type": "string" }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -786,6 +836,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "tags": { "type": "object", "defaultValue": {} @@ -827,8 +881,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedHttpPort'), 'backendPort', parameters('aiUnlimitedHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedAuthPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", @@ -1061,7 +1115,7 @@ "value": "azureuser" }, "sshPublicKey": { - "value": "[parameters('PublicKey')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key'), '2022-09-01').outputs.PublicKey.value]" }, "dnsLabelPrefix": { "value": "[variables('dnsLabelPrefix')]" @@ -1079,7 +1133,7 @@ "value": "[parameters('OSVersion')]" }, "cloudInitData": { - "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedHttpPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerGrpcPort'), variables('AiUnlimitedSchedulerHttpPort')))))]" + "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" }, "usePersistentVolume": { "value": "[parameters('UsePersistentVolume')]" @@ -1462,7 +1516,140 @@ }, "dependsOn": [ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer')]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer')]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "Public-Key", + "resourceGroup": "[parameters('ResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "Name": { + "value": "[parameters('AiUnlimitedName')]" + }, + "Location": { + "value": "[deployment().location]" + }, + "VaultName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" + }, + "RoleID": { + "value": "[parameters('RoleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2861565763492996333" + } + }, + "parameters": { + "Location": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "VaultName": { + "type": "string" + }, + "RoleID": { + "type": "string" + }, + "Uuid": { + "type": "string", + "defaultValue": "[newGuid()]" + } + }, + "variables": { + "SecretName": "[format('{0}-PrivateKey', parameters('Name'))]", + "ScriptName": "[format('{0}-createKeys', parameters('Name'))]", + "IdentityName": "[format('{0}-scratch', parameters('Name'))]", + "RoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleID'))]", + "RoleDefinitionName": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), variables('RoleDefinitionId'), resourceGroup().id)]" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('IdentityName')]", + "location": "[parameters('Location')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[variables('RoleDefinitionName')]", + "properties": { + "roleDefinitionId": "[variables('RoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('ScriptName')]", + "location": "[parameters('Location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')))]": {} + } + }, + "kind": "AzureCLI", + "properties": { + "forceUpdateTag": "[parameters('Uuid')]", + "azCliVersion": "2.0.80", + "timeout": "PT30M", + "retentionInterval": "P1D", + "cleanupPreference": "OnSuccess", + "scriptContent": " #/bin/bash -e\n\n echo -e 'y' | ssh-keygen -f scratch\n\n privateKey=$(cat scratch)\n publicKey=$(cat 'scratch.pub')\n\n json=\"{\\\"keyinfo\\\":{\\\"privateKey\\\":\\\"$privateKey\\\",\\\"publicKey\\\":\\\"$publicKey\\\"}}\"\n\n echo \"$json\" > $AZ_SCRIPTS_OUTPUT_PATH\n " + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]", + "[resourceId('Microsoft.Authorization/roleAssignments', variables('RoleDefinitionName'))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('VaultName'), variables('SecretName'))]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.privateKey]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName'))]" + ] + } + ], + "outputs": { + "PublicKey": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.publicKey]" + }, + "Status": { + "type": "object", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').status]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" ] } ], @@ -1477,11 +1664,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", @@ -1499,10 +1686,6 @@ "type": "string", "value": "[format('http://{0}:{1}?token={2}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('JupyterHttpPort'), parameters('JupyterToken'))]" }, - "sshCommand": { - "type": "string", - "value": "[format('ssh azureuser@{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value)]" - }, "SecurityGroup": { "type": "string", "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json index d32b169..e4d5535 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "5181328523083770552" + "templateHash": "5233063193651485146" } }, "parameters": { @@ -22,12 +22,6 @@ "description": "Name for the Workspace service's virtual machine." } }, - "PublicKey": { - "type": "securestring", - "metadata": { - "description": "SSH public key value" - } - }, "OSVersion": { "type": "string", "defaultValue": "Ubuntu-2004", @@ -82,11 +76,11 @@ "description": "port to access the Jupyter Labs UI." } }, - "AiUnlimitedHttpPort": { + "AiUnlimitedAuthPort": { "type": "int", "defaultValue": 3000, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited auth service." } }, "AiUnlimitedGrpcPort": { @@ -96,6 +90,13 @@ "description": "port to access the AI Unlimited service api." } }, + "AiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "port to access the AI Unlimited service UI." + } + }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -116,13 +117,6 @@ "description": "GUID of the AI Unlimited Role" } }, - "AllowPublicSSH": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "allow access the AI Unlimited ssh port from the access cidr." - } - }, "UseKeyVault": { "type": "string", "defaultValue": "New", @@ -161,14 +155,21 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.2.23", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, + "AiUnlimitedUIVersion": { + "type": "string", + "defaultValue": "v0.0.5", + "metadata": { + "description": "Container Version of the AI Unlimited UI service" + } + }, "JupyterVersion": { "type": "string", - "defaultValue": "latest", + "defaultValue": "v0.0.43", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -188,11 +189,11 @@ } }, "variables": { - "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", - "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", - "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "AiUnlimitedSchedulerGrpcPort": 50051, + "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{3}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", + "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", + "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -201,7 +202,8 @@ "workspaceRepository": "ai-unlimited-workspaces", "jupyterRepository": "ai-unlimited-jupyter", "workspaceSchedulerRepository": "ai-unlimited-scheduler", - "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedHttpPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerGrpcPort'), variables('AiUnlimitedSchedulerHttpPort')))))]" + "workspaceUIRepository": "ai-unlimited-workspaces-ui", + "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" }, "resources": [ { @@ -418,10 +420,10 @@ "value": "[parameters('AccessCIDRs')]" }, "sshAccess": { - "value": "[parameters('AllowPublicSSH')]" + "value": false }, - "aiUnlimitedHttpPort": { - "value": "[parameters('AiUnlimitedHttpPort')]" + "aiUnlimitedAuthPort": { + "value": "[parameters('AiUnlimitedAuthPort')]" }, "aiUnlimitedGrpcPort": { "value": "[parameters('AiUnlimitedGrpcPort')]" @@ -429,6 +431,9 @@ "aiUnlimitedSchedulerHttpPort": { "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, + "aiUnlimitedUIHttpPort": { + "value": "[parameters('AiUnlimitedUIHttpPort')]" + }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" }, @@ -449,7 +454,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "3577307217619354540" + "templateHash": "17204210556751390284" } }, "parameters": { @@ -475,7 +480,7 @@ "type": "bool", "defaultValue": false }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -487,6 +492,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -552,10 +561,10 @@ ] }, { - "condition": "[not(equals(parameters('aiUnlimitedHttpPort'), 0))]", + "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-http-allow', variables('uniqueSecurityGroupName')))]", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", "properties": { "copy": [ { @@ -578,7 +587,7 @@ "access": "Allow", "description": "allow http to the workspace instance", "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedHttpPort'))]", + "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", "direction": "Inbound", "priority": 701, "protocol": "Tcp", @@ -702,6 +711,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow http to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", + "direction": "Inbound", + "priority": 705, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -734,7 +781,7 @@ "value": "azureuser" }, "sshPublicKey": { - "value": "[parameters('PublicKey')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key'), '2022-09-01').outputs.PublicKey.value]" }, "dnsLabelPrefix": { "value": "[variables('dnsLabelPrefix')]" @@ -1128,7 +1175,140 @@ } }, "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "Public-Key", + "resourceGroup": "[parameters('ResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "Name": { + "value": "[parameters('AiUnlimitedName')]" + }, + "Location": { + "value": "[deployment().location]" + }, + "VaultName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" + }, + "RoleID": { + "value": "[parameters('RoleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2861565763492996333" + } + }, + "parameters": { + "Location": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "VaultName": { + "type": "string" + }, + "RoleID": { + "type": "string" + }, + "Uuid": { + "type": "string", + "defaultValue": "[newGuid()]" + } + }, + "variables": { + "SecretName": "[format('{0}-PrivateKey', parameters('Name'))]", + "ScriptName": "[format('{0}-createKeys', parameters('Name'))]", + "IdentityName": "[format('{0}-scratch', parameters('Name'))]", + "RoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleID'))]", + "RoleDefinitionName": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), variables('RoleDefinitionId'), resourceGroup().id)]" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('IdentityName')]", + "location": "[parameters('Location')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[variables('RoleDefinitionName')]", + "properties": { + "roleDefinitionId": "[variables('RoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('ScriptName')]", + "location": "[parameters('Location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')))]": {} + } + }, + "kind": "AzureCLI", + "properties": { + "forceUpdateTag": "[parameters('Uuid')]", + "azCliVersion": "2.0.80", + "timeout": "PT30M", + "retentionInterval": "P1D", + "cleanupPreference": "OnSuccess", + "scriptContent": " #/bin/bash -e\n\n echo -e 'y' | ssh-keygen -f scratch\n\n privateKey=$(cat scratch)\n publicKey=$(cat 'scratch.pub')\n\n json=\"{\\\"keyinfo\\\":{\\\"privateKey\\\":\\\"$privateKey\\\",\\\"publicKey\\\":\\\"$publicKey\\\"}}\"\n\n echo \"$json\" > $AZ_SCRIPTS_OUTPUT_PATH\n " + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]", + "[resourceId('Microsoft.Authorization/roleAssignments', variables('RoleDefinitionName'))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('VaultName'), variables('SecretName'))]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.privateKey]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName'))]" + ] + } + ], + "outputs": { + "PublicKey": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.publicKey]" + }, + "Status": { + "type": "object", + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').status]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" ] } ], @@ -1143,11 +1323,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedHttpPort'))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", @@ -1165,10 +1345,6 @@ "type": "string", "value": "[format('http://{0}:{1}?token={2}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('JupyterHttpPort'), parameters('JupyterToken'))]" }, - "sshCommand": { - "type": "string", - "value": "[format('ssh azureuser@{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value)]" - }, "SecurityGroup": { "type": "string", "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" diff --git a/deployments/azure/templates/arm/init/resources.json b/deployments/azure/templates/arm/init/resources.json index 47cf3a6..a2c19a3 100644 --- a/deployments/azure/templates/arm/init/resources.json +++ b/deployments/azure/templates/arm/init/resources.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "3755223610480160492" + "version": "0.29.47.4906", + "templateHash": "11746473283873690149" } }, "parameters": { @@ -74,6 +74,7 @@ "Microsoft.KeyVault/vaults/read", "Microsoft.KeyVault/vaults/write", "Microsoft.KeyVault/vaults/delete", + "Microsoft.KeyVault/vaults/secrets/write", "Microsoft.KeyVault/vaults/accessPolicies/write", "Microsoft.KeyVault/locations/operationResults/read", "Microsoft.KeyVault/locations/deletedVaults/purge/action", @@ -163,8 +164,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "3893635077912970094" + "version": "0.29.47.4906", + "templateHash": "10026202347308594610" } }, "parameters": { @@ -240,4 +241,4 @@ "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('name')), 'Microsoft.Resources/deployments', 'networkDeployment'), '2022-09-01').outputs.subnetName.value]" } } -} +} \ No newline at end of file diff --git a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json index 0743441..0df867b 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "13407002185802552800" + "version": "0.29.47.4906", + "templateHash": "16727973129371051282" } }, "parameters": { @@ -151,7 +151,7 @@ }, "variables": { "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- sleep 60\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n", - "$fxv#1": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", + "$fxv#1": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", "dnsId": "[uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('JupyterName'))]", "dnsLabelPrefix": "[format('td{0}', variables('dnsId'))]", "nlbDnsLabelPrefix": "[format('td{0}-nlb', variables('dnsId'))]", @@ -202,8 +202,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "4929926268271391774" + "version": "0.29.47.4906", + "templateHash": "14464115164304997192" } }, "parameters": { @@ -241,6 +241,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -456,6 +460,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow http to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", + "direction": "Inbound", + "priority": 705, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -500,8 +542,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "9026566997103330654" + "version": "0.29.47.4906", + "templateHash": "16665436156133272643" } }, "parameters": { @@ -530,6 +572,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "tags": { "type": "object", "defaultValue": {} @@ -571,8 +617,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedHttpPort'), 'backendPort', parameters('aiUnlimitedHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedHTTP', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedHttpPort'), 'backendPort', parameters('aiUnlimitedHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}HTTPLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', format('{0}HTTPLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", @@ -628,8 +674,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "6759154498137298299" + "version": "0.29.47.4906", + "templateHash": "11278674213062453956" } }, "parameters": { @@ -710,8 +756,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "6759154498137298299" + "version": "0.29.47.4906", + "templateHash": "11278674213062453956" } }, "parameters": { @@ -853,8 +899,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "14119123377490335719" + "version": "0.29.47.4906", + "templateHash": "13207593080095673481" } }, "parameters": { @@ -1134,8 +1180,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "6759154498137298299" + "version": "0.29.47.4906", + "templateHash": "11278674213062453956" } }, "parameters": { @@ -1236,4 +1282,4 @@ "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" } } -} +} \ No newline at end of file diff --git a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json index 0120d25..2b98cef 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "8452004607038960062" + "version": "0.29.47.4906", + "templateHash": "11024397819019437861" } }, "parameters": { @@ -151,7 +151,7 @@ }, "variables": { "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- sleep 60\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n", - "$fxv#1": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker exec %n stop || true\nExecStartPre=-/usr/bin/docker rm %n || true\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", + "$fxv#1": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", "dnsLabelPrefix": "[format('td{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('JupyterName')))]", "registry": "teradata", "jupyterRepository": "ai-unlimited-jupyter", @@ -200,8 +200,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "4929926268271391774" + "version": "0.29.47.4906", + "templateHash": "14464115164304997192" } }, "parameters": { @@ -239,6 +239,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -454,6 +458,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow http to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", + "direction": "Inbound", + "priority": 705, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -528,8 +570,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "14119123377490335719" + "version": "0.29.47.4906", + "templateHash": "13207593080095673481" } }, "parameters": { @@ -809,8 +851,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "6759154498137298299" + "version": "0.29.47.4906", + "templateHash": "11278674213062453956" } }, "parameters": { @@ -910,4 +952,4 @@ "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" } } -} +} \ No newline at end of file diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep index 41026ec..805cc4f 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep @@ -6,10 +6,6 @@ param ResourceGroupName string = 'ai-unlimited-workspace' @description('Name for the AI Unlimited service\'s virtual machine.') param AiUnlimitedName string -@description('SSH public key value') -@secure() -param PublicKey string - @description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') @allowed([ 'Ubuntu-1804' @@ -33,8 +29,8 @@ param SecurityGroup string = 'AiUnlimitedSecurityGroup' @description('The CIDR ranges that can be used to communicate with the AI Unlimited service instance.') param AccessCIDRs array = ['0.0.0.0/0'] -@description('port to access the AI Unlimited service UI.') -param AiUnlimitedHttpPort int = 3000 +@description('port to access the AI Unlimited auth service.') +param AiUnlimitedAuthPort int = 3000 @description('port to access the AI Unlimited service api.') param AiUnlimitedGrpcPort int = 3282 @@ -45,6 +41,9 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service grpc api.') var AiUnlimitedSchedulerHttpPort = 50061 +@description('port to access the AI Unlimited service UI.') +param AiUnlimitedUIHttpPort int = 80 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -54,9 +53,6 @@ param detinationAppSecGroups array = [] @description('GUID of the AI Unlimited Role') param RoleDefinitionId string -@description('allow access the AI Unlimited ssh port from the access cidr.') -param AllowPublicSSH bool = false - @description('should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes.') @allowed(['New', 'None']) param UseKeyVault string = 'New' @@ -72,7 +68,10 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.2.23' +param AiUnlimitedVersion string = 'v0.3.0' + +@description('Container Version of the AI Unlimited UI service') +param AiUnlimitedUIVersion string = 'v0.0.5' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -89,6 +88,8 @@ var nlbDnsLabelPrefix = 'td${dnsId}-nlb' var registry = 'teradata' var workspaceRepository = 'ai-unlimited-workspaces' var workspaceSchedulerRepository = 'ai-unlimited-scheduler' +var workspaceUIRepository = 'ai-unlimited-workspaces-ui' + var cloudInitData = base64(format( loadTextContent('../../../scripts/ai-unlimited.cloudinit.yaml'), @@ -97,7 +98,7 @@ var cloudInitData = base64(format( registry, workspaceRepository, AiUnlimitedVersion, - AiUnlimitedHttpPort, + AiUnlimitedAuthPort, AiUnlimitedGrpcPort, subscription().subscriptionId, subscription().tenantId, @@ -110,6 +111,16 @@ var cloudInitData = base64(format( AiUnlimitedSchedulerVersion, // AiUnlimitedSchedulerGrpcPort, AiUnlimitedSchedulerHttpPort + )), + base64(format( + loadTextContent('../../../scripts/ai-unlimited-ui.service'), + registry, + workspaceUIRepository, + AiUnlimitedUIVersion, + AiUnlimitedUIHttpPort, + AiUnlimitedAuthPort, + AiUnlimitedGrpcPort, + '--network-alias ${nlb.outputs.PublicDns}' )) )) @@ -178,13 +189,14 @@ module firewall '../modules/firewall.bicep' = { location: rg.location name: SecurityGroup accessCidrs: AccessCIDRs - aiUnlimitedHttpPort: AiUnlimitedHttpPort + aiUnlimitedAuthPort: AiUnlimitedAuthPort aiUnlimitedGrpcPort: AiUnlimitedGrpcPort aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort + aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups - sshAccess: AllowPublicSSH + sshAccess: false tags: Tags } } @@ -196,10 +208,11 @@ module nlb '../modules/nlb.bicep' = { name: AiUnlimitedName dnsPrefix: nlbDnsLabelPrefix location: rg.location - aiUnlimitedHttpPort: AiUnlimitedHttpPort + aiUnlimitedAuthPort: AiUnlimitedAuthPort aiUnlimitedGrpcPort: AiUnlimitedGrpcPort aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort + aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort tags: Tags } } @@ -211,7 +224,7 @@ module aiUnlimited '../modules/instance.bicep' = { location: rg.location name: AiUnlimitedName adminUsername: 'azureuser' - sshPublicKey: PublicKey + sshPublicKey: PublicKey.outputs.PublicKey dnsLabelPrefix: dnsLabelPrefix vmSize: InstanceType subnetId: subnet.id @@ -228,6 +241,17 @@ module aiUnlimited '../modules/instance.bicep' = { } } +module PublicKey '../modules/public-key.bicep' = { + scope: rg + name: 'Public-Key' + params: { + Name: AiUnlimitedName + Location: deployment().location + VaultName: vault.outputs.name + RoleID: RoleDefinitionId + } +} + resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { scope: subscription() name: roleAssignmentName @@ -239,10 +263,9 @@ resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { output PublicIP string = nlb.outputs.PublicIp output PrivateIP string = aiUnlimited.outputs.PrivateIP -output AiUnlimitedPublicHttpAccess string = 'http://${nlb.outputs.PublicDns}:${AiUnlimitedHttpPort}' -output AiUnlimitedPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedHttpPort}' +output AiUnlimitedPublicHttpAccess string = concat('http://${nlb.outputs.PublicDns}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) +output AiUnlimitedPrivateHttpAccess string = concat('http://${aiUnlimited.outputs.PrivateIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) output AiUnlimitedPublicGrpcAccess string = 'http://${nlb.outputs.PublicDns}:${AiUnlimitedGrpcPort}' output AiUnlimitedPrivateGrpcAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedGrpcPort}' -output sshCommand string = 'ssh azureuser@${aiUnlimited.outputs.PrivateIP}' output KeyVaultName string = (UseKeyVault == 'New') ? vault.outputs.name : '' output NetworkSecurityGroupId string = firewall.outputs.Id diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam index 34d98d9..10bd86a 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam @@ -2,7 +2,6 @@ using './ai-unlimited-with-nlb.bicep' param ResourceGroupName = 'ai-unlimited-workspace' param AiUnlimitedName = '' -param PublicKey = '' param OSVersion = 'Ubuntu-2004' param InstanceType = 'Standard_D2s_v3' param Network = '' @@ -11,10 +10,11 @@ param SecurityGroup = 'AiUnlimitedSecurityGroup' param AccessCIDRs = [ '0.0.0.0/0' ] -param AiUnlimitedHttpPort = 3000 +param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerHttpPort = 50061 // param AiUnlimitedSchedulerGrpcPort = 50051 +param AiUnlimitedUIHttpPort = 80 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' @@ -22,6 +22,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.2.23' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.0.5' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep index eaf5f2d..486eeb6 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep @@ -6,10 +6,6 @@ param ResourceGroupName string = 'ai-unlimited-workspace' @description('Name for the AI Unlimited service\'s virtual machine.') param AiUnlimitedName string -@description('SSH public key value') -@secure() -param PublicKey string - @description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') @allowed([ 'Ubuntu-1804' @@ -33,8 +29,8 @@ param SecurityGroup string = 'AiUnlimitedSecurityGroup' @description('The CIDR ranges that can be used to communicate with the AI Unlimited service instance.') param AccessCIDRs array = ['0.0.0.0/0'] -@description('port to access the AI Unlimited service UI.') -param AiUnlimitedHttpPort int = 3000 +@description('port to access the AI Unlimited auth service.') +param AiUnlimitedAuthPort int = 3000 @description('port to access the AI Unlimited service api.') param AiUnlimitedGrpcPort int = 3282 @@ -45,6 +41,9 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service api.') var AiUnlimitedSchedulerHttpPort = 50061 +@description('port to access the AI Unlimited service UI.') +param AiUnlimitedUIHttpPort int = 80 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -54,9 +53,6 @@ param detinationAppSecGroups array = [] @description('GUID of the AI Unlimited Role') param RoleDefinitionId string -@description('allow access the AI Unlimited ssh port from the access cidr.') -param AllowPublicSSH bool = true - @description('should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes.') @allowed(['New', 'None']) param UseKeyVault string = 'New' @@ -72,7 +68,10 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.2.23' +param AiUnlimitedVersion string = 'v0.3.0' + +@description('Container Version of the AI Unlimited UI service') +param AiUnlimitedUIVersion string = 'v0.0.5' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -87,6 +86,7 @@ var dnsLabelPrefix = 'td${uniqueString(rg.id, deployment().name, AiUnlimitedName var registry = 'teradata' var workspaceRepository = 'ai-unlimited-workspaces' var workspaceSchedulerRepository = 'ai-unlimited-scheduler' +var workspaceUIRepository = 'ai-unlimited-workspaces-ui' var cloudInitData = base64(format( loadTextContent('../../../scripts/ai-unlimited.cloudinit.yaml'), @@ -95,7 +95,7 @@ var cloudInitData = base64(format( registry, workspaceRepository, AiUnlimitedVersion, - AiUnlimitedHttpPort, + AiUnlimitedAuthPort, AiUnlimitedGrpcPort, subscription().subscriptionId, subscription().tenantId, @@ -108,6 +108,16 @@ var cloudInitData = base64(format( AiUnlimitedSchedulerVersion, // AiUnlimitedSchedulerGrpcPort, AiUnlimitedSchedulerHttpPort + )), + base64(format( + loadTextContent('../../../scripts/ai-unlimited-ui.service'), + registry, + workspaceUIRepository, + AiUnlimitedUIVersion, + AiUnlimitedUIHttpPort, + AiUnlimitedAuthPort, + AiUnlimitedGrpcPort, + '--network-alias ai-unlimited' )) )) @@ -176,11 +186,12 @@ module firewall '../modules/firewall.bicep' = { location: rg.location name: SecurityGroup accessCidrs: AccessCIDRs - sshAccess: AllowPublicSSH - aiUnlimitedHttpPort: AiUnlimitedHttpPort + sshAccess: false + aiUnlimitedAuthPort: AiUnlimitedAuthPort aiUnlimitedGrpcPort: AiUnlimitedGrpcPort aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort + aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups tags: Tags @@ -194,7 +205,7 @@ module aiUnlimited '../modules/instance.bicep' = { location: rg.location name: AiUnlimitedName adminUsername: 'azureuser' - sshPublicKey: PublicKey + sshPublicKey: PublicKey.outputs.PublicKey dnsLabelPrefix: dnsLabelPrefix vmSize: InstanceType subnetId: subnet.id @@ -209,6 +220,17 @@ module aiUnlimited '../modules/instance.bicep' = { } } +module PublicKey '../modules/public-key.bicep' = { + scope: rg + name: 'Public-Key' + params: { + Name: AiUnlimitedName + Location: deployment().location + VaultName: vault.outputs.name + RoleID: RoleDefinitionId + } +} + resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { scope: subscription() name: roleAssignmentName @@ -220,10 +242,9 @@ resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { output PublicIP string = aiUnlimited.outputs.PublicIP output PrivateIP string = aiUnlimited.outputs.PrivateIP -output AiUnlimitedPublicHttpAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${AiUnlimitedHttpPort}' -output AiUnlimitedPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedHttpPort}' +output AiUnlimitedPublicHttpAccess string = concat('http://${aiUnlimited.outputs.PublicIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) +output AiUnlimitedPrivateHttpAccess string = concat('http://${aiUnlimited.outputs.PrivateIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) output AiUnlimitedPublicGrpcAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${AiUnlimitedGrpcPort}' output AiUnlimitedPrivateGrpcAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedGrpcPort}' -output sshCommand string = 'ssh azureuser@${aiUnlimited.outputs.PublicIP}' output KeyVaultName string = (UseKeyVault == 'New') ? vault.outputs.name : '' output NetworkSecurityGroupId string = firewall.outputs.Id diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam index f7eb31f..58482af 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam @@ -2,7 +2,6 @@ using './ai-unlimited-without-lb.bicep' param ResourceGroupName = 'ai-unlimited-workspace' param AiUnlimitedName = '' -param PublicKey = '' param OSVersion = 'Ubuntu-2004' param InstanceType = 'Standard_D2s_v3' param Network = '' @@ -11,18 +10,19 @@ param SecurityGroup = 'AiUnlimitedSecurityGroup' param AccessCIDRs = [ '0.0.0.0/0' ] -param AiUnlimitedHttpPort = 3000 +param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerGrpcPort = 50051 // param AiUnlimitedSchedulerHttpPort = 50061 +param AiUnlimitedUIHttpPort = 80 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' -param AllowPublicSSH = true param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.2.23' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.0.5' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep index b75bdc5..e988909 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep @@ -6,10 +6,6 @@ param ResourceGroupName string = 'ai-unlimited-workspace' @description('Name for the Workspace service\'s virtual machine.') param AiUnlimitedName string -@description('SSH public key value') -@secure() -param PublicKey string - @description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') @allowed([ 'Ubuntu-1804' @@ -36,18 +32,21 @@ param AccessCIDRs array = ['0.0.0.0/0'] @description('port to access the Jupyter Labs UI.') param JupyterHttpPort int = 8888 -@description('port to access the AI Unlimited service UI.') -param AiUnlimitedHttpPort int = 3000 +@description('port to access the AI Unlimited auth service.') +param AiUnlimitedAuthPort int = 3000 @description('port to access the AI Unlimited service api.') param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service grpc api.') -var AiUnlimitedSchedulerGrpcPort = 50051 +// var AiUnlimitedSchedulerGrpcPort = 50051 // @description('port to access the AI Unlimited scheduler service http api.') var AiUnlimitedSchedulerHttpPort = 50061 +@description('port to access the AI Unlimited service UI.') +param AiUnlimitedUIHttpPort int = 80 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -57,9 +56,6 @@ param detinationAppSecGroups array = [] @description('GUID of the AI Unlimited Role') param RoleDefinitionId string -@description('allow access the AI Unlimited ssh port from the access cidr.') -param AllowPublicSSH bool = false - @description('should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes.') @allowed(['New', 'None']) param UseKeyVault string = 'New' @@ -75,10 +71,13 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.2.23' +param AiUnlimitedVersion string = 'v0.3.0' + +@description('Container Version of the AI Unlimited UI service') +param AiUnlimitedUIVersion string = 'v0.0.5' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'latest' +param JupyterVersion string = 'v0.0.43' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -100,6 +99,7 @@ var registry = 'teradata' var workspaceRepository = 'ai-unlimited-workspaces' var jupyterRepository = 'ai-unlimited-jupyter' var workspaceSchedulerRepository = 'ai-unlimited-scheduler' +var workspaceUIRepository = 'ai-unlimited-workspaces-ui' var cloudInitData = base64(format( loadTextContent('../../../scripts/all-in-one.cloudinit.yaml'), @@ -108,7 +108,7 @@ var cloudInitData = base64(format( registry, workspaceRepository, AiUnlimitedVersion, - AiUnlimitedHttpPort, + AiUnlimitedAuthPort, AiUnlimitedGrpcPort, subscription().subscriptionId, subscription().tenantId, @@ -127,8 +127,18 @@ var cloudInitData = base64(format( registry, workspaceSchedulerRepository, AiUnlimitedSchedulerVersion, - AiUnlimitedSchedulerGrpcPort, + // AiUnlimitedSchedulerGrpcPort, AiUnlimitedSchedulerHttpPort + )), + base64(format( + loadTextContent('../../../scripts/ai-unlimited-ui.service'), + registry, + workspaceUIRepository, + AiUnlimitedUIVersion, + AiUnlimitedUIHttpPort, + AiUnlimitedAuthPort, + AiUnlimitedGrpcPort, + '--network-alias ${nlb.outputs.PublicDns}' )) )) @@ -197,11 +207,12 @@ module firewall '../modules/firewall.bicep' = { location: rg.location name: SecurityGroup accessCidrs: AccessCIDRs - sshAccess: AllowPublicSSH - aiUnlimitedHttpPort: AiUnlimitedHttpPort + sshAccess: false + aiUnlimitedAuthPort: AiUnlimitedAuthPort aiUnlimitedGrpcPort: AiUnlimitedGrpcPort aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort + aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort jupyterHttpPort: JupyterHttpPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups @@ -216,10 +227,11 @@ module nlb '../modules/nlb.bicep' = { name: AiUnlimitedName location: rg.location dnsPrefix: dnsLabelPrefix - aiUnlimitedHttpPort: AiUnlimitedHttpPort + aiUnlimitedAuthPort: AiUnlimitedAuthPort aiUnlimitedGrpcPort: AiUnlimitedGrpcPort aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort + aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort jupyterHttpPort: JupyterHttpPort tags: Tags } @@ -232,7 +244,7 @@ module aiUnlimited '../modules/instance.bicep' = { location: rg.location name: AiUnlimitedName adminUsername: 'azureuser' - sshPublicKey: PublicKey + sshPublicKey: PublicKey.outputs.PublicKey dnsLabelPrefix: dnsLabelPrefix vmSize: InstanceType subnetId: subnet.id @@ -249,6 +261,17 @@ module aiUnlimited '../modules/instance.bicep' = { } } +module PublicKey '../modules/public-key.bicep' = { + scope: rg + name: 'Public-Key' + params: { + Name: AiUnlimitedName + Location: deployment().location + VaultName: vault.outputs.name + RoleID: RoleDefinitionId + } +} + resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { scope: subscription() name: roleAssignmentName @@ -260,11 +283,10 @@ resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { output PublicIP string = nlb.outputs.PublicIp output PrivateIP string = aiUnlimited.outputs.PrivateIP -output AiUnlimitedPublicHttpAccess string = 'http://${nlb.outputs.PublicDns}:${AiUnlimitedHttpPort}' -output AiUnlimitedPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedHttpPort}' +output AiUnlimitedPublicHttpAccess string = concat('http://${nlb.outputs.PublicDns}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) +output AiUnlimitedPrivateHttpAccess string = concat('http://${aiUnlimited.outputs.PrivateIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) output AiUnlimitedPublicGrpcAccess string = 'http://${nlb.outputs.PublicDns}:${AiUnlimitedGrpcPort}' output AiUnlimitedPrivateGrpcAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedGrpcPort}' output JupyterLabPublicHttpAccess string = 'http://${nlb.outputs.PublicDns}:${JupyterHttpPort}?token=${JupyterToken}' output JupyterLabPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${JupyterHttpPort}?token=${JupyterToken}' -output sshCommand string = 'ssh azureuser@${aiUnlimited.outputs.PrivateIP}' output SecurityGroup string = firewall.outputs.Id diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam index 1569ea1..2565d15 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam @@ -2,7 +2,6 @@ using './all-in-one-with-nlb.bicep' param ResourceGroupName = 'ai-unlimited-workspace' param AiUnlimitedName = '' -param PublicKey = '' param OSVersion = 'Ubuntu-2004' param InstanceType = 'Standard_D2s_v3' param Network = '' @@ -12,20 +11,21 @@ param AccessCIDRs = [ '0.0.0.0/0' ] param JupyterHttpPort = 8888 -param AiUnlimitedHttpPort = 3000 +param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerGrpcPort = 50051 // param AiUnlimitedSchedulerHttpPort = 50061 +param AiUnlimitedUIHttpPort = 80 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' -param AllowPublicSSH = true param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.2.23' -param JupyterVersion = 'latest' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.0.5' +param JupyterVersion = 'v0.0.43' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep index 745ddbe..d99810d 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep @@ -6,10 +6,6 @@ param ResourceGroupName string = 'ai-unlimited-workspace' @description('Name for the Workspace service\'s virtual machine.') param AiUnlimitedName string -@description('SSH public key value') -@secure() -param PublicKey string - @description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') @allowed([ 'Ubuntu-1804' @@ -36,18 +32,21 @@ param AccessCIDRs array = ['0.0.0.0/0'] @description('port to access the Jupyter Labs UI.') param JupyterHttpPort int = 8888 -@description('port to access the AI Unlimited service UI.') -param AiUnlimitedHttpPort int = 3000 +@description('port to access the AI Unlimited auth service.') +param AiUnlimitedAuthPort int = 3000 @description('port to access the AI Unlimited service api.') param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service grpc api.') -var AiUnlimitedSchedulerGrpcPort = 50051 +// var AiUnlimitedSchedulerGrpcPort = 50051 // @description('port to access the AI Unlimited scheduler service http api.') var AiUnlimitedSchedulerHttpPort = 50061 +@description('port to access the AI Unlimited service UI.') +param AiUnlimitedUIHttpPort int = 80 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -57,9 +56,6 @@ param detinationAppSecGroups array = [] @description('GUID of the AI Unlimited Role') param RoleDefinitionId string -@description('allow access the AI Unlimited ssh port from the access cidr.') -param AllowPublicSSH bool = true - @description('should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes.') @allowed(['New', 'None']) param UseKeyVault string = 'New' @@ -75,10 +71,13 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.2.23' +param AiUnlimitedVersion string = 'v0.3.0' + +@description('Container Version of the AI Unlimited UI service') +param AiUnlimitedUIVersion string = 'v0.0.5' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'latest' +param JupyterVersion string = 'v0.0.43' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -98,6 +97,7 @@ var registry = 'teradata' var workspaceRepository = 'ai-unlimited-workspaces' var jupyterRepository = 'ai-unlimited-jupyter' var workspaceSchedulerRepository = 'ai-unlimited-scheduler' +var workspaceUIRepository = 'ai-unlimited-workspaces-ui' var cloudInitData = base64(format( loadTextContent('../../../scripts/all-in-one.cloudinit.yaml'), @@ -106,7 +106,7 @@ var cloudInitData = base64(format( registry, workspaceRepository, AiUnlimitedVersion, - AiUnlimitedHttpPort, + AiUnlimitedAuthPort, AiUnlimitedGrpcPort, subscription().subscriptionId, subscription().tenantId, @@ -125,8 +125,18 @@ var cloudInitData = base64(format( registry, workspaceSchedulerRepository, AiUnlimitedSchedulerVersion, - AiUnlimitedSchedulerGrpcPort, + // AiUnlimitedSchedulerGrpcPort, AiUnlimitedSchedulerHttpPort + )), + base64(format( + loadTextContent('../../../scripts/ai-unlimited-ui.service'), + registry, + workspaceUIRepository, + AiUnlimitedUIVersion, + AiUnlimitedUIHttpPort, + AiUnlimitedAuthPort, + AiUnlimitedGrpcPort, + '--network-alias ai-unlimited' )) )) @@ -195,11 +205,12 @@ module firewall '../modules/firewall.bicep' = { location: rg.location name: SecurityGroup accessCidrs: AccessCIDRs - sshAccess: AllowPublicSSH - aiUnlimitedHttpPort: AiUnlimitedHttpPort + sshAccess: false + aiUnlimitedAuthPort: AiUnlimitedAuthPort aiUnlimitedGrpcPort: AiUnlimitedGrpcPort aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort + aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort jupyterHttpPort: JupyterHttpPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups @@ -214,7 +225,7 @@ module aiUnlimited '../modules/instance.bicep' = { location: rg.location name: AiUnlimitedName adminUsername: 'azureuser' - sshPublicKey: PublicKey + sshPublicKey: PublicKey.outputs.PublicKey dnsLabelPrefix: dnsLabelPrefix vmSize: InstanceType subnetId: subnet.id @@ -229,6 +240,17 @@ module aiUnlimited '../modules/instance.bicep' = { } } +module PublicKey '../modules/public-key.bicep' = { + scope: rg + name: 'Public-Key' + params: { + Name: AiUnlimitedName + Location: deployment().location + VaultName: vault.outputs.name + RoleID: RoleDefinitionId + } +} + resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { scope: subscription() name: roleAssignmentName @@ -240,11 +262,10 @@ resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { output PublicIP string = aiUnlimited.outputs.PublicIP output PrivateIP string = aiUnlimited.outputs.PrivateIP -output AiUnlimitedPublicHttpAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${AiUnlimitedHttpPort}' -output AiUnlimitedPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedHttpPort}' +output AiUnlimitedPublicHttpAccess string = concat('http://${aiUnlimited.outputs.PublicIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) +output AiUnlimitedPrivateHttpAccess string = concat('http://${aiUnlimited.outputs.PrivateIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) output AiUnlimitedPublicGrpcAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${AiUnlimitedGrpcPort}' output AiUnlimitedPrivateGrpcAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedGrpcPort}' output JupyterLabPublicHttpAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${JupyterHttpPort}?token=${JupyterToken}' output JupyterLabPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${JupyterHttpPort}?token=${JupyterToken}' -output sshCommand string = 'ssh azureuser@${aiUnlimited.outputs.PublicIP}' output SecurityGroup string = firewall.outputs.Id diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam index 1524f91..3474280 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam @@ -2,7 +2,6 @@ using './all-in-one-without-lb.bicep' param ResourceGroupName = 'ai-unlimited-workspace' param AiUnlimitedName = '' -param PublicKey = '' param OSVersion = 'Ubuntu-2004' param InstanceType = 'Standard_D2s_v3' param Network = '' @@ -12,20 +11,21 @@ param AccessCIDRs = [ '0.0.0.0/0' ] param JupyterHttpPort = 8888 -param AiUnlimitedHttpPort = 3000 +param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerGrpcPort = 50051 // param AiUnlimitedSchedulerHttpPort = 50061 +param AiUnlimitedUIHttpPort = 80 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' -param AllowPublicSSH = true param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.2.23' -param JupyterVersion = 'latest' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.0.5' +param JupyterVersion = 'v0.0.43' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} diff --git a/deployments/azure/templates/bicep/modules/firewall.bicep b/deployments/azure/templates/bicep/modules/firewall.bicep index 54fe4da..66ea040 100644 --- a/deployments/azure/templates/bicep/modules/firewall.bicep +++ b/deployments/azure/templates/bicep/modules/firewall.bicep @@ -5,10 +5,11 @@ param accessCidrs array = [] param sourceAppSecGroups array = [] param detinationAppSecGroups array = [] param sshAccess bool = false -param aiUnlimitedHttpPort int = 0 +param aiUnlimitedAuthPort int = 0 param aiUnlimitedGrpcPort int = 0 param aiUnlimitedSchedulerHttpPort int = 0 // param aiUnlimitedSchedulerGrpcPort int = 0 +param aiUnlimitedUIHttpPort int = 0 param jupyterHttpPort int = 0 param tags object = {} param uuid string = newGuid() @@ -73,8 +74,8 @@ resource sshAllow 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04 // } // } -resource AiUnlimitedHTTP 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04-01' = if (aiUnlimitedHttpPort != 0) { - name: '${uniqueSecurityGroupName}-workspace-http-allow' +resource AiUnlimitedAuth 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04-01' = if (aiUnlimitedAuthPort != 0) { + name: '${uniqueSecurityGroupName}-workspace-auth-allow' parent: networkSecurityGroup properties: { @@ -87,7 +88,7 @@ resource AiUnlimitedHTTP 'Microsoft.Network/networkSecurityGroups/securityRules@ location: location } ] - destinationPortRange: string(aiUnlimitedHttpPort) // destinationPortRanges: [] + destinationPortRange: string(aiUnlimitedAuthPort) // destinationPortRanges: [] direction: 'Inbound' priority: 701 protocol: 'Tcp' @@ -189,6 +190,33 @@ resource AiUnlimitedSchedulerHTTP 'Microsoft.Network/networkSecurityGroups/secur } } +resource AiUnlimitedUIHTTP 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04-01' = if (aiUnlimitedUIHttpPort != 0) { + name: '${name}-workspace-ui-http-allow' + parent: networkSecurityGroup + + properties: { + access: 'Allow' + description: 'allow http to the workspace ui instance' + destinationAddressPrefix: '*' // destinationAddressPrefixes: [] + destinationApplicationSecurityGroups: [for secgroup in detinationAppSecGroups: { + id: secgroup + location: location + } + ] + destinationPortRange: string(aiUnlimitedUIHttpPort) // destinationPortRanges: [] + direction: 'Inbound' + priority: 705 + protocol: 'Tcp' + sourceAddressPrefixes: accessCidrs // sourceAddressPrefix: 'string' + sourceApplicationSecurityGroups: [for secgroup in sourceAppSecGroups: { + id: secgroup + location: location + } + ] + sourcePortRange: '*' // sourcePortRanges: [] + } +} + // resource AiUnlimitedSchedulerGRPC 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04-01' = if (aiUnlimitedSchedulerGrpcPort != 0) { // name: '${uniqueSecurityGroupName}-scheduler-grpc-allow' // parent: networkSecurityGroup diff --git a/deployments/azure/templates/bicep/modules/nlb.bicep b/deployments/azure/templates/bicep/modules/nlb.bicep index aaf7f9b..c8bfc70 100644 --- a/deployments/azure/templates/bicep/modules/nlb.bicep +++ b/deployments/azure/templates/bicep/modules/nlb.bicep @@ -1,11 +1,12 @@ param name string param location string param dnsPrefix string -param aiUnlimitedHttpPort int = 0 +param aiUnlimitedAuthPort int = 0 param aiUnlimitedGrpcPort int = 0 param aiUnlimitedSchedulerHttpPort int = 0 // param aiUnlimitedSchedulerGrpcPort int = 0 param jupyterHttpPort int = 0 +param aiUnlimitedUIHttpPort int = 0 param tags object = {} module lbPublicIPAddress 'public-ip.bicep' = { @@ -62,10 +63,10 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { } ] loadBalancingRules: flatten([ - aiUnlimitedHttpPort != 0 + aiUnlimitedAuthPort != 0 ? [ { - name: 'AiUnlimitedUI' + name: 'AiUnlimitedAuth' properties: { frontendIPConfiguration: { id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', name, '${name}Inbound') @@ -77,8 +78,8 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { '${name}OutboundBackendPool' ) } - frontendPort: aiUnlimitedHttpPort - backendPort: aiUnlimitedHttpPort + frontendPort: aiUnlimitedAuthPort + backendPort: aiUnlimitedAuthPort enableFloatingIP: false idleTimeoutInMinutes: 15 protocol: 'Tcp' @@ -86,7 +87,7 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { loadDistribution: 'Default' disableOutboundSnat: true probe: { - id: resourceId('Microsoft.Network/loadBalancers/probes', name, '${name}UILbProbe') + id: resourceId('Microsoft.Network/loadBalancers/probes', name, '${name}AuthLbProbe') } } } @@ -212,15 +213,46 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { // } // ] // : [] + aiUnlimitedUIHttpPort != 0 + ? [ + { + name: 'AiUnlimitedUI' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', name, '${name}Inbound') + } + backendAddressPool: { + id: resourceId( + 'Microsoft.Network/loadBalancers/backendAddressPools', + name, + '${name}OutboundBackendPool' + ) + } + frontendPort: aiUnlimitedUIHttpPort + backendPort: aiUnlimitedUIHttpPort + enableFloatingIP: false + idleTimeoutInMinutes: 15 + protocol: 'Tcp' + enableTcpReset: true + loadDistribution: 'Default' + disableOutboundSnat: true + probe: { + id: resourceId('Microsoft.Network/loadBalancers/probes', name, '${name}UILbProbe') + } + } + } + ] + : [] ]) probes: flatten([ - aiUnlimitedHttpPort != 0 + aiUnlimitedAuthPort != 0 ? [ { - name: '${name}UILbProbe' + name: '${name}AuthLbProbe' properties: { - protocol: 'Tcp' - port: aiUnlimitedHttpPort + protocol: 'Http' + port: aiUnlimitedAuthPort + requestPath: '/healthcheck' intervalInSeconds: 5 numberOfProbes: 2 } @@ -281,6 +313,20 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { // } // ] // : [] + aiUnlimitedUIHttpPort != 0 + ? [ + { + name: '${name}UILbProbe' + properties: { + protocol: 'Http' + port: aiUnlimitedUIHttpPort + requestPath: '/' + intervalInSeconds: 5 + numberOfProbes: 2 + } + } + ] + : [] ]) outboundRules: [ { diff --git a/deployments/azure/templates/bicep/modules/public-key.bicep b/deployments/azure/templates/bicep/modules/public-key.bicep new file mode 100644 index 0000000..9f4bd1c --- /dev/null +++ b/deployments/azure/templates/bicep/modules/public-key.bicep @@ -0,0 +1,70 @@ +param Location string +param Name string +param VaultName string +param RoleID string +param Uuid string = newGuid() + +var SecretName = format('{0}-PrivateKey', Name) +var ScriptName = format('{0}-createKeys', Name) +var IdentityName = format('{0}-scratch', Name) +var RoleDefinitionId = resourceId('Microsoft.Authorization/roleDefinitions', RoleID) +var RoleDefinitionName = guid(Identity.id, RoleDefinitionId, resourceGroup().id) + +resource Identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: IdentityName + location: Location +} + +resource RoleDefinition 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: RoleDefinitionName + properties: { + roleDefinitionId: RoleDefinitionId + principalId: Identity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource Script 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: ScriptName + location: Location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${Identity.id}': {} + } + } + kind: 'AzureCLI' + properties: { + forceUpdateTag: Uuid + azCliVersion: '2.0.80' + timeout: 'PT30M' + retentionInterval: 'P1D' + cleanupPreference: 'OnSuccess' + scriptContent: ''' + #/bin/bash -e + + echo -e 'y' | ssh-keygen -f scratch + + privateKey=$(cat scratch) + publicKey=$(cat 'scratch.pub') + + json="{\"keyinfo\":{\"privateKey\":\"$privateKey\",\"publicKey\":\"$publicKey\"}}" + + echo "$json" > $AZ_SCRIPTS_OUTPUT_PATH + ''' + // primaryScriptUri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.resources/deployment-script-ssh-key-gen/new-key.sh' + } + dependsOn: [ + RoleDefinition + ] +} + +resource SshKeyecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { + name: '${VaultName}/${SecretName}' + properties: { + value: Script.properties.outputs.keyinfo.privateKey + } +} + +output PublicKey string = Script.properties.outputs.keyinfo.publicKey +output Status object = Script.properties.status diff --git a/deployments/azure/templates/init/resources.bicep b/deployments/azure/templates/init/resources.bicep index ae353db..30aeb66 100644 --- a/deployments/azure/templates/init/resources.bicep +++ b/deployments/azure/templates/init/resources.bicep @@ -53,6 +53,7 @@ resource roleDef 'Microsoft.Authorization/roleDefinitions@2022-04-01' = { 'Microsoft.KeyVault/vaults/read' 'Microsoft.KeyVault/vaults/write' 'Microsoft.KeyVault/vaults/delete' + 'Microsoft.KeyVault/vaults/secrets/write' 'Microsoft.KeyVault/vaults/accessPolicies/write' 'Microsoft.KeyVault/locations/operationResults/read' 'Microsoft.KeyVault/locations/deletedVaults/purge/action' From ece241f69ce9a2bc5626794b80e316da20588d51 Mon Sep 17 00:00:00 2001 From: hc186011 Date: Wed, 30 Oct 2024 12:57:00 -0700 Subject: [PATCH 09/28] Update changes --- deployments/docker/ai-unlimited.yaml | 2 +- deployments/docker/jupyter.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index 9f444d8..c37b8c2 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -28,7 +28,7 @@ services: replicas: 1 platform: linux/amd64 container_name: workspaces-ui - image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_IMAGE_TAG:-v0.0.1} + image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_UI_IMAGE_TAG:-v0.0.6} ports: - "443:443/tcp" - "${TD_VCD_UI_PORT:-80}:80/tcp" diff --git a/deployments/docker/jupyter.yaml b/deployments/docker/jupyter.yaml index e09d939..efa17c4 100644 --- a/deployments/docker/jupyter.yaml +++ b/deployments/docker/jupyter.yaml @@ -6,7 +6,7 @@ services: replicas: 1 platform: linux/amd64 container_name: jupyter - image: ${JUPYTER_IMAGE_NAME:-teradata/ai-unlimited-jupyter}:${JUPYTER_IMAGE_TAG:-latest} + image: ${JUPYTER_IMAGE_NAME:-teradata/ai-unlimited-jupyter}:${JUPYTER_IMAGE_TAG:-v0.0.49} environment: accept_license: "Y" ports: From 6c533412c2428298003f7fa234ad9a300fece612 Mon Sep 17 00:00:00 2001 From: Aopanis Date: Wed, 30 Oct 2024 14:30:13 -0700 Subject: [PATCH 10/28] New versions. (#52) * New versions. * Rain fmt. --------- Co-authored-by: Anton Panis --- .../ai-unlimited/ai-unlimited-with-nlb.yaml | 13 ++++++---- .../ai-unlimited/ai-unlimited-without-lb.yaml | 25 ++++++++++--------- .../all-in-one/all-in-one-with-nlb.yaml | 15 ++++++----- .../all-in-one/all-in-one-without-lb.yaml | 25 +++++++++++-------- .../templates/jupyter/jupyter-with-nlb.yaml | 3 +-- .../templates/jupyter/jupyter-without-lb.yaml | 3 +-- .../ai-unlimited/ai-unlimited-with-nlb.json | 4 +-- .../ai-unlimited/ai-unlimited-without-lb.json | 4 +-- .../arm/all-in-one/all-in-one-with-nlb.json | 6 ++--- .../arm/all-in-one/all-in-one-without-lb.json | 6 ++--- .../arm/jupyter/jupyter-with-nlb.json | 22 ++++++++-------- .../arm/jupyter/jupyter-without-lb.json | 14 +++++------ .../ai-unlimited/ai-unlimited-with-nlb.bicep | 2 +- .../ai-unlimited-with-nlb.bicepparam | 2 +- .../ai-unlimited-without-lb.bicep | 2 +- .../ai-unlimited-without-lb.bicepparam | 2 +- .../all-in-one/all-in-one-with-nlb.bicep | 4 +-- .../all-in-one/all-in-one-with-nlb.bicepparam | 4 +-- .../all-in-one/all-in-one-without-lb.bicep | 4 +-- .../all-in-one-without-lb.bicepparam | 4 +-- .../bicep/jupyter/jupyter-with-nlb.bicep | 2 +- .../bicep/jupyter/jupyter-with-nlb.bicepparam | 2 +- .../bicep/jupyter/jupyter-without-lb.bicep | 2 +- .../jupyter/jupyter-without-lb.bicepparam | 2 +- 24 files changed, 90 insertions(+), 82 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index b36648d..67d74a2 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -151,7 +151,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.5 + Default: v0.0.6 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -379,7 +379,10 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 Resources: AiUnlimitedVolume: @@ -509,7 +512,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -1301,8 +1304,8 @@ Outputs: Description: Loadbalancer access endpoint for AI Unlimited UI Access Value: !If - PortIsNotEighty - - !Sub "http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck" - - !Sub "http://${ LoadBalancer.DNSName }" + - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck + - !Sub http://${ LoadBalancer.DNSName } AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 73ebed5..39192d8 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -141,7 +141,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.5 + Default: v0.0.6 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -364,8 +364,7 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEightyAndHasPublicIp: - !And + PortIsNotEightyAndHasPublicIp: !And - !Not - !Equals - !Ref Private @@ -375,7 +374,10 @@ Conditions: - !Ref AiUnlimitedUiPort - 80 - PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 Resources: AiUnlimitedVolume: @@ -490,7 +492,6 @@ Resources: docker: enabled: "true" ensureRunning: "true" - configure_ai_unlimited_ui_service: files: /usr/lib/systemd/system/ai-unlimited-ui.service: @@ -506,7 +507,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -534,7 +535,6 @@ Resources: ai-unlimited-ui: enabled: "true" ensureRunning: "true" - configure_ai_unlimited_service: files: /usr/lib/systemd/system/ai-unlimited.service: @@ -997,17 +997,18 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !If [ PortIsNotEightyAndHasPublicIp, - !Sub "http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck", - !Sub "http://${AiUnlimitedServer.PublicDnsName}" ] + Value: !If + - PortIsNotEightyAndHasPublicIp + - !Sub http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck + - !Sub http://${AiUnlimitedServer.PublicDnsName} Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access Value: !If - PortIsNotEighty - - !Sub "http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck" - - !Sub "http://${AiUnlimitedServer.PrivateDnsName}" + - !Sub http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck + - !Sub http://${AiUnlimitedServer.PrivateDnsName} AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 283c19b..4f38178 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -165,7 +165,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.5 + Default: v0.0.6 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -183,7 +183,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: latest + Default: v0.0.49 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -395,7 +395,10 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 Resources: AiUnlimitedVolume: @@ -527,7 +530,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -1454,8 +1457,8 @@ Outputs: Description: Loadbalancer access endpoint for AI Unlimited UI Access Value: !If - PortIsNotEighty - - !Sub "http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck" - - !Sub "http://${ LoadBalancer.DNSName }" + - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck + - !Sub http://${ LoadBalancer.DNSName } AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index 7a2df95..111c4d4 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -155,7 +155,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.5 + Default: v0.0.6 JupyterHttpPort: Description: port to access the Jupyter UI. @@ -168,7 +168,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: latest + Default: v0.0.49 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -380,8 +380,7 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEightyAndHasPublicIp: - !And + PortIsNotEightyAndHasPublicIp: !And - !Not - !Equals - !Ref Private @@ -391,7 +390,10 @@ Conditions: - !Ref AiUnlimitedUiPort - 80 - PortIsNotEighty: !Not [!Equals [!Ref AiUnlimitedUiPort, 80]] + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 Resources: AiUnlimitedVolume: @@ -523,7 +525,7 @@ Resources: TimeoutStartSec=0 Restart=always RestartSec=2 - + ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -1077,17 +1079,18 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !If [ PortIsNotEightyAndHasPublicIp, - !Sub "http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck", - !Sub "http://${AiUnlimitedServer.PublicDnsName}" ] + Value: !If + - PortIsNotEightyAndHasPublicIp + - !Sub http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck + - !Sub http://${AiUnlimitedServer.PublicDnsName} Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access Value: !If - PortIsNotEighty - - !Sub "http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck" - - !Sub "http://${AiUnlimitedServer.PrivateDnsName}" + - !Sub http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck + - !Sub http://${AiUnlimitedServer.PrivateDnsName} AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access diff --git a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml index dd169b4..e2e7645 100644 --- a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml @@ -120,7 +120,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: latest + Default: v0.0.49 RootVolumeSize: Description: size of the root disk to the jupyter server. @@ -753,7 +753,6 @@ Outputs: Description: AI Unlimited Security Group Value: !GetAtt JupyterSecurityGroup.GroupId - LoadBalancerSecurityGroups: Description: AI Unlimited Load Balancer Security Group Value: !Join diff --git a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml index cfd9fef..7248ecd 100644 --- a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml @@ -105,7 +105,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: latest + Default: v0.0.49 RootVolumeSize: Description: size of the root disk to the jupyter server. @@ -671,7 +671,6 @@ Outputs: Description: AI Unlimited Security Group Value: !GetAtt JupyterSecurityGroup.GroupId - PublicSSHConeection: Description: Jupyter ssh connnection string Value: !Sub ssh ec2-user@${ JupyterServer.PublicIp } diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json index 5da992d..18270bb 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "11962177184326515391" + "templateHash": "2835298721030345346" } }, "parameters": { @@ -155,7 +155,7 @@ }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.5", + "defaultValue": "v0.0.6", "metadata": { "description": "Container Version of the AI Unlimited UI service" } diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json index a37a9d5..f197d00 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10042357043303845085" + "templateHash": "9964344374735929406" } }, "parameters": { @@ -155,7 +155,7 @@ }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.5", + "defaultValue": "v0.0.6", "metadata": { "description": "Container Version of the AI Unlimited UI service" } diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json index d0b204d..d4f6ee6 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1860230839229358162" + "templateHash": "8915778081204530415" } }, "parameters": { @@ -162,14 +162,14 @@ }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.5", + "defaultValue": "v0.0.6", "metadata": { "description": "Container Version of the AI Unlimited UI service" } }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.43", + "defaultValue": "v0.0.49", "metadata": { "description": "Container Version of the Jupyter Labs service" } diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json index e4d5535..a431f44 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "5233063193651485146" + "templateHash": "10676142330204484121" } }, "parameters": { @@ -162,14 +162,14 @@ }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.5", + "defaultValue": "v0.0.6", "metadata": { "description": "Container Version of the AI Unlimited UI service" } }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.43", + "defaultValue": "v0.0.49", "metadata": { "description": "Container Version of the Jupyter Labs service" } diff --git a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json index 0df867b..7128ae9 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "16727973129371051282" + "templateHash": "12586694840490067753" } }, "parameters": { @@ -130,7 +130,7 @@ }, "JupyterVersion": { "type": "string", - "defaultValue": "latest", + "defaultValue": "v0.0.49", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -203,7 +203,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14464115164304997192" + "templateHash": "17204210556751390284" } }, "parameters": { @@ -229,7 +229,7 @@ "type": "bool", "defaultValue": false }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -310,10 +310,10 @@ ] }, { - "condition": "[not(equals(parameters('aiUnlimitedHttpPort'), 0))]", + "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-http-allow', variables('uniqueSecurityGroupName')))]", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", "properties": { "copy": [ { @@ -336,7 +336,7 @@ "access": "Allow", "description": "allow http to the workspace instance", "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedHttpPort'))]", + "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", "direction": "Inbound", "priority": 701, "protocol": "Tcp", @@ -543,7 +543,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "16665436156133272643" + "templateHash": "1616678944691212739" } }, "parameters": { @@ -556,7 +556,7 @@ "dnsPrefix": { "type": "string" }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -617,8 +617,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedHTTP', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedHttpPort'), 'backendPort', parameters('aiUnlimitedHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}HTTPLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedHttpPort'), 0)), createArray(createObject('name', format('{0}HTTPLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedAuthPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", diff --git a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json index 2b98cef..3bae8d0 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "11024397819019437861" + "templateHash": "17407221377602669028" } }, "parameters": { @@ -130,7 +130,7 @@ }, "JupyterVersion": { "type": "string", - "defaultValue": "latest", + "defaultValue": "v0.0.49", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -201,7 +201,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14464115164304997192" + "templateHash": "17204210556751390284" } }, "parameters": { @@ -227,7 +227,7 @@ "type": "bool", "defaultValue": false }, - "aiUnlimitedHttpPort": { + "aiUnlimitedAuthPort": { "type": "int", "defaultValue": 0 }, @@ -308,10 +308,10 @@ ] }, { - "condition": "[not(equals(parameters('aiUnlimitedHttpPort'), 0))]", + "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", "type": "Microsoft.Network/networkSecurityGroups/securityRules", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-http-allow', variables('uniqueSecurityGroupName')))]", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", "properties": { "copy": [ { @@ -334,7 +334,7 @@ "access": "Allow", "description": "allow http to the workspace instance", "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedHttpPort'))]", + "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", "direction": "Inbound", "priority": 701, "protocol": "Tcp", diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep index 805cc4f..a033556 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep @@ -71,7 +71,7 @@ param ExistingPersistentVolume string = 'NONE' param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.5' +param AiUnlimitedUIVersion string = 'v0.0.6' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam index 10bd86a..eecbc4a 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam @@ -23,6 +23,6 @@ param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.5' +param AiUnlimitedUIVersion = 'v0.0.6' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep index 486eeb6..84e6353 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep @@ -71,7 +71,7 @@ param ExistingPersistentVolume string = 'NONE' param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.5' +param AiUnlimitedUIVersion string = 'v0.0.6' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam index 58482af..f391976 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam @@ -23,6 +23,6 @@ param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.5' +param AiUnlimitedUIVersion = 'v0.0.6' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep index e988909..edf816d 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep @@ -74,10 +74,10 @@ param ExistingPersistentVolume string = 'NONE' param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.5' +param AiUnlimitedUIVersion string = 'v0.0.6' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.43' +param JupyterVersion string = 'v0.0.49' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam index 2565d15..b922542 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam @@ -24,8 +24,8 @@ param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.5' -param JupyterVersion = 'v0.0.43' +param AiUnlimitedUIVersion = 'v0.0.6' +param JupyterVersion = 'v0.0.49' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep index d99810d..db7799c 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep @@ -74,10 +74,10 @@ param ExistingPersistentVolume string = 'NONE' param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.5' +param AiUnlimitedUIVersion string = 'v0.0.6' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.43' +param JupyterVersion string = 'v0.0.49' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam index 3474280..5f69542 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam @@ -24,8 +24,8 @@ param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.5' -param JupyterVersion = 'v0.0.43' +param AiUnlimitedUIVersion = 'v0.0.6' +param JupyterVersion = 'v0.0.49' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep index 1cdc5ac..52479b4 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep +++ b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep @@ -56,7 +56,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'latest' +param JupyterVersion string = 'v0.0.49' @description('Join token for the Jupyter Labs service') @secure() diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam index c29bc89..87d94c1 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam @@ -17,7 +17,7 @@ param detinationAppSecGroups = [] param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param JupyterVersion = 'latest' +param JupyterVersion = 'v0.0.49' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep index c8739d1..f0ac351 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep +++ b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep @@ -56,7 +56,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'latest' +param JupyterVersion string = 'v0.0.49' @description('Join token for the Jupyter Labs service') @secure() diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam index f291ead..9cd7bf0 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam @@ -18,7 +18,7 @@ param AllowPublicSSH = true param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param JupyterVersion = 'latest' +param JupyterVersion = 'v0.0.49' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} From 2cf2e76a274a472945e453d08729d2fd440f0609 Mon Sep 17 00:00:00 2001 From: hc186011 Date: Wed, 30 Oct 2024 15:58:41 -0700 Subject: [PATCH 11/28] Update Jupyter Tag --- deployments/docker/jupyter.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/docker/jupyter.yaml b/deployments/docker/jupyter.yaml index efa17c4..5029dde 100644 --- a/deployments/docker/jupyter.yaml +++ b/deployments/docker/jupyter.yaml @@ -6,7 +6,7 @@ services: replicas: 1 platform: linux/amd64 container_name: jupyter - image: ${JUPYTER_IMAGE_NAME:-teradata/ai-unlimited-jupyter}:${JUPYTER_IMAGE_TAG:-v0.0.49} + image: ${JUPYTER_IMAGE_NAME:-teradata/ai-unlimited-jupyter}:${JUPYTER_IMAGE_TAG:-v0.0.51} environment: accept_license: "Y" ports: From 2413aa3f6776530b30f8856d0a9db035624b0a0d Mon Sep 17 00:00:00 2001 From: alicia-td <166751279+alicia-td@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:48:00 -0700 Subject: [PATCH 12/28] chore: update workspaces docker image to v0.3.1 --- deployments/docker/ai-unlimited.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index c37b8c2..de4b96c 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -6,7 +6,7 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces - image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.3.0} + image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.3.1} command: workspaces serve -v restart: unless-stopped ports: @@ -42,4 +42,4 @@ services: networks: ai-unlimited-network: - name: ai-unlimited-network \ No newline at end of file + name: ai-unlimited-network From 5d6e69ac7826c8906bbf285eeef6b74e726aed37 Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 10:27:23 -0700 Subject: [PATCH 13/28] version is deprecated, ignored --- deployments/docker/aws-credentials-local-volume.yaml | 2 -- deployments/docker/azure-credentials-local-volume.yaml | 2 -- deployments/docker/jupyter.yaml | 2 -- 3 files changed, 6 deletions(-) diff --git a/deployments/docker/aws-credentials-local-volume.yaml b/deployments/docker/aws-credentials-local-volume.yaml index 941d20f..693f9dd 100644 --- a/deployments/docker/aws-credentials-local-volume.yaml +++ b/deployments/docker/aws-credentials-local-volume.yaml @@ -1,5 +1,3 @@ -version: "3.9" - services: ai-unlimited: volumes: diff --git a/deployments/docker/azure-credentials-local-volume.yaml b/deployments/docker/azure-credentials-local-volume.yaml index 29efc58..2d20d4c 100644 --- a/deployments/docker/azure-credentials-local-volume.yaml +++ b/deployments/docker/azure-credentials-local-volume.yaml @@ -1,5 +1,3 @@ -version: "3.9" - services: ai-unlimited: volumes: diff --git a/deployments/docker/jupyter.yaml b/deployments/docker/jupyter.yaml index 5029dde..4878888 100644 --- a/deployments/docker/jupyter.yaml +++ b/deployments/docker/jupyter.yaml @@ -1,5 +1,3 @@ -version: "3.9" - services: jupyter: deploy: From 4577aff743306996f497af1ce7c24aae89f7d88e Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 11:19:25 -0700 Subject: [PATCH 14/28] version deprecated & require env vars when this compose is in use --- deployments/docker/aws-credentials-env-vars.yaml | 8 +++----- deployments/docker/azure-credentials-env-vars.yaml | 10 ++++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/deployments/docker/aws-credentials-env-vars.yaml b/deployments/docker/aws-credentials-env-vars.yaml index 69f49c9..d957270 100644 --- a/deployments/docker/aws-credentials-env-vars.yaml +++ b/deployments/docker/aws-credentials-env-vars.yaml @@ -1,8 +1,6 @@ -version: "3.9" - services: ai-unlimited: environment: - AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID:-''}" - AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY:-''}" - AWS_SESSION_TOKEN: "${AWS_SESSION_TOKEN:-''}" + AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID:?Required to have access to AWS}" + AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY:?Required to have access to AWS}" + AWS_SESSION_TOKEN: "${AWS_SESSION_TOKEN:?Required to have access to AWS}" diff --git a/deployments/docker/azure-credentials-env-vars.yaml b/deployments/docker/azure-credentials-env-vars.yaml index b5e712a..3f312ad 100644 --- a/deployments/docker/azure-credentials-env-vars.yaml +++ b/deployments/docker/azure-credentials-env-vars.yaml @@ -1,9 +1,7 @@ -version: "3.9" - services: ai-unlimited: environment: - ARM_SUBSCRIPTION_ID: "${ARM_SUBSCRIPTION_ID:-''}" - ARM_CLIENT_ID: "${ARM_CLIENT_ID:-''}" - ARM_CLIENT_SECRET: "${ARM_CLIENT_SECRET:-''}" - ARM_TENANT_ID: "${ARM_TENANT_ID:-''}" + ARM_SUBSCRIPTION_ID: "${ARM_SUBSCRIPTION_ID:?Required to have access to Azure}" + ARM_CLIENT_ID: "${ARM_CLIENT_ID:?Required to have access to Azure}" + ARM_CLIENT_SECRET: "${ARM_CLIENT_SECRET:?Required to have access to Azure}" + ARM_TENANT_ID: "${ARM_TENANT_ID:?Required to have access to Azure}" From e187df04ba9b7cbfbed6fc94bb7d5354f7e94628 Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 11:19:35 -0700 Subject: [PATCH 15/28] adding TLS changes --- deployments/docker/ai-unlimited.yaml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index de4b96c..15885e6 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -1,5 +1,3 @@ -version: "3.9" - services: ai-unlimited: deploy: @@ -18,7 +16,9 @@ services: TD_VCD_API_PORT: "${TD_VCD_API_PORT:-3282}" TD_VCD_AUTH_PORT: "${TD_VCD_AUTH_PORT:-3000}" TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" + TD_VCD_LOG_LEVEL: "${AI_UNLIMITED_LOG_LEVEL:-INFO}" volumes: + - ssl_certs:/etc/td/ssl - ${AI_UNLIMITED_HOME:-./volumes/ai-unlimited-workspaces}:/etc/td networks: - ai-unlimited-network @@ -27,19 +27,29 @@ services: deploy: replicas: 1 platform: linux/amd64 - container_name: workspaces-ui + container_name: ai-unlimited-workspaces-ui image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_UI_IMAGE_TAG:-v0.0.6} ports: - "443:443/tcp" - - "${TD_VCD_UI_PORT:-80}:80/tcp" + - "80:80/tcp" environment: - TD_VCD_UI_PORT: "${TD_VCD_UI_PORT:-80}" + TD_VCD_USE_TLS: "${TD_VCD_USE_TLS:-false}" TD_VCD_API_PORT: "${TD_VCD_API_PORT:-3282}" TD_VCD_AUTH_PORT: "${TD_VCD_AUTH_PORT:-3000}" TD_VCD_INIT_API_KEY: "${AI_UNLIMITED_INIT_API_KEY:?Initial API key is required, please run the generate api key script.}" + volumes: + - ssl_certs:/etc/ssl/td networks: - ai-unlimited-network +volumes: + ssl_certs: + # external: true + +# make the volume external if you'd like to preload the certificate & private key in advance. Like so: +# docker volume create ssl_certs +# docker run --rm -v ${PWD}/ssl:/source -v ssl_certs:/dest busybox cp -r /source/certs /source/private /dest/ + networks: ai-unlimited-network: name: ai-unlimited-network From 425ec32a50454ea0157e4bc674f8dea9f0285014 Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 11:19:42 -0700 Subject: [PATCH 16/28] improved documentation for docker compose --- deployments/docker/README.md | 153 ++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 31 deletions(-) diff --git a/deployments/docker/README.md b/deployments/docker/README.md index 971df83..d0a7e74 100644 --- a/deployments/docker/README.md +++ b/deployments/docker/README.md @@ -1,64 +1,155 @@ -# Deploy with Docker Compose +# Deploy AI Unlimited with Docker Compose -## AI Unlimited + -### Pre-requisite Steps -An initial API Key Environment Variable is required to start the Docker Compose Stack. You can generate one by doing the following: + -#### On OSX/Linux +- [1. Pre-requisite Steps](#1-pre-requisite-steps) + - [1.1 Cleanup](#11-cleanup) + - [1.2 Initial API Key](#12-initial-api-key) + - [On macOS/Linux](#on-macoslinux) + - [On Windows](#on-windows) + - [1.3 TLS/SSL Certificates](#13-tlsssl-certificates) + - [1.4 Debug mode](#14-debug-mode) +- [2. Deploy AI Unlimited with AWS](#2-deploy-ai-unlimited-with-aws) +- [3. Deploy AI Unlimited with Azure](#3-deploy-ai-unlimited-with-azure) +- [4. Deploy Jupyter](#4-deploy-jupyter) +- [5. Deploy Jupyter and AI Unlimited](#5-deploy-jupyter-and-ai-unlimited) + - [5.1 With AWS](#51-with-aws) + - [5.2 With Azure](#52-with-azure) + - [5.3 With AWS and Azure](#53-with-aws-and-azure) + + +## 1. Pre-requisite Steps + +### 1.1 Cleanup + +If you spun up AI Unlimited previously on the same domain (i.e. `localhost` or `my.ai-unlimited.local`) we recommend to cleanup the browser cache. + +If you pulled or used the Docker images previously, and are still there, we recommend to delete them, like so: + +```bash +docker-compose -f ai-unlimited.yaml down +docker-compose -f ai-unlimited.yaml rm -fsv +docker rmi $(docker images 'teradata/ai-unlimited*' -qa | sort | uniq) || true +docker images 'teradata/ai-unlimited*' ``` + +If you'd like a new fresh installation with no previous users in AI Unlimited, TLS/SSL certificates, or configuration, we recommend to delete these files or the files with the configration you don't want to persist: + +```bash +rm -rf ./volumes +rm -rf ./ssl +``` + +### 1.2 Initial API Key + +An Initial API Key is required in the `AI_UNLIMITED_INIT_API_KEY` environment variable to start the docker-compose stack. You can generate one by doing the following: + +#### On macOS/Linux + +```bash source generate_api_key.sh ``` + #### On Windows -``` +Execute this script and follow the instructions from the scripts output. + +```powershell ./generate_api_key.ps1 ``` -Follow the instructions from the scripts output. -### With AWS -``` -docker compose -f ai-unlimited.yaml -f aws-credentials-env-vars.yaml.yaml -``` -### With Azure -``` -docker compose -f ai-unlimited.yaml -f azure-credentials-env-vars.yaml.yaml -``` +### 1.3 TLS/SSL Certificates -## Jupyter +To execute AI Unlimited with TLS/SSL enabled you need a Certificate & Private Key pair and (optional but recommended) a CA certificate. There are many different ways to generate them for testing environments on localhost, here is one of them using `mkcert`: -``` -docker compose -f jupyter.yaml up -``` -## Jupyter and AI Unlimited +1. Install `mkcert` following the instructions according to your OS from its [Github repository](https://github.com/FiloSottile/mkcert). If you are on macOS execute: + + ```bash + brew install mkcert + brew install nss # if you use Firefox + ``` + +2. Generate and install the CA certificate, executing: + + ```bash + mkcert -install + ``` + +3. Generate the Certificate and Private Key + - generate them in the desired directory, for example, in `./ssl/certs/` and `./ssl/private/` + - if you have a local custom DNS in your `/etc/hosts`, include the hostname at the end of the list, for example, `my.ai-unlimited.local` -### With AWS, using environment variables + ```bash + mkdir -p ./ssl/{certs,private} + mkcert -cert-file ./ssl/certs/ai-unlimited.crt -key-file ./ssl/private/ai-unlimited.key localhost 127.0.0.1 ::1 my.ai-unlimited.local + ``` +Feel free to use `mkcert` as you which - or other tool - as long as you have a valid Certificate & Private Key pair. + +### 1.4 Debug mode + +To start on debug mode, export the environment variable `AI_UNLIMITED_LOG_LEVEL` with `DEBUG`, like so: + +```bash +export AI_UNLIMITED_LOG_LEVEL=DEBUG ``` -docker compose -f ai-unlimited.yaml -f aws-credentials-env-vars.yaml -f jupyter.yaml up + +## 2. Deploy AI Unlimited with AWS + +```bash +docker-compose -f ai-unlimited.yaml -f aws-credentials-env-vars.yaml up ``` -### With AWS, using a local volume with credentials +## 3. Deploy AI Unlimited with Azure +```bash +docker-compose -f ai-unlimited.yaml -f azure-credentials-env-vars.yaml up ``` -docker compose -f ai-unlimited.yaml -f aws-credentials-local-volume.yaml -f jupyter.yaml up + +## 4. Deploy Jupyter + +```bash +docker-compose -f jupyter.yaml up ``` -### With Azure, using environment variables +## 5. Deploy Jupyter and AI Unlimited + +### 5.1 With AWS +If you have the AWS credentials on environment variables, execute: + +```bash +docker-compose -f ai-unlimited.yaml -f aws-credentials-env-vars.yaml -f jupyter.yaml up ``` -docker compose -f ai-unlimited.yaml -f azure-credentials-env-vars.yaml -f jupyter.yaml up + +Otherwise, if you are using the AWS configuration files (i.e. `~/.aws/`), execute: + +```bash +docker-compose -f ai-unlimited.yaml -f aws-credentials-local-volume.yaml -f jupyter.yaml up ``` -### With Azure, using a local volume with credentials +### 5.2 With Azure + +If you have the Azure credentials on environment variables, execute: +```bash +docker-compose -f ai-unlimited.yaml -f azure-credentials-env-vars.yaml -f jupyter.yaml up ``` -docker compose -f ai-unlimited.yaml -f azure-credentials-local-volume.yaml -f jupyter.yaml up + +Otherwise, if you are using the Azure configuration files (i.e. `~/.azure/`), execute: + +```bash +docker-compose -f ai-unlimited.yaml -f azure-credentials-local-volume.yaml -f jupyter.yaml up ``` -### With Aws and Azure, using two local credential volumes +### 5.3 With AWS and Azure + +Same as above but using both files, for AWS and Azure either with the credentials on environment variables or with the configuration files or a conbination of both. +In this example, both environments are using the credentials on environment variables: +```bash +docker-compose -f ai-unlimited.yaml -f aws-credentials-local-volume.yaml -f azure-credentials-local-volume.yaml -f jupyter.yaml up ``` -docker compose -f ai-unlimited.yaml -f aws-credentials-local-volume.yaml -f azure-credentials-local-volume.yaml -f jupyter.yaml up -``` \ No newline at end of file From 0154016569aabc5fb4503b2cdc920c902cdf77ed Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 14:33:55 -0700 Subject: [PATCH 17/28] feat: add ports & shared volume for ui and server --- .../templates/ai-unlimited/ai-unlimited-with-nlb.yaml | 9 +++++++-- .../templates/ai-unlimited/ai-unlimited-without-lb.yaml | 9 +++++++-- .../aws/templates/all-in-one/all-in-one-with-nlb.yaml | 9 +++++++-- .../aws/templates/all-in-one/all-in-one-without-lb.yaml | 9 +++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index 67d74a2..198613c 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -513,6 +513,7 @@ Resources: Restart=always RestartSec=2 + ExecStartPre=-/bin/bash -c '/usr/bin/docker volume create ssl_certs || true' ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -522,11 +523,13 @@ Resources: ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ - -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_USE_TLS=false \ -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedUiPort }:80 \ + -p 80:80 \ + -p 443:443 \ + -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } [Install] @@ -567,6 +570,8 @@ Resources: -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ + -v /etc/td/ai-unlimited:/etc/td \ + -v ssl_certs:/etc/td/ssl \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 39192d8..3c104d4 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -508,6 +508,7 @@ Resources: Restart=always RestartSec=2 + ExecStartPre=-/bin/bash -c '/usr/bin/docker volume create ssl_certs || true' ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -517,11 +518,13 @@ Resources: ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ - -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_USE_TLS=false \ -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedUiPort }:80 \ + -p 80:80 \ + -p 443:443 \ + -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } [Install] @@ -562,6 +565,8 @@ Resources: -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ + -v /etc/td/ai-unlimited:/etc/td \ + -v ssl_certs:/etc/td/ssl \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 4f38178..1f716a3 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -531,6 +531,7 @@ Resources: Restart=always RestartSec=2 + ExecStartPre=-/bin/bash -c '/usr/bin/docker volume create ssl_certs || true' ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -540,11 +541,13 @@ Resources: ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ - -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_USE_TLS=false \ -e TD_VCD_API_PORT=3282 \ -e TD_VCD_AUTH_PORT=3000 \ -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedUiPort }:80 \ + -p 80:80 \ + -p 443:443 \ + -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } [Install] @@ -585,6 +588,8 @@ Resources: -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ + -v /etc/td/ai-unlimited:/etc/td \ + -v ssl_certs:/etc/td/ssl \ --network ai_unlimited \ --net-alias ${ LoadBalancer.DNSName } \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index 111c4d4..9a87bdb 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -526,6 +526,7 @@ Resources: Restart=always RestartSec=2 + ExecStartPre=-/bin/bash -c '/usr/bin/docker volume create ssl_certs || true' ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt @@ -535,11 +536,13 @@ Resources: ExecStart=/usr/bin/docker run \ -e accept_license=Y \ -e PLATFORM=aws \ - -e TD_VCD_UI_PORT=${ AiUnlimitedUiPort } \ + -e TD_VCD_USE_TLS=false \ -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedUiPort }:80 \ + -p 80:80 \ + -p 443:443 \ + -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } [Install] @@ -580,6 +583,8 @@ Resources: -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ + -v /etc/td/ai-unlimited:/etc/td \ + -v ssl_certs:/etc/td/ssl \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v [Install] From a95b097900adffced7f117bf9b1bdf2d89946dcf Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 15:04:36 -0700 Subject: [PATCH 18/28] feat: add ports & shared volume for ui and server on Azure --- deployments/azure/scripts/ai-unlimited-ui.service | 9 +++++---- deployments/azure/scripts/ai-unlimited.service | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/deployments/azure/scripts/ai-unlimited-ui.service b/deployments/azure/scripts/ai-unlimited-ui.service index 95cd599..a2cf43c 100644 --- a/deployments/azure/scripts/ai-unlimited-ui.service +++ b/deployments/azure/scripts/ai-unlimited-ui.service @@ -15,14 +15,15 @@ ExecStartPre=-/usr/bin/docker rm %n ExecStartPre=/usr/bin/docker pull {0}/{1}:{2} ExecStart=/usr/bin/docker run \ - -e TD_VCD_UI_PORT={3} \ + -e TD_VCD_USE_TLS=false \ -e TD_VCD_AUTH_PORT={4}\ -e TD_VCD_API_PORT={5}\ -e TD_VCD_INIT_API_KEY \ - -v /etc/td/ai-unlimited:/etc/td \ - -p {3}:80 \ + -p 80:80 \ + -p 443:443 \ + -v ssl_certs:/etc/ssl/td \ --network ai_unlimited {6} \ - --rm --name %n {0}/{1}:{2} + --rm --name %n {0}/{1}:{2} [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/deployments/azure/scripts/ai-unlimited.service b/deployments/azure/scripts/ai-unlimited.service index b9bed57..da29dd9 100644 --- a/deployments/azure/scripts/ai-unlimited.service +++ b/deployments/azure/scripts/ai-unlimited.service @@ -10,6 +10,7 @@ TimeoutStartSec=0 Restart=always RestartSec=2 EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt +ExecStartPre=-/usr/bin/docker volume create ssl_certs ExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited ExecStartPre=-/usr/bin/docker stop %n @@ -23,9 +24,10 @@ ExecStart=/usr/bin/docker run \ -e ARM_SUBSCRIPTION_ID={5} \ -e ARM_TENANT_ID={6} \ -e TD_VCD_INIT_API_KEY \ - -v /etc/td/ai-unlimited:/etc/td \ -p {3}:3000 \ -p {4}:3282 \ + -v /etc/td/ai-unlimited:/etc/td \ + -v ssl_certs:/etc/td/ssl \ --network ai_unlimited {7} \ --rm --name %n {0}/{1}:{2} workspaces serve -v From 7422e52615a6c85a4c6cfe5a210468c4744c2dcb Mon Sep 17 00:00:00 2001 From: Johandry Amador Date: Fri, 1 Nov 2024 15:13:03 -0700 Subject: [PATCH 19/28] Remove AiUnlimitedUiPort, it uses always port 80. Adding 443 to some places (incomplete) --- .../ai-unlimited/ai-unlimited-with-nlb.yaml | 69 +++++++++++-------- .../ai-unlimited/ai-unlimited-without-lb.yaml | 39 ++--------- .../all-in-one/all-in-one-with-nlb.yaml | 38 +++------- .../all-in-one/all-in-one-without-lb.yaml | 39 ++--------- 4 files changed, 57 insertions(+), 128 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index 198613c..82797d8 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -35,7 +35,6 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort - - AiUnlimitedUiPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -127,14 +126,6 @@ Parameters: MinValue: 0 MaxValue: 65535 - AiUnlimitedUiPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 80 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - AiUnlimitedGrpcPort: Description: port to access the AI Unlimited API. Type: Number @@ -379,11 +370,6 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEighty: !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -521,8 +507,6 @@ Resources: ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ -e TD_VCD_USE_TLS=false \ -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ @@ -567,7 +551,6 @@ Resources: -e accept_license=Y \ -e PLATFORM=aws \ -e TD_VCD_INIT_API_KEY \ - -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ -v /etc/td/ai-unlimited:/etc/td \ @@ -710,9 +693,24 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiPort + - FromPort: 80 + IpProtocol: tcp + ToPort: 80 + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue + - FromPort: 443 IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiPort + ToPort: 443 CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -799,7 +797,17 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedUITargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedUiPort + Port: 80 + Protocol: TCP + + AiUnlimitedUISSLListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref AiUnlimitedUITargetGroup + LoadBalancerArn: !Ref LoadBalancer + Port: 443 Protocol: TCP AiUnlimitedSchedulerHTTPListener: @@ -876,7 +884,7 @@ Resources: - td-aiu - ui - api - Port: !Ref AiUnlimitedUiPort + Port: 80 Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -887,7 +895,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedUiPort + Port: 80 VpcId: !Ref Vpc AiUnlimitedGRPCTargetGroup: @@ -1011,8 +1019,12 @@ Resources: ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiPort - ToPort: !Ref AiUnlimitedUiPort + FromPort: 80 + ToPort: 80 + SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP @@ -1031,8 +1043,8 @@ Resources: - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiPort - ToPort: !Ref AiUnlimitedUiPort + FromPort: 80 + ToPort: 80 SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue @@ -1307,10 +1319,7 @@ Outputs: AiUnlimitedUiAccess: Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !If - - PortIsNotEighty - - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck - - !Sub http://${ LoadBalancer.DNSName } + Value: !Sub http://${ LoadBalancer.DNSName } AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 3c104d4..25aca4b 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -33,7 +33,6 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort - - AiUnlimitedUiPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -120,14 +119,6 @@ Parameters: MinValue: 0 MaxValue: 65535 - AiUnlimitedUiPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 80 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -364,21 +355,6 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEightyAndHasPublicIp: !And - - !Not - - !Equals - - !Ref Private - - "true" - - !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - - PortIsNotEighty: !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -562,7 +538,6 @@ Resources: -e accept_license=Y \ -e PLATFORM=aws \ -e TD_VCD_INIT_API_KEY \ - -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ -v /etc/td/ai-unlimited:/etc/td \ @@ -710,9 +685,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiPort + - FromPort: 80 IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiPort + ToPort: 80 CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -1002,18 +977,12 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !If - - PortIsNotEightyAndHasPublicIp - - !Sub http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck - - !Sub http://${AiUnlimitedServer.PublicDnsName} + Value: !Sub http://${AiUnlimitedServer.PublicDnsName} Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access - Value: !If - - PortIsNotEighty - - !Sub http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck - - !Sub http://${AiUnlimitedServer.PrivateDnsName} + Value: !Sub http://${AiUnlimitedServer.PrivateDnsName} AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 1f716a3..7814181 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -35,7 +35,6 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort - - AiUnlimitedUiPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -149,14 +148,6 @@ Parameters: MinValue: 0 MaxValue: 65535 - AiUnlimitedUiPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 80 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -395,11 +386,6 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEighty: !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -585,7 +571,6 @@ Resources: -e accept_license=Y \ -e PLATFORM=aws \ -e TD_VCD_INIT_API_KEY \ - -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ -v /etc/td/ai-unlimited:/etc/td \ @@ -769,9 +754,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiPort + - FromPort: 80 IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiPort + ToPort: 80 CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -872,7 +857,7 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedUITargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedUiPort + Port: 80 Protocol: TCP JupyterHTTPListener: @@ -969,7 +954,7 @@ Resources: - td-aiu - ui - api - Port: !Ref AiUnlimitedUiPort + Port: 80 Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -980,7 +965,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedUiPort + Port: 80 VpcId: !Ref Vpc JupyterHTTPTargetGroup: @@ -1138,8 +1123,8 @@ Resources: ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiPort - ToPort: !Ref AiUnlimitedUiPort + FromPort: 80 + ToPort: 80 SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP @@ -1158,8 +1143,8 @@ Resources: - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiPort - ToPort: !Ref AiUnlimitedUiPort + FromPort: 80 + ToPort: 80 SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue @@ -1460,10 +1445,7 @@ Outputs: AiUnlimitedUiAccess: Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !If - - PortIsNotEighty - - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck - - !Sub http://${ LoadBalancer.DNSName } + Value: !Sub http://${ LoadBalancer.DNSName } AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index 9a87bdb..d3a98fa 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -33,7 +33,6 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort - - AiUnlimitedUiPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -134,14 +133,6 @@ Parameters: MinValue: 0 MaxValue: 65535 - AiUnlimitedUiPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 80 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -380,21 +371,6 @@ Conditions: - !Ref IamRoleName - "" - PortIsNotEightyAndHasPublicIp: !And - - !Not - - !Equals - - !Ref Private - - "true" - - !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - - PortIsNotEighty: !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -580,7 +556,6 @@ Resources: -e accept_license=Y \ -e PLATFORM=aws \ -e TD_VCD_INIT_API_KEY \ - -v /etc/td/ai-unlimited:/etc/td \ -p ${ AiUnlimitedAuthPort }:3000 \ -p ${ AiUnlimitedGrpcPort }:3282 \ -v /etc/td/ai-unlimited:/etc/td \ @@ -766,9 +741,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiPort + - FromPort: 80 IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiPort + ToPort: 80 CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -1084,18 +1059,12 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !If - - PortIsNotEightyAndHasPublicIp - - !Sub http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck - - !Sub http://${AiUnlimitedServer.PublicDnsName} + Value: !Sub http://${AiUnlimitedServer.PublicDnsName} Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access - Value: !If - - PortIsNotEighty - - !Sub http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck - - !Sub http://${AiUnlimitedServer.PrivateDnsName} + Value: !Sub http://${AiUnlimitedServer.PrivateDnsName} AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access From 87089b1be47d93f7c6293912bdb74366418cd58e Mon Sep 17 00:00:00 2001 From: surendra alokam Date: Mon, 4 Nov 2024 10:11:11 -0600 Subject: [PATCH 20/28] added 443 port to the tls support --- .../ai-unlimited/ai-unlimited-without-lb.yaml | 16 +++++++++++++++- .../aws/templates/jupyter/jupyter-with-nlb.yaml | 1 - .../templates/jupyter/jupyter-without-lb.yaml | 1 - 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 25aca4b..460a9b8 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -700,7 +700,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - + - FromPort: 443 + IpProtocol: tcp + ToPort: 443 + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: diff --git a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml index e2e7645..35e9038 100644 --- a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml @@ -12,7 +12,6 @@ Metadata: - InstanceType - RootVolumeSize - TerminationProtection - - JupyterToken - IamRole - IamRoleName - IamPermissionsBoundary diff --git a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml index 7248ecd..51fa96e 100644 --- a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml @@ -12,7 +12,6 @@ Metadata: - InstanceType - RootVolumeSize - TerminationProtection - - JupyterToken - IamRole - IamRoleName - IamPermissionsBoundary From d32c4b14f6e62ead5a92adc57aeb4896b12bcad7 Mon Sep 17 00:00:00 2001 From: surendra alokam Date: Mon, 4 Nov 2024 12:27:10 -0600 Subject: [PATCH 21/28] updating templates to add port 443 --- .../ai-unlimited/ai-unlimited-with-nlb.yaml | 45 ++++++++++- .../all-in-one/all-in-one-with-nlb.yaml | 74 ++++++++++++++++++- .../all-in-one/all-in-one-without-lb.yaml | 17 ++++- .../templates/jupyter/jupyter-with-nlb.yaml | 2 +- .../templates/jupyter/jupyter-without-lb.yaml | 2 +- 5 files changed, 135 insertions(+), 5 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index 82797d8..250e04e 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -805,7 +805,7 @@ Resources: Properties: DefaultActions: - Type: forward - TargetGroupArn: !Ref AiUnlimitedUITargetGroup + TargetGroupArn: !Ref AiUnlimitedUIHTTPSTargetGroup LoadBalancerArn: !Ref LoadBalancer Port: 443 Protocol: TCP @@ -883,6 +883,7 @@ Resources: - !Ref AWS::StackId - td-aiu - ui + - http - api Port: 80 Protocol: TCP @@ -898,6 +899,41 @@ Resources: Port: 80 VpcId: !Ref Vpc + AiUnlimitedUIHTTPSTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckProtocol: HTTPS + HealthCheckTimeoutSeconds: 15 + Name: !Join + - '-' + - - !Select + - 4 + - !Split + - '-' + - !Select + - 2 + - !Split + - / + - !Ref AWS::StackId + - td-aiu + - ui + - https + - api + Port: 443 + Protocol: TCP + TargetGroupAttributes: + - Key: stickiness.enabled + Value: true + - Key: stickiness.type + Value: source_ip + - Key: deregistration_delay.timeout_seconds + Value: "20" + Targets: + - Id: !Ref AiUnlimitedServer + Port: 443 + VpcId: !Ref Vpc + AiUnlimitedGRPCTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: @@ -1047,6 +1083,13 @@ Resources: ToPort: 80 SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue + - !If + - HASSECURITYGROUP + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + SourceSecurityGroupId: !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 7814181..8a1c3ac 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -174,7 +174,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.49 + Default: v0.0.51 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -769,6 +769,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + - FromPort: 443 + IpProtocol: tcp + ToPort: 443 + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue Condition: HASCIDRORPREFIXLISTORSECGROUP LoadBalancerSchedulerSecurityGroup: @@ -860,6 +875,16 @@ Resources: Port: 80 Protocol: TCP + AiUnlimitedUISSLListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref AiUnlimitedUIHTTPSTargetGroup + LoadBalancerArn: !Ref LoadBalancer + Port: 443 + Protocol: TCP + JupyterHTTPListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: @@ -953,6 +978,7 @@ Resources: - !Ref AWS::StackId - td-aiu - ui + - http - api Port: 80 Protocol: TCP @@ -968,6 +994,41 @@ Resources: Port: 80 VpcId: !Ref Vpc + AiUnlimitedUIHTTPSTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + HealthCheckIntervalSeconds: 30 + HealthCheckProtocol: HTTPS + HealthCheckTimeoutSeconds: 15 + Name: !Join + - '-' + - - !Select + - 4 + - !Split + - '-' + - !Select + - 2 + - !Split + - / + - !Ref AWS::StackId + - td-aiu + - ui + - https + - api + Port: 443 + Protocol: TCP + TargetGroupAttributes: + - Key: stickiness.enabled + Value: true + - Key: stickiness.type + Value: source_ip + - Key: deregistration_delay.timeout_seconds + Value: "20" + Targets: + - Id: !Ref AiUnlimitedServer + Port: 443 + VpcId: !Ref Vpc + JupyterHTTPTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: @@ -1126,6 +1187,10 @@ Resources: FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP - IpProtocol: tcp @@ -1147,6 +1212,13 @@ Resources: ToPort: 80 SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue + - !If + - HASSECURITYGROUP + - IpProtocol: tcp + FromPort: 443 + ToPort: 443 + SourceSecurityGroupId: !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index d3a98fa..181beb8 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -159,7 +159,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.49 + Default: v0.0.51 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -756,6 +756,21 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + - FromPort: 443 + IpProtocol: tcp + ToPort: 443 + CidrIp: !If + - HASCIDR + - !Ref AccessCIDR + - !Ref AWS::NoValue + SourcePrefixListId: !If + - HASPREFIXLIST + - !Ref PrefixList + - !Ref AWS::NoValue + SourceSecurityGroupId: !If + - HASSECURITYGROUP + - !Ref SecurityGroup + - !Ref AWS::NoValue AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup diff --git a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml index 35e9038..923bd5f 100644 --- a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml @@ -119,7 +119,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.49 + Default: v0.0.51 RootVolumeSize: Description: size of the root disk to the jupyter server. diff --git a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml index 51fa96e..a0d83c5 100644 --- a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml @@ -104,7 +104,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.49 + Default: v0.0.51 RootVolumeSize: Description: size of the root disk to the jupyter server. From 48328b71370be03dc88e44203c2a3f8adbca6283 Mon Sep 17 00:00:00 2001 From: surendra alokam Date: Mon, 4 Nov 2024 12:34:27 -0600 Subject: [PATCH 22/28] fixing template format --- .../aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 460a9b8..6dad378 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -715,6 +715,7 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue + AiUnlimitedSchedulerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: From 0925b475b8803f1836a6f66b789e652c0de5a6aa Mon Sep 17 00:00:00 2001 From: surendra alokam Date: Tue, 5 Nov 2024 16:38:31 -0600 Subject: [PATCH 23/28] updating workspaces and ui version --- .../aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml | 4 ++-- .../aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml | 4 ++-- deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml | 4 ++-- .../aws/templates/all-in-one/all-in-one-without-lb.yaml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index 250e04e..985998b 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -137,12 +137,12 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.0 + Default: v0.3.2 AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.6 + Default: v0.0.7 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 6dad378..4b7db78 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -122,7 +122,7 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.0 + Default: v0.3.2 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -132,7 +132,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.6 + Default: v0.0.7 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 8a1c3ac..30f60ea 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -151,12 +151,12 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.0 + Default: v0.3.2 AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.6 + Default: v0.0.7 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index 181beb8..e1edc27 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -136,7 +136,7 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.0 + Default: v0.3.2 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -146,7 +146,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.6 + Default: v0.0.7 JupyterHttpPort: Description: port to access the Jupyter UI. From 90eff2d03354f97bbef132269327db26c17d9375 Mon Sep 17 00:00:00 2001 From: surendra alokam Date: Tue, 5 Nov 2024 18:04:33 -0600 Subject: [PATCH 24/28] updating hardcoded ports to defaults and jupyter version --- .../ai-unlimited/ai-unlimited-with-nlb.yaml | 70 +++++++++++++------ .../ai-unlimited/ai-unlimited-without-lb.yaml | 55 ++++++++++++--- .../all-in-one/all-in-one-with-nlb.yaml | 70 +++++++++++++------ .../all-in-one/all-in-one-without-lb.yaml | 47 +++++++++++-- .../templates/jupyter/jupyter-with-nlb.yaml | 2 +- .../templates/jupyter/jupyter-without-lb.yaml | 2 +- 6 files changed, 186 insertions(+), 60 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index 985998b..fe1f7cc 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -35,6 +35,8 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiHttpsPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -134,6 +136,22 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + + AiUnlimitedUiHttpsPort: + Description: port to allow https access the AI Unlimited UI. + Type: Number + Default: 443 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -370,6 +388,11 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -507,12 +530,14 @@ Resources: ExecStartPre=-/usr/bin/docker rm %n || true ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } ExecStart=/usr/bin/docker run \ + -e accept_license=Y \ + -e PLATFORM=aws \ -e TD_VCD_USE_TLS=false \ -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ -e TD_VCD_INIT_API_KEY \ - -p 80:80 \ - -p 443:443 \ + -p ${ AiUnlimitedUiPort }:80 \ + -p ${ AiUnlimitedUiHttpsPort }:443 \ -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } @@ -693,9 +718,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 80 + - FromPort: !Ref AiUnlimitedUiPort IpProtocol: tcp - ToPort: 80 + ToPort: !Ref AiUnlimitedUiPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -708,9 +733,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 443 + - FromPort: !Ref AiUnlimitedUiHttpsPort IpProtocol: tcp - ToPort: 443 + ToPort: !Ref AiUnlimitedUiHttpsPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -797,7 +822,7 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedUITargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: 80 + Port: !Ref AiUnlimitedUiPort Protocol: TCP AiUnlimitedUISSLListener: @@ -807,7 +832,7 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedUIHTTPSTargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: 443 + Port: !Ref AiUnlimitedUiHttpsPort Protocol: TCP AiUnlimitedSchedulerHTTPListener: @@ -885,7 +910,7 @@ Resources: - ui - http - api - Port: 80 + Port: !Ref AiUnlimitedUiPort Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -896,7 +921,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: 80 + Port: !Ref AiUnlimitedUiPort VpcId: !Ref Vpc AiUnlimitedUIHTTPSTargetGroup: @@ -920,7 +945,7 @@ Resources: - ui - https - api - Port: 443 + Port: !Ref AiUnlimitedUiHttpsPort Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -931,7 +956,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: 443 + Port: !Ref AiUnlimitedUiHttpsPort VpcId: !Ref Vpc AiUnlimitedGRPCTargetGroup: @@ -1055,12 +1080,12 @@ Resources: ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp - FromPort: 80 - ToPort: 80 + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp - FromPort: 443 - ToPort: 443 + FromPort: !Ref AiUnlimitedUiHttpsPort + ToPort: !Ref AiUnlimitedUiHttpsPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP @@ -1079,15 +1104,15 @@ Resources: - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: 80 - ToPort: 80 + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: 443 - ToPort: 443 + FromPort: !Ref AiUnlimitedUiHttpsPort + ToPort: !Ref AiUnlimitedUiHttpsPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue @@ -1362,7 +1387,10 @@ Outputs: AiUnlimitedUiAccess: Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !Sub http://${ LoadBalancer.DNSName } + Value: !If + - PortIsNotEighty + - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck + - !Sub http://${ LoadBalancer.DNSName } AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 4b7db78..4b2dfc1 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -33,6 +33,8 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiHttpsPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -119,6 +121,22 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + + AiUnlimitedUiHttpsPort: + Description: port to allow https access the AI Unlimited UI. + Type: Number + Default: 443 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -355,6 +373,21 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEightyAndHasPublicIp: !And + - !Not + - !Equals + - !Ref Private + - "true" + - !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -498,8 +531,8 @@ Resources: -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ -e TD_VCD_INIT_API_KEY \ - -p 80:80 \ - -p 443:443 \ + -p ${ AiUnlimitedUiPort }:80 \ + -p ${ AiUnlimitedUiHttpsPort }:443 \ -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } @@ -685,9 +718,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 80 + - FromPort: !Ref AiUnlimitedUiPort IpProtocol: tcp - ToPort: 80 + ToPort: !Ref AiUnlimitedUiPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -700,9 +733,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 443 + - FromPort: !Ref AiUnlimitedUiHttpsPort IpProtocol: tcp - ToPort: 443 + ToPort: !Ref AiUnlimitedUiHttpsPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -992,12 +1025,18 @@ Outputs: AiUnlimitedPublicUIAccess: Description: Teradata AI Unlimited public UI Access - Value: !Sub http://${AiUnlimitedServer.PublicDnsName} + Value: !If + - PortIsNotEightyAndHasPublicIp + - !Sub http://${AiUnlimitedServer.PublicDnsName}:${AiUnlimitedUiPort}/healthcheck + - !Sub http://${AiUnlimitedServer.PublicDnsName} Condition: HASPUBLICIP AiUnlimitedPrivateUIAccess: Description: Teradata AI Unlimited private UI Access - Value: !Sub http://${AiUnlimitedServer.PrivateDnsName} + Value: !If + - PortIsNotEighty + - !Sub http://${AiUnlimitedServer.PrivateDnsName}:${AiUnlimitedUiPort}/healthcheck + - !Sub http://${AiUnlimitedServer.PrivateDnsName} AiUnlimitedPublicAPIAccess: Description: Teradata AI Unlimited public API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index 30f60ea..d8d113e 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -35,6 +35,8 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiHttpsPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -148,6 +150,22 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + + AiUnlimitedUiHttpsPort: + Description: port to allow https access the AI Unlimited UI. + Type: Number + Default: 443 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -174,7 +192,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.51 + Default: v0.0.52 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -386,6 +404,11 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -531,8 +554,8 @@ Resources: -e TD_VCD_API_PORT=3282 \ -e TD_VCD_AUTH_PORT=3000 \ -e TD_VCD_INIT_API_KEY \ - -p 80:80 \ - -p 443:443 \ + -p ${ AiUnlimitedUiPort }:80 \ + -p ${ AiUnlimitedUiHttpsPort }:443 \ -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } @@ -754,9 +777,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 80 + - FromPort: !Ref AiUnlimitedUiPort IpProtocol: tcp - ToPort: 80 + ToPort: !Ref AiUnlimitedUiPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -769,9 +792,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 443 + - FromPort: !Ref AiUnlimitedUiHttpsPort IpProtocol: tcp - ToPort: 443 + ToPort: !Ref AiUnlimitedUiHttpsPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -872,7 +895,7 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedUITargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: 80 + Port: !Ref AiUnlimitedUiPort Protocol: TCP AiUnlimitedUISSLListener: @@ -882,7 +905,7 @@ Resources: - Type: forward TargetGroupArn: !Ref AiUnlimitedUIHTTPSTargetGroup LoadBalancerArn: !Ref LoadBalancer - Port: 443 + Port: !Ref AiUnlimitedUiHttpsPort Protocol: TCP JupyterHTTPListener: @@ -980,7 +1003,7 @@ Resources: - ui - http - api - Port: 80 + Port: !Ref AiUnlimitedUiPort Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -991,7 +1014,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: 80 + Port: !Ref AiUnlimitedUiPort VpcId: !Ref Vpc AiUnlimitedUIHTTPSTargetGroup: @@ -1015,7 +1038,7 @@ Resources: - ui - https - api - Port: 443 + Port: !Ref AiUnlimitedUiHttpsPort Protocol: TCP TargetGroupAttributes: - Key: stickiness.enabled @@ -1026,7 +1049,7 @@ Resources: Value: "20" Targets: - Id: !Ref AiUnlimitedServer - Port: 443 + Port: !Ref AiUnlimitedUiHttpsPort VpcId: !Ref Vpc JupyterHTTPTargetGroup: @@ -1184,12 +1207,12 @@ Resources: ToPort: !Ref AiUnlimitedGrpcPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp - FromPort: 80 - ToPort: 80 + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - IpProtocol: tcp - FromPort: 443 - ToPort: 443 + FromPort: !Ref AiUnlimitedUiHttpsPort + ToPort: !Ref AiUnlimitedUiHttpsPort SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - !If - HASSECURITYGROUP @@ -1208,15 +1231,15 @@ Resources: - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: 80 - ToPort: 80 + FromPort: !Ref AiUnlimitedUiPort + ToPort: !Ref AiUnlimitedUiPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue - !If - HASSECURITYGROUP - IpProtocol: tcp - FromPort: 443 - ToPort: 443 + FromPort: !Ref AiUnlimitedUiHttpsPort + ToPort: !Ref AiUnlimitedUiHttpsPort SourceSecurityGroupId: !Ref SecurityGroup - !Ref AWS::NoValue @@ -1517,7 +1540,10 @@ Outputs: AiUnlimitedUiAccess: Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !Sub http://${ LoadBalancer.DNSName } + Value: !If + - PortIsNotEighty + - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck + - !Sub http://${ LoadBalancer.DNSName } AiUnlimitedApiAccess: Description: Loadbalancer access endpoint for AI Unlimited API Access diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index e1edc27..670276f 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -33,6 +33,8 @@ Metadata: - AiUnlimitedSchedulerVersion - AiUnlimitedSchedulerHttpPort - AiUnlimitedSchedulerGrpcPort + - AiUnlimitedUiPort + - AiUnlimitedUiHttpsPort - AiUnlimitedUiVersion - Label: default: Persistent volume @@ -133,6 +135,22 @@ Parameters: MinValue: 0 MaxValue: 65535 + AiUnlimitedUiPort: + Description: port to access the AI Unlimited UI. + Type: Number + Default: 80 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + + AiUnlimitedUiHttpsPort: + Description: port to allow https access the AI Unlimited UI. + Type: Number + Default: 443 + ConstraintDescription: must be a valid ununsed port between 0 and 65535. + MinValue: 0 + MaxValue: 65535 + AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String @@ -159,7 +177,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.51 + Default: v0.0.52 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. @@ -371,6 +389,21 @@ Conditions: - !Ref IamRoleName - "" + PortIsNotEightyAndHasPublicIp: !And + - !Not + - !Equals + - !Ref Private + - "true" + - !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + + PortIsNotEighty: !Not + - !Equals + - !Ref AiUnlimitedUiPort + - 80 + Resources: AiUnlimitedVolume: DeletionPolicy: !Ref PersistentVolumeDeletionPolicy @@ -516,8 +549,8 @@ Resources: -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ -e TD_VCD_INIT_API_KEY \ - -p 80:80 \ - -p 443:443 \ + -p ${ AiUnlimitedUiPort }:80 \ + -p ${ AiUnlimitedUiHttpsPort }:443 \ -v ssl_certs:/etc/ssl/td \ --network ai_unlimited \ --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } @@ -741,9 +774,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 80 + - FromPort: !Ref AiUnlimitedUiPort IpProtocol: tcp - ToPort: 80 + ToPort: !Ref AiUnlimitedUiPort CidrIp: !If - HASCIDR - !Ref AccessCIDR @@ -756,9 +789,9 @@ Resources: - HASSECURITYGROUP - !Ref SecurityGroup - !Ref AWS::NoValue - - FromPort: 443 + - FromPort: !Ref AiUnlimitedUiHttpsPort IpProtocol: tcp - ToPort: 443 + ToPort: !Ref AiUnlimitedUiHttpsPort CidrIp: !If - HASCIDR - !Ref AccessCIDR diff --git a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml index 923bd5f..6c1d395 100644 --- a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml @@ -119,7 +119,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.51 + Default: v0.0.52 RootVolumeSize: Description: size of the root disk to the jupyter server. diff --git a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml index a0d83c5..77859fa 100644 --- a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml @@ -104,7 +104,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.51 + Default: v0.0.52 RootVolumeSize: Description: size of the root disk to the jupyter server. From ce4c3d804921f1055b20cf8491c2557ec9f7af95 Mon Sep 17 00:00:00 2001 From: Aopanis Date: Tue, 12 Nov 2024 12:34:08 -0800 Subject: [PATCH 25/28] Feature/add tls azure (#56) * Added port 443 to firewall and nlb, and updated component versions. --------- Co-authored-by: Anton Panis --- .../ai-unlimited/ai-unlimited-with-nlb.json | 79 +++++++++++++++--- .../ai-unlimited/ai-unlimited-without-lb.json | 66 +++++++++++++-- .../arm/all-in-one/all-in-one-with-nlb.json | 81 ++++++++++++++++--- .../arm/all-in-one/all-in-one-without-lb.json | 68 ++++++++++++++-- .../arm/jupyter/jupyter-with-nlb.json | 58 +++++++++++-- .../arm/jupyter/jupyter-without-lb.json | 48 ++++++++++- .../ai-unlimited/ai-unlimited-with-nlb.bicep | 11 ++- .../ai-unlimited-with-nlb.bicepparam | 5 +- .../ai-unlimited-without-lb.bicep | 10 ++- .../ai-unlimited-without-lb.bicepparam | 4 +- .../all-in-one/all-in-one-with-nlb.bicep | 13 ++- .../all-in-one/all-in-one-with-nlb.bicepparam | 6 +- .../all-in-one/all-in-one-without-lb.bicep | 12 ++- .../all-in-one-without-lb.bicepparam | 6 +- .../bicep/jupyter/jupyter-with-nlb.bicep | 2 +- .../bicep/jupyter/jupyter-with-nlb.bicepparam | 2 +- .../bicep/jupyter/jupyter-without-lb.bicep | 2 +- .../jupyter/jupyter-without-lb.bicepparam | 2 +- .../templates/bicep/modules/firewall.bicep | 28 +++++++ .../azure/templates/bicep/modules/nlb.bicep | 54 +++++++++++-- 20 files changed, 479 insertions(+), 78 deletions(-) diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json index 18270bb..31006cf 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "2835298721030345346" + "templateHash": "8692220933648332781" } }, "parameters": { @@ -87,7 +87,14 @@ "type": "int", "defaultValue": 80, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited service UI http." + } + }, + "AiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 443, + "metadata": { + "description": "port to access the AI Unlimited service UI https." } }, "SourceAppSecGroups": { @@ -148,14 +155,14 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.0", + "defaultValue": "v0.3.2", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.6", + "defaultValue": "v0.0.7", "metadata": { "description": "Container Version of the AI Unlimited UI service" } @@ -170,9 +177,9 @@ }, "variables": { "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td\n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker volume create ssl_certs\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -v ssl_certs:/etc/td/ssl \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -410,6 +417,9 @@ "aiUnlimitedUIHttpPort": { "value": "[parameters('AiUnlimitedUIHttpPort')]" }, + "aiUnlimitedUIHttpsPort": { + "value": "[parameters('AiUnlimitedUIHttpsPort')]" + }, "sourceAppSecGroups": { "value": "[parameters('SourceAppSecGroups')]" }, @@ -430,7 +440,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17204210556751390284" + "templateHash": "11675442112517489951" } }, "parameters": { @@ -472,6 +482,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -725,6 +739,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow https to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", + "direction": "Inbound", + "priority": 706, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -768,6 +820,9 @@ "aiUnlimitedUIHttpPort": { "value": "[parameters('AiUnlimitedUIHttpPort')]" }, + "aiUnlimitedUIHttpsPort": { + "value": "[parameters('AiUnlimitedUIHttpsPort')]" + }, "tags": { "value": "[parameters('Tags')]" } @@ -779,7 +834,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1616678944691212739" + "templateHash": "5109107861889662451" } }, "parameters": { @@ -812,6 +867,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "tags": { "type": "object", "defaultValue": {} @@ -853,8 +912,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedAuthPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttps', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpsPort'), 'backendPort', parameters('aiUnlimitedUIHttpsPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpsLbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedAuthPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UIHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', format('{0}UIHttpsLbProbe', parameters('name')), 'properties', createObject('protocol', 'Https', 'port', parameters('aiUnlimitedUIHttpsPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json index f197d00..23e9213 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "9964344374735929406" + "templateHash": "18411899321530490967" } }, "parameters": { @@ -87,7 +87,14 @@ "type": "int", "defaultValue": 80, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited service UI http." + } + }, + "AiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 443, + "metadata": { + "description": "port to access the AI Unlimited service UI https." } }, "SourceAppSecGroups": { @@ -148,14 +155,14 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.0", + "defaultValue": "v0.3.2", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.6", + "defaultValue": "v0.0.7", "metadata": { "description": "Container Version of the AI Unlimited UI service" } @@ -170,9 +177,9 @@ }, "variables": { "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td\n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker volume create ssl_certs\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -v ssl_certs:/etc/td/ssl \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -412,6 +419,9 @@ "aiUnlimitedUIHttpPort": { "value": "[parameters('AiUnlimitedUIHttpPort')]" }, + "aiUnlimitedUIHttpsPort": { + "value": "[parameters('AiUnlimitedUIHttpsPort')]" + }, "sourceAppSecGroups": { "value": "[parameters('SourceAppSecGroups')]" }, @@ -429,7 +439,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17204210556751390284" + "templateHash": "11675442112517489951" } }, "parameters": { @@ -471,6 +481,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -724,6 +738,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow https to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", + "direction": "Inbound", + "priority": 706, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json index d4f6ee6..aebdfe0 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "8915778081204530415" + "templateHash": "243466911239880803" } }, "parameters": { @@ -94,7 +94,14 @@ "type": "int", "defaultValue": 80, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited service UI http." + } + }, + "AiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 443, + "metadata": { + "description": "port to access the AI Unlimited service UI https." } }, "SourceAppSecGroups": { @@ -155,21 +162,21 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.0", + "defaultValue": "v0.3.2", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.6", + "defaultValue": "v0.0.7", "metadata": { "description": "Container Version of the AI Unlimited UI service" } }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.49", + "defaultValue": "v0.0.52", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -190,10 +197,10 @@ }, "variables": { "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{3}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker volume create ssl_certs\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -v ssl_certs:/etc/td/ssl \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -435,6 +442,9 @@ "aiUnlimitedUIHttpPort": { "value": "[parameters('AiUnlimitedUIHttpPort')]" }, + "aiUnlimitedUIHttpsPort": { + "value": "[parameters('AiUnlimitedUIHttpsPort')]" + }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" }, @@ -455,7 +465,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17204210556751390284" + "templateHash": "11675442112517489951" } }, "parameters": { @@ -497,6 +507,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -750,6 +764,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow https to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", + "direction": "Inbound", + "priority": 706, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -793,6 +845,9 @@ "aiUnlimitedUIHttpPort": { "value": "[parameters('AiUnlimitedUIHttpPort')]" }, + "aiUnlimitedUIHttpsPort": { + "value": "[parameters('AiUnlimitedUIHttpsPort')]" + }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" }, @@ -807,7 +862,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1616678944691212739" + "templateHash": "5109107861889662451" } }, "parameters": { @@ -840,6 +895,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "tags": { "type": "object", "defaultValue": {} @@ -881,8 +940,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedAuthPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttps', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpsPort'), 'backendPort', parameters('aiUnlimitedUIHttpsPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpsLbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedAuthPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UIHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', format('{0}UIHttpsLbProbe', parameters('name')), 'properties', createObject('protocol', 'Https', 'port', parameters('aiUnlimitedUIHttpsPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json index a431f44..9e641db 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "10676142330204484121" + "templateHash": "7165782172909449202" } }, "parameters": { @@ -94,7 +94,14 @@ "type": "int", "defaultValue": 80, "metadata": { - "description": "port to access the AI Unlimited service UI." + "description": "port to access the AI Unlimited service UI http." + } + }, + "AiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 443, + "metadata": { + "description": "port to access the AI Unlimited service UI https." } }, "SourceAppSecGroups": { @@ -155,21 +162,21 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.0", + "defaultValue": "v0.3.2", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.6", + "defaultValue": "v0.0.7", "metadata": { "description": "Container Version of the AI Unlimited UI service" } }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.49", + "defaultValue": "v0.0.52", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -190,10 +197,10 @@ }, "variables": { "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{3}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker volume create ssl_certs\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -v ssl_certs:/etc/td/ssl \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_UI_PORT={3} \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -p {3}:80 \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target", + "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", @@ -434,6 +441,9 @@ "aiUnlimitedUIHttpPort": { "value": "[parameters('AiUnlimitedUIHttpPort')]" }, + "aiUnlimitedUIHttpsPort": { + "value": "[parameters('AiUnlimitedUIHttpsPort')]" + }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" }, @@ -454,7 +464,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17204210556751390284" + "templateHash": "11675442112517489951" } }, "parameters": { @@ -496,6 +506,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -749,6 +763,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow https to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", + "direction": "Inbound", + "priority": 706, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { diff --git a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json index 7128ae9..4023910 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "12586694840490067753" + "templateHash": "9373218648166429762" } }, "parameters": { @@ -130,7 +130,7 @@ }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.49", + "defaultValue": "v0.0.52", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -203,7 +203,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17204210556751390284" + "templateHash": "11675442112517489951" } }, "parameters": { @@ -245,6 +245,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -498,6 +502,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow https to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", + "direction": "Inbound", + "priority": 706, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { @@ -543,7 +585,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1616678944691212739" + "templateHash": "5109107861889662451" } }, "parameters": { @@ -576,6 +618,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "tags": { "type": "object", "defaultValue": {} @@ -617,8 +663,8 @@ "name": "[format('{0}OutboundBackendPool', parameters('name'))]" } ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UILbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedAuthPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UILbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", + "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttps', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpsPort'), 'backendPort', parameters('aiUnlimitedUIHttpsPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpsLbProbe', parameters('name'))))))), createArray())))]", + "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedAuthPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UIHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', format('{0}UIHttpsLbProbe', parameters('name')), 'properties', createObject('protocol', 'Https', 'port', parameters('aiUnlimitedUIHttpsPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", "outboundRules": [ { "name": "myOutboundRule", diff --git a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json index 3bae8d0..6eb0a96 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17407221377602669028" + "templateHash": "15682003766962519140" } }, "parameters": { @@ -130,7 +130,7 @@ }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.49", + "defaultValue": "v0.0.52", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -201,7 +201,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17204210556751390284" + "templateHash": "11675442112517489951" } }, "parameters": { @@ -243,6 +243,10 @@ "type": "int", "defaultValue": 0 }, + "aiUnlimitedUIHttpsPort": { + "type": "int", + "defaultValue": 0 + }, "jupyterHttpPort": { "type": "int", "defaultValue": 0 @@ -496,6 +500,44 @@ "dependsOn": [ "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" ] + }, + { + "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "destinationApplicationSecurityGroups", + "count": "[length(parameters('detinationAppSecGroups'))]", + "input": { + "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + }, + { + "name": "sourceApplicationSecurityGroups", + "count": "[length(parameters('sourceAppSecGroups'))]", + "input": { + "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", + "location": "[parameters('location')]" + } + } + ], + "access": "Allow", + "description": "allow https to the workspace ui instance", + "destinationAddressPrefix": "*", + "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", + "direction": "Inbound", + "priority": 706, + "protocol": "Tcp", + "sourceAddressPrefixes": "[parameters('accessCidrs')]", + "sourcePortRange": "*" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" + ] } ], "outputs": { diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep index a033556..25c814a 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep @@ -41,9 +41,12 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service grpc api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI.') +@description('port to access the AI Unlimited service UI http.') param AiUnlimitedUIHttpPort int = 80 +@description('port to access the AI Unlimited service UI https.') +param AiUnlimitedUIHttpsPort int = 443 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -68,10 +71,10 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.0' +param AiUnlimitedVersion string = 'v0.3.2' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.6' +param AiUnlimitedUIVersion string = 'v0.0.7' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -194,6 +197,7 @@ module firewall '../modules/firewall.bicep' = { aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort + aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups sshAccess: false @@ -213,6 +217,7 @@ module nlb '../modules/nlb.bicep' = { aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort + aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort tags: Tags } } diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam index eecbc4a..ccf7548 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam @@ -15,6 +15,7 @@ param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerHttpPort = 50061 // param AiUnlimitedSchedulerGrpcPort = 50051 param AiUnlimitedUIHttpPort = 80 +param AiUnlimitedUIHttpsPort = 443 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' @@ -22,7 +23,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.6' +param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedUIVersion = 'v0.0.7' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep index 84e6353..8e478ef 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep @@ -41,9 +41,12 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI.') +@description('port to access the AI Unlimited service UI http.') param AiUnlimitedUIHttpPort int = 80 +@description('port to access the AI Unlimited service UI https.') +param AiUnlimitedUIHttpsPort int = 443 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -68,10 +71,10 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.0' +param AiUnlimitedVersion string = 'v0.3.2' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.6' +param AiUnlimitedUIVersion string = 'v0.0.7' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -192,6 +195,7 @@ module firewall '../modules/firewall.bicep' = { aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort + aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups tags: Tags diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam index f391976..dc123f2 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam @@ -22,7 +22,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.6' +param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedUIVersion = 'v0.0.7' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep index edf816d..34c30ec 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep @@ -44,9 +44,12 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service http api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI.') +@description('port to access the AI Unlimited service UI http.') param AiUnlimitedUIHttpPort int = 80 +@description('port to access the AI Unlimited service UI https.') +param AiUnlimitedUIHttpsPort int = 443 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -71,13 +74,13 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.0' +param AiUnlimitedVersion string = 'v0.3.2' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.6' +param AiUnlimitedUIVersion string = 'v0.0.7' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.49' +param JupyterVersion string = 'v0.0.52' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -213,6 +216,7 @@ module firewall '../modules/firewall.bicep' = { aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort + aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort jupyterHttpPort: JupyterHttpPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups @@ -232,6 +236,7 @@ module nlb '../modules/nlb.bicep' = { aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort + aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort jupyterHttpPort: JupyterHttpPort tags: Tags } diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam index b922542..dcb01a8 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam @@ -23,9 +23,9 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.6' -param JupyterVersion = 'v0.0.49' +param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedUIVersion = 'v0.0.7' +param JupyterVersion = 'v0.0.52' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep index db7799c..34df6c0 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep @@ -44,9 +44,12 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service http api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI.') +@description('port to access the AI Unlimited service UI http.') param AiUnlimitedUIHttpPort int = 80 +@description('port to access the AI Unlimited service UI https.') +param AiUnlimitedUIHttpsPort int = 443 + @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -71,13 +74,13 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.0' +param AiUnlimitedVersion string = 'v0.3.2' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.6' +param AiUnlimitedUIVersion string = 'v0.0.7' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.49' +param JupyterVersion string = 'v0.0.52' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' @@ -211,6 +214,7 @@ module firewall '../modules/firewall.bicep' = { aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort + aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort jupyterHttpPort: JupyterHttpPort sourceAppSecGroups: SourceAppSecGroups detinationAppSecGroups: detinationAppSecGroups diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam index 5f69542..c8aea75 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam @@ -23,9 +23,9 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.0.6' -param JupyterVersion = 'v0.0.49' +param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedUIVersion = 'v0.0.7' +param JupyterVersion = 'v0.0.52' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep index 52479b4..2ef2d80 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep +++ b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep @@ -56,7 +56,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.49' +param JupyterVersion string = 'v0.0.52' @description('Join token for the Jupyter Labs service') @secure() diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam index 87d94c1..7942c65 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam @@ -17,7 +17,7 @@ param detinationAppSecGroups = [] param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param JupyterVersion = 'v0.0.49' +param JupyterVersion = 'v0.0.52' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep index f0ac351..2941c26 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep +++ b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep @@ -56,7 +56,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.49' +param JupyterVersion string = 'v0.0.52' @description('Join token for the Jupyter Labs service') @secure() diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam index 9cd7bf0..4dea18b 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam @@ -18,7 +18,7 @@ param AllowPublicSSH = true param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param JupyterVersion = 'v0.0.49' +param JupyterVersion = 'v0.0.52' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} diff --git a/deployments/azure/templates/bicep/modules/firewall.bicep b/deployments/azure/templates/bicep/modules/firewall.bicep index 66ea040..dc9d96f 100644 --- a/deployments/azure/templates/bicep/modules/firewall.bicep +++ b/deployments/azure/templates/bicep/modules/firewall.bicep @@ -10,6 +10,7 @@ param aiUnlimitedGrpcPort int = 0 param aiUnlimitedSchedulerHttpPort int = 0 // param aiUnlimitedSchedulerGrpcPort int = 0 param aiUnlimitedUIHttpPort int = 0 +param aiUnlimitedUIHttpsPort int = 0 param jupyterHttpPort int = 0 param tags object = {} param uuid string = newGuid() @@ -217,6 +218,33 @@ resource AiUnlimitedUIHTTP 'Microsoft.Network/networkSecurityGroups/securityRule } } +resource AiUnlimitedUIHTTPS 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04-01' = if (aiUnlimitedUIHttpsPort != 0) { + name: '${name}-workspace-ui-https-allow' + parent: networkSecurityGroup + + properties: { + access: 'Allow' + description: 'allow https to the workspace ui instance' + destinationAddressPrefix: '*' // destinationAddressPrefixes: [] + destinationApplicationSecurityGroups: [for secgroup in detinationAppSecGroups: { + id: secgroup + location: location + } + ] + destinationPortRange: string(aiUnlimitedUIHttpsPort) // destinationPortRanges: [] + direction: 'Inbound' + priority: 706 + protocol: 'Tcp' + sourceAddressPrefixes: accessCidrs // sourceAddressPrefix: 'string' + sourceApplicationSecurityGroups: [for secgroup in sourceAppSecGroups: { + id: secgroup + location: location + } + ] + sourcePortRange: '*' // sourcePortRanges: [] + } +} + // resource AiUnlimitedSchedulerGRPC 'Microsoft.Network/networkSecurityGroups/securityRules@2023-04-01' = if (aiUnlimitedSchedulerGrpcPort != 0) { // name: '${uniqueSecurityGroupName}-scheduler-grpc-allow' // parent: networkSecurityGroup diff --git a/deployments/azure/templates/bicep/modules/nlb.bicep b/deployments/azure/templates/bicep/modules/nlb.bicep index c8bfc70..8b42f17 100644 --- a/deployments/azure/templates/bicep/modules/nlb.bicep +++ b/deployments/azure/templates/bicep/modules/nlb.bicep @@ -7,6 +7,7 @@ param aiUnlimitedSchedulerHttpPort int = 0 // param aiUnlimitedSchedulerGrpcPort int = 0 param jupyterHttpPort int = 0 param aiUnlimitedUIHttpPort int = 0 +param aiUnlimitedUIHttpsPort int = 0 param tags object = {} module lbPublicIPAddress 'public-ip.bicep' = { @@ -216,7 +217,7 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { aiUnlimitedUIHttpPort != 0 ? [ { - name: 'AiUnlimitedUI' + name: 'AiUnlimitedUIHttp' properties: { frontendIPConfiguration: { id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', name, '${name}Inbound') @@ -237,7 +238,37 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { loadDistribution: 'Default' disableOutboundSnat: true probe: { - id: resourceId('Microsoft.Network/loadBalancers/probes', name, '${name}UILbProbe') + id: resourceId('Microsoft.Network/loadBalancers/probes', name, '${name}UIHttpLbProbe') + } + } + } + ] + : [] + aiUnlimitedUIHttpsPort != 0 + ? [ + { + name: 'AiUnlimitedUIHttps' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', name, '${name}Inbound') + } + backendAddressPool: { + id: resourceId( + 'Microsoft.Network/loadBalancers/backendAddressPools', + name, + '${name}OutboundBackendPool' + ) + } + frontendPort: aiUnlimitedUIHttpsPort + backendPort: aiUnlimitedUIHttpsPort + enableFloatingIP: false + idleTimeoutInMinutes: 15 + protocol: 'Tcp' + enableTcpReset: true + loadDistribution: 'Default' + disableOutboundSnat: true + probe: { + id: resourceId('Microsoft.Network/loadBalancers/probes', name, '${name}UIHttpsLbProbe') } } } @@ -250,9 +281,8 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { { name: '${name}AuthLbProbe' properties: { - protocol: 'Http' + protocol: 'Tcp' port: aiUnlimitedAuthPort - requestPath: '/healthcheck' intervalInSeconds: 5 numberOfProbes: 2 } @@ -316,7 +346,7 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { aiUnlimitedUIHttpPort != 0 ? [ { - name: '${name}UILbProbe' + name: '${name}UIHttpLbProbe' properties: { protocol: 'Http' port: aiUnlimitedUIHttpPort @@ -327,6 +357,20 @@ resource lb 'Microsoft.Network/loadBalancers@2021-08-01' = { } ] : [] + aiUnlimitedUIHttpsPort != 0 + ? [ + { + name: '${name}UIHttpsLbProbe' + properties: { + protocol: 'Https' + port: aiUnlimitedUIHttpsPort + requestPath: '/' + intervalInSeconds: 5 + numberOfProbes: 2 + } + } + ] + : [] ]) outboundRules: [ { From 5bd2b8046b3a7c256dc73dc17678dc9a3ab5ddd1 Mon Sep 17 00:00:00 2001 From: Aopanis Date: Fri, 15 Nov 2024 11:56:18 -0800 Subject: [PATCH 26/28] Removed port parameters, updated workspaces version, and regenerated templates. (#59) Co-authored-by: Anton Panis --- .../ai-unlimited/ai-unlimited-with-nlb.json | 34 ++++++------------- .../ai-unlimited/ai-unlimited-without-lb.json | 30 +++++----------- .../arm/all-in-one/all-in-one-with-nlb.json | 34 ++++++------------- .../arm/all-in-one/all-in-one-without-lb.json | 30 +++++----------- .../ai-unlimited/ai-unlimited-with-nlb.bicep | 10 +++--- .../ai-unlimited-with-nlb.bicepparam | 6 ++-- .../ai-unlimited-without-lb.bicep | 10 +++--- .../ai-unlimited-without-lb.bicepparam | 5 +-- .../all-in-one/all-in-one-with-nlb.bicep | 10 +++--- .../all-in-one/all-in-one-with-nlb.bicepparam | 5 +-- .../all-in-one/all-in-one-without-lb.bicep | 10 +++--- .../all-in-one-without-lb.bicepparam | 5 +-- 12 files changed, 72 insertions(+), 117 deletions(-) diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json index 31006cf..b24aa22 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "8692220933648332781" + "templateHash": "889180382186938082" } }, "parameters": { @@ -83,20 +83,6 @@ "description": "port to access the AI Unlimited service api." } }, - "AiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "port to access the AI Unlimited service UI http." - } - }, - "AiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 443, - "metadata": { - "description": "port to access the AI Unlimited service UI https." - } - }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -155,7 +141,7 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.2", + "defaultValue": "v0.3.4", "metadata": { "description": "Container Version of the AI Unlimited service" } @@ -181,6 +167,8 @@ "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, + "AiUnlimitedUIHttpPort": 80, + "AiUnlimitedUIHttpsPort": 443, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", "dnsId": "[uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('AiUnlimitedName'))]", @@ -415,10 +403,10 @@ "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, "aiUnlimitedUIHttpPort": { - "value": "[parameters('AiUnlimitedUIHttpPort')]" + "value": "[variables('AiUnlimitedUIHttpPort')]" }, "aiUnlimitedUIHttpsPort": { - "value": "[parameters('AiUnlimitedUIHttpsPort')]" + "value": "[variables('AiUnlimitedUIHttpsPort')]" }, "sourceAppSecGroups": { "value": "[parameters('SourceAppSecGroups')]" @@ -818,10 +806,10 @@ "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, "aiUnlimitedUIHttpPort": { - "value": "[parameters('AiUnlimitedUIHttpPort')]" + "value": "[variables('AiUnlimitedUIHttpPort')]" }, "aiUnlimitedUIHttpsPort": { - "value": "[parameters('AiUnlimitedUIHttpsPort')]" + "value": "[variables('AiUnlimitedUIHttpsPort')]" }, "tags": { "value": "[parameters('Tags')]" @@ -1164,7 +1152,7 @@ "value": "[parameters('OSVersion')]" }, "cloudInitData": { - "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" + "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), variables('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" }, "usePersistentVolume": { "value": "[parameters('UsePersistentVolume')]" @@ -1695,11 +1683,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json index 23e9213..5a98955 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "18411899321530490967" + "templateHash": "2333729599339256313" } }, "parameters": { @@ -83,20 +83,6 @@ "description": "port to access the AI Unlimited service api." } }, - "AiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "port to access the AI Unlimited service UI http." - } - }, - "AiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 443, - "metadata": { - "description": "port to access the AI Unlimited service UI https." - } - }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -155,7 +141,7 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.2", + "defaultValue": "v0.3.4", "metadata": { "description": "Container Version of the AI Unlimited service" } @@ -181,6 +167,8 @@ "$fxv#2": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", "$fxv#3": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, + "AiUnlimitedUIHttpPort": 80, + "AiUnlimitedUIHttpsPort": 443, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", "dnsLabelPrefix": "[format('td{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('AiUnlimitedName')))]", @@ -188,7 +176,7 @@ "workspaceRepository": "ai-unlimited-workspaces", "workspaceSchedulerRepository": "ai-unlimited-scheduler", "workspaceUIRepository": "ai-unlimited-workspaces-ui", - "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" + "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), variables('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" }, "resources": [ { @@ -417,10 +405,10 @@ "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, "aiUnlimitedUIHttpPort": { - "value": "[parameters('AiUnlimitedUIHttpPort')]" + "value": "[variables('AiUnlimitedUIHttpPort')]" }, "aiUnlimitedUIHttpsPort": { - "value": "[parameters('AiUnlimitedUIHttpsPort')]" + "value": "[variables('AiUnlimitedUIHttpsPort')]" }, "sourceAppSecGroups": { "value": "[parameters('SourceAppSecGroups')]" @@ -1350,11 +1338,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json index aebdfe0..c8d29ea 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "243466911239880803" + "templateHash": "13345157895989330658" } }, "parameters": { @@ -90,20 +90,6 @@ "description": "port to access the AI Unlimited service api." } }, - "AiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "port to access the AI Unlimited service UI http." - } - }, - "AiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 443, - "metadata": { - "description": "port to access the AI Unlimited service UI https." - } - }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -162,7 +148,7 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.2", + "defaultValue": "v0.3.4", "metadata": { "description": "Container Version of the AI Unlimited service" } @@ -202,6 +188,8 @@ "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, + "AiUnlimitedUIHttpPort": 80, + "AiUnlimitedUIHttpsPort": 443, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", "dnsId": "[uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('AiUnlimitedName'))]", @@ -440,10 +428,10 @@ "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, "aiUnlimitedUIHttpPort": { - "value": "[parameters('AiUnlimitedUIHttpPort')]" + "value": "[variables('AiUnlimitedUIHttpPort')]" }, "aiUnlimitedUIHttpsPort": { - "value": "[parameters('AiUnlimitedUIHttpsPort')]" + "value": "[variables('AiUnlimitedUIHttpsPort')]" }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" @@ -843,10 +831,10 @@ "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, "aiUnlimitedUIHttpPort": { - "value": "[parameters('AiUnlimitedUIHttpPort')]" + "value": "[variables('AiUnlimitedUIHttpPort')]" }, "aiUnlimitedUIHttpsPort": { - "value": "[parameters('AiUnlimitedUIHttpsPort')]" + "value": "[variables('AiUnlimitedUIHttpsPort')]" }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" @@ -1192,7 +1180,7 @@ "value": "[parameters('OSVersion')]" }, "cloudInitData": { - "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" + "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), variables('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" }, "usePersistentVolume": { "value": "[parameters('UsePersistentVolume')]" @@ -1723,11 +1711,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json index 9e641db..59998ec 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7165782172909449202" + "templateHash": "12517215385567961799" } }, "parameters": { @@ -90,20 +90,6 @@ "description": "port to access the AI Unlimited service api." } }, - "AiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "port to access the AI Unlimited service UI http." - } - }, - "AiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 443, - "metadata": { - "description": "port to access the AI Unlimited service UI https." - } - }, "SourceAppSecGroups": { "type": "array", "defaultValue": [], @@ -162,7 +148,7 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.2", + "defaultValue": "v0.3.4", "metadata": { "description": "Container Version of the AI Unlimited service" } @@ -202,6 +188,8 @@ "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", "AiUnlimitedSchedulerHttpPort": 50061, + "AiUnlimitedUIHttpPort": 80, + "AiUnlimitedUIHttpsPort": 443, "AiUnlimitedSchedulerVersion": "latest", "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", "dnsLabelPrefix": "[format('td{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('AiUnlimitedName')))]", @@ -210,7 +198,7 @@ "jupyterRepository": "ai-unlimited-jupyter", "workspaceSchedulerRepository": "ai-unlimited-scheduler", "workspaceUIRepository": "ai-unlimited-workspaces-ui", - "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), parameters('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" + "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), variables('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" }, "resources": [ { @@ -439,10 +427,10 @@ "value": "[variables('AiUnlimitedSchedulerHttpPort')]" }, "aiUnlimitedUIHttpPort": { - "value": "[parameters('AiUnlimitedUIHttpPort')]" + "value": "[variables('AiUnlimitedUIHttpPort')]" }, "aiUnlimitedUIHttpsPort": { - "value": "[parameters('AiUnlimitedUIHttpsPort')]" + "value": "[variables('AiUnlimitedUIHttpsPort')]" }, "jupyterHttpPort": { "value": "[parameters('JupyterHttpPort')]" @@ -1375,11 +1363,11 @@ }, "AiUnlimitedPublicHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPrivateHttpAccess": { "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(parameters('AiUnlimitedUIHttpPort'), 80)), concat(':', string(parameters('AiUnlimitedUIHttpPort'))), ''))]" + "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" }, "AiUnlimitedPublicGrpcAccess": { "type": "string", diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep index 25c814a..4a25d95 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep @@ -41,11 +41,11 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service grpc api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI http.') -param AiUnlimitedUIHttpPort int = 80 +// @description('port to access the AI Unlimited service UI http.') +var AiUnlimitedUIHttpPort = 80 -@description('port to access the AI Unlimited service UI https.') -param AiUnlimitedUIHttpsPort int = 443 +// @description('port to access the AI Unlimited service UI https.') +var AiUnlimitedUIHttpsPort = 443 @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -71,7 +71,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.2' +param AiUnlimitedVersion string = 'v0.3.4' @description('Container Version of the AI Unlimited UI service') param AiUnlimitedUIVersion string = 'v0.0.7' diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam index ccf7548..4ef1787 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam @@ -14,8 +14,8 @@ param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerHttpPort = 50061 // param AiUnlimitedSchedulerGrpcPort = 50051 -param AiUnlimitedUIHttpPort = 80 -param AiUnlimitedUIHttpsPort = 443 +// param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpsPort = 443 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' @@ -23,7 +23,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedVersion = 'v0.3.4' param AiUnlimitedUIVersion = 'v0.0.7' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep index 8e478ef..452803f 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep @@ -41,11 +41,11 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI http.') -param AiUnlimitedUIHttpPort int = 80 +// @description('port to access the AI Unlimited service UI http.') +var AiUnlimitedUIHttpPort = 80 -@description('port to access the AI Unlimited service UI https.') -param AiUnlimitedUIHttpsPort int = 443 +// @description('port to access the AI Unlimited service UI https.') +var AiUnlimitedUIHttpsPort = 443 @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -71,7 +71,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.2' +param AiUnlimitedVersion string = 'v0.3.4' @description('Container Version of the AI Unlimited UI service') param AiUnlimitedUIVersion string = 'v0.0.7' diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam index dc123f2..4eb30e8 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam @@ -14,7 +14,8 @@ param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerGrpcPort = 50051 // param AiUnlimitedSchedulerHttpPort = 50061 -param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpsPort = 443 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' @@ -22,7 +23,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedVersion = 'v0.3.4' param AiUnlimitedUIVersion = 'v0.0.7' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep index 34c30ec..fa31c9f 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep @@ -44,11 +44,11 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service http api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI http.') -param AiUnlimitedUIHttpPort int = 80 +// @description('port to access the AI Unlimited service UI http.') +var AiUnlimitedUIHttpPort = 80 -@description('port to access the AI Unlimited service UI https.') -param AiUnlimitedUIHttpsPort int = 443 +// @description('port to access the AI Unlimited service UI https.') +var AiUnlimitedUIHttpsPort = 443 @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -74,7 +74,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.2' +param AiUnlimitedVersion string = 'v0.3.4' @description('Container Version of the AI Unlimited UI service') param AiUnlimitedUIVersion string = 'v0.0.7' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam index dcb01a8..18a769d 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam @@ -15,7 +15,8 @@ param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerGrpcPort = 50051 // param AiUnlimitedSchedulerHttpPort = 50061 -param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpsPort = 443 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' @@ -23,7 +24,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedVersion = 'v0.3.4' param AiUnlimitedUIVersion = 'v0.0.7' param JupyterVersion = 'v0.0.52' // param AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep index 34df6c0..38e4645 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep @@ -44,11 +44,11 @@ param AiUnlimitedGrpcPort int = 3282 // @description('port to access the AI Unlimited scheduler service http api.') var AiUnlimitedSchedulerHttpPort = 50061 -@description('port to access the AI Unlimited service UI http.') -param AiUnlimitedUIHttpPort int = 80 +// @description('port to access the AI Unlimited service UI http.') +var AiUnlimitedUIHttpPort = 80 -@description('port to access the AI Unlimited service UI https.') -param AiUnlimitedUIHttpsPort int = 443 +// @description('port to access the AI Unlimited service UI https.') +var AiUnlimitedUIHttpsPort = 443 @description('Source Application Security Groups to access the AI Unlimited service api.') param SourceAppSecGroups array = [] @@ -74,7 +74,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.2' +param AiUnlimitedVersion string = 'v0.3.4' @description('Container Version of the AI Unlimited UI service') param AiUnlimitedUIVersion string = 'v0.0.7' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam index c8aea75..59c9101 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam @@ -15,7 +15,8 @@ param AiUnlimitedAuthPort = 3000 param AiUnlimitedGrpcPort = 3282 // param AiUnlimitedSchedulerGrpcPort = 50051 // param AiUnlimitedSchedulerHttpPort = 50061 -param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpPort = 80 +// param AiUnlimitedUIHttpsPort = 443 param SourceAppSecGroups = [] param detinationAppSecGroups = [] param RoleDefinitionId = '' @@ -23,7 +24,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.2' +param AiUnlimitedVersion = 'v0.3.4' param AiUnlimitedUIVersion = 'v0.0.7' param JupyterVersion = 'v0.0.52' // param AiUnlimitedSchedulerVersion = 'latest' From 5f300f9d9fbbe6c0179167e752de8441cf5a610a Mon Sep 17 00:00:00 2001 From: Aopanis Date: Mon, 9 Dec 2024 09:59:29 -0800 Subject: [PATCH 27/28] Updated versions in template files for oct release. (#60) * Updated versions in template files for oct release. * Updated UI version to v0.1.0 and regenerated templates. * Jupyter to v0.1.0 and regenerate templates. --------- Co-authored-by: Anton Panis --- .../ai-unlimited/ai-unlimited-with-nlb.yaml | 4 +- .../ai-unlimited/ai-unlimited-without-lb.yaml | 4 +- .../all-in-one/all-in-one-with-nlb.yaml | 6 +-- .../all-in-one/all-in-one-without-lb.yaml | 6 +-- .../templates/jupyter/jupyter-with-nlb.yaml | 2 +- .../templates/jupyter/jupyter-without-lb.yaml | 2 +- .../ai-unlimited/ai-unlimited-with-nlb.json | 44 +++++++++--------- .../ai-unlimited/ai-unlimited-without-lb.json | 32 ++++++------- .../arm/all-in-one/all-in-one-with-nlb.json | 46 +++++++++---------- .../arm/all-in-one/all-in-one-without-lb.json | 34 +++++++------- .../arm/jupyter/jupyter-with-nlb.json | 30 ++++++------ .../arm/jupyter/jupyter-without-lb.json | 18 ++++---- .../ai-unlimited/ai-unlimited-with-nlb.bicep | 4 +- .../ai-unlimited-with-nlb.bicepparam | 4 +- .../ai-unlimited-without-lb.bicep | 4 +- .../ai-unlimited-without-lb.bicepparam | 4 +- .../all-in-one/all-in-one-with-nlb.bicep | 6 +-- .../all-in-one/all-in-one-with-nlb.bicepparam | 6 +-- .../all-in-one/all-in-one-without-lb.bicep | 6 +-- .../all-in-one-without-lb.bicepparam | 6 +-- .../bicep/jupyter/jupyter-with-nlb.bicep | 2 +- .../bicep/jupyter/jupyter-with-nlb.bicepparam | 2 +- .../bicep/jupyter/jupyter-without-lb.bicep | 2 +- .../jupyter/jupyter-without-lb.bicepparam | 2 +- deployments/docker/ai-unlimited.yaml | 4 +- deployments/docker/jupyter.yaml | 2 +- 26 files changed, 141 insertions(+), 141 deletions(-) diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml index fe1f7cc..1e19a32 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-with-nlb.yaml @@ -155,12 +155,12 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.2 + Default: v0.3.0 AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.7 + Default: v0.1.0 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" diff --git a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml index 4b2dfc1..4ae712d 100644 --- a/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml +++ b/deployments/aws/templates/ai-unlimited/ai-unlimited-without-lb.yaml @@ -140,7 +140,7 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.2 + Default: v0.3.0 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -150,7 +150,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.7 + Default: v0.1.0 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml index d8d113e..7a5dcfb 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml @@ -169,12 +169,12 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.2 + Default: v0.3.0 AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.7 + Default: v0.1.0 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -192,7 +192,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.52 + Default: v0.1.0 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml index 670276f..3be4131 100644 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml @@ -154,7 +154,7 @@ Parameters: AiUnlimitedVersion: Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.3.2 + Default: v0.3.0 AiUnlimitedSchedulerVersion: Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" @@ -164,7 +164,7 @@ Parameters: AiUnlimitedUiVersion: Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.7 + Default: v0.1.0 JupyterHttpPort: Description: port to access the Jupyter UI. @@ -177,7 +177,7 @@ Parameters: JupyterVersion: Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.52 + Default: v0.1.0 RootVolumeSize: Description: size of the root disk to the AI Unlimited server. diff --git a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml index 6c1d395..0db29cd 100644 --- a/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-with-nlb.yaml @@ -119,7 +119,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.52 + Default: v0.1.0 RootVolumeSize: Description: size of the root disk to the jupyter server. diff --git a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml index 77859fa..f4fb410 100644 --- a/deployments/aws/templates/jupyter/jupyter-without-lb.yaml +++ b/deployments/aws/templates/jupyter/jupyter-without-lb.yaml @@ -104,7 +104,7 @@ Parameters: JupyterVersion: Description: Which version of jupyter to deploy, uses container version tags, defaults to "latest" Type: String - Default: v0.0.52 + Default: v0.1.0 RootVolumeSize: Description: size of the root disk to the jupyter server. diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json index b24aa22..c28afa3 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-with-nlb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "889180382186938082" + "version": "0.31.92.45157", + "templateHash": "7009335605344942432" } }, "parameters": { @@ -141,14 +141,14 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.4", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.7", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the AI Unlimited UI service" } @@ -223,8 +223,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6929508783023913887" + "version": "0.31.92.45157", + "templateHash": "29287785012335710" } }, "parameters": { @@ -342,8 +342,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17702031998905620424" + "version": "0.31.92.45157", + "templateHash": "16095084913002426133" } }, "parameters": { @@ -427,8 +427,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11675442112517489951" + "version": "0.31.92.45157", + "templateHash": "392354314460473239" } }, "parameters": { @@ -821,8 +821,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5109107861889662451" + "version": "0.31.92.45157", + "templateHash": "370499549708602593" } }, "parameters": { @@ -957,8 +957,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1039,8 +1039,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1182,8 +1182,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13207593080095673481" + "version": "0.31.92.45157", + "templateHash": "11687747621230861550" } }, "parameters": { @@ -1463,8 +1463,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1569,8 +1569,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2861565763492996333" + "version": "0.31.92.45157", + "templateHash": "9690061458974637253" } }, "parameters": { diff --git a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json index 5a98955..84936a5 100644 --- a/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json +++ b/deployments/azure/templates/arm/ai-unlimited/ai-unlimited-without-lb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2333729599339256313" + "version": "0.31.92.45157", + "templateHash": "7904991390945018605" } }, "parameters": { @@ -141,14 +141,14 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.4", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.7", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the AI Unlimited UI service" } @@ -222,8 +222,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6929508783023913887" + "version": "0.31.92.45157", + "templateHash": "29287785012335710" } }, "parameters": { @@ -341,8 +341,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17702031998905620424" + "version": "0.31.92.45157", + "templateHash": "16095084913002426133" } }, "parameters": { @@ -426,8 +426,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11675442112517489951" + "version": "0.31.92.45157", + "templateHash": "392354314460473239" } }, "parameters": { @@ -838,8 +838,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13207593080095673481" + "version": "0.31.92.45157", + "templateHash": "11687747621230861550" } }, "parameters": { @@ -1119,8 +1119,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1224,8 +1224,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2861565763492996333" + "version": "0.31.92.45157", + "templateHash": "9690061458974637253" } }, "parameters": { diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json index c8d29ea..462abaf 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13345157895989330658" + "version": "0.31.92.45157", + "templateHash": "7316600174603488782" } }, "parameters": { @@ -148,21 +148,21 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.4", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.7", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the AI Unlimited UI service" } }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.52", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -245,8 +245,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6929508783023913887" + "version": "0.31.92.45157", + "templateHash": "29287785012335710" } }, "parameters": { @@ -364,8 +364,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17702031998905620424" + "version": "0.31.92.45157", + "templateHash": "16095084913002426133" } }, "parameters": { @@ -452,8 +452,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11675442112517489951" + "version": "0.31.92.45157", + "templateHash": "392354314460473239" } }, "parameters": { @@ -849,8 +849,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5109107861889662451" + "version": "0.31.92.45157", + "templateHash": "370499549708602593" } }, "parameters": { @@ -985,8 +985,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1067,8 +1067,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1210,8 +1210,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13207593080095673481" + "version": "0.31.92.45157", + "templateHash": "11687747621230861550" } }, "parameters": { @@ -1491,8 +1491,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1597,8 +1597,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2861565763492996333" + "version": "0.31.92.45157", + "templateHash": "9690061458974637253" } }, "parameters": { diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json index 59998ec..bc1c757 100644 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json +++ b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12517215385567961799" + "version": "0.31.92.45157", + "templateHash": "17623174102781456375" } }, "parameters": { @@ -148,21 +148,21 @@ }, "AiUnlimitedVersion": { "type": "string", - "defaultValue": "v0.3.4", + "defaultValue": "v0.3.0", "metadata": { "description": "Container Version of the AI Unlimited service" } }, "AiUnlimitedUIVersion": { "type": "string", - "defaultValue": "v0.0.7", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the AI Unlimited UI service" } }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.52", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -244,8 +244,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6929508783023913887" + "version": "0.31.92.45157", + "templateHash": "29287785012335710" } }, "parameters": { @@ -363,8 +363,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17702031998905620424" + "version": "0.31.92.45157", + "templateHash": "16095084913002426133" } }, "parameters": { @@ -451,8 +451,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11675442112517489951" + "version": "0.31.92.45157", + "templateHash": "392354314460473239" } }, "parameters": { @@ -863,8 +863,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13207593080095673481" + "version": "0.31.92.45157", + "templateHash": "11687747621230861550" } }, "parameters": { @@ -1144,8 +1144,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -1249,8 +1249,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2861565763492996333" + "version": "0.31.92.45157", + "templateHash": "9690061458974637253" } }, "parameters": { diff --git a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json index 4023910..8b6c555 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-with-nlb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9373218648166429762" + "version": "0.31.92.45157", + "templateHash": "1520819731474419291" } }, "parameters": { @@ -130,7 +130,7 @@ }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.52", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -202,8 +202,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11675442112517489951" + "version": "0.31.92.45157", + "templateHash": "392354314460473239" } }, "parameters": { @@ -584,8 +584,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5109107861889662451" + "version": "0.31.92.45157", + "templateHash": "370499549708602593" } }, "parameters": { @@ -720,8 +720,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -802,8 +802,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { @@ -945,8 +945,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13207593080095673481" + "version": "0.31.92.45157", + "templateHash": "11687747621230861550" } }, "parameters": { @@ -1226,8 +1226,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { diff --git a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json index 6eb0a96..ed1c946 100644 --- a/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json +++ b/deployments/azure/templates/arm/jupyter/jupyter-without-lb.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15682003766962519140" + "version": "0.31.92.45157", + "templateHash": "2742666112813260424" } }, "parameters": { @@ -130,7 +130,7 @@ }, "JupyterVersion": { "type": "string", - "defaultValue": "v0.0.52", + "defaultValue": "v0.1.0", "metadata": { "description": "Container Version of the Jupyter Labs service" } @@ -200,8 +200,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11675442112517489951" + "version": "0.31.92.45157", + "templateHash": "392354314460473239" } }, "parameters": { @@ -612,8 +612,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13207593080095673481" + "version": "0.31.92.45157", + "templateHash": "11687747621230861550" } }, "parameters": { @@ -893,8 +893,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11278674213062453956" + "version": "0.31.92.45157", + "templateHash": "4325662974998231491" } }, "parameters": { diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep index 4a25d95..9cfdb10 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicep @@ -71,10 +71,10 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.4' +param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.7' +param AiUnlimitedUIVersion string = 'v0.1.0' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam index 4ef1787..a575181 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-with-nlb.bicepparam @@ -23,7 +23,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.4' -param AiUnlimitedUIVersion = 'v0.0.7' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.1.0' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep index 452803f..66544ee 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicep @@ -71,10 +71,10 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.4' +param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.7' +param AiUnlimitedUIVersion string = 'v0.1.0' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam index 4eb30e8..881bdac 100644 --- a/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/ai-unlimited/ai-unlimited-without-lb.bicepparam @@ -23,7 +23,7 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.4' -param AiUnlimitedUIVersion = 'v0.0.7' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.1.0' // param AiUnlimitedSchedulerVersion = 'latest' param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep index fa31c9f..35a9a1f 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep @@ -74,13 +74,13 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.4' +param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.7' +param AiUnlimitedUIVersion string = 'v0.1.0' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.52' +param JupyterVersion string = 'v0.1.0' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam index 18a769d..9d74d63 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam @@ -24,9 +24,9 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.4' -param AiUnlimitedUIVersion = 'v0.0.7' -param JupyterVersion = 'v0.0.52' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.1.0' +param JupyterVersion = 'v0.1.0' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep index 38e4645..1e62e1d 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep @@ -74,13 +74,13 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.4' +param AiUnlimitedVersion string = 'v0.3.0' @description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.0.7' +param AiUnlimitedUIVersion string = 'v0.1.0' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.52' +param JupyterVersion string = 'v0.1.0' // @description('Container Version of the AI Unlimited scheduler service') var AiUnlimitedSchedulerVersion = 'latest' diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam index 59c9101..d99c519 100644 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam @@ -24,9 +24,9 @@ param UseKeyVault = 'New' param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.4' -param AiUnlimitedUIVersion = 'v0.0.7' -param JupyterVersion = 'v0.0.52' +param AiUnlimitedVersion = 'v0.3.0' +param AiUnlimitedUIVersion = 'v0.1.0' +param JupyterVersion = 'v0.1.0' // param AiUnlimitedSchedulerVersion = 'latest' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep index 2ef2d80..b6b94d0 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep +++ b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicep @@ -56,7 +56,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.52' +param JupyterVersion string = 'v0.1.0' @description('Join token for the Jupyter Labs service') @secure() diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam index 7942c65..efeb49b 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam +++ b/deployments/azure/templates/bicep/jupyter/jupyter-with-nlb.bicepparam @@ -17,7 +17,7 @@ param detinationAppSecGroups = [] param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param JupyterVersion = 'v0.0.52' +param JupyterVersion = 'v0.1.0' param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ param Tags = {} diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep index 2941c26..f7fe4d6 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep +++ b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicep @@ -56,7 +56,7 @@ param PersistentVolumeSize int = 100 param ExistingPersistentVolume string = 'NONE' @description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.0.52' +param JupyterVersion string = 'v0.1.0' @description('Join token for the Jupyter Labs service') @secure() diff --git a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam index 4dea18b..b6b52b9 100644 --- a/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam +++ b/deployments/azure/templates/bicep/jupyter/jupyter-without-lb.bicepparam @@ -18,7 +18,7 @@ param AllowPublicSSH = true param UsePersistentVolume = 'New' param PersistentVolumeSize = 100 param ExistingPersistentVolume = 'NONE' -param JupyterVersion = 'v0.0.52' +param JupyterVersion = 'v0.1.0' param JupyterToken = 'USE_A_SECURE_TOKEN' param Tags = {} diff --git a/deployments/docker/ai-unlimited.yaml b/deployments/docker/ai-unlimited.yaml index 15885e6..77d8598 100644 --- a/deployments/docker/ai-unlimited.yaml +++ b/deployments/docker/ai-unlimited.yaml @@ -4,7 +4,7 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces - image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.3.1} + image: ${AI_UNLIMITED_IMAGE_NAME:-teradata/ai-unlimited-workspaces}:${AI_UNLIMITED_IMAGE_TAG:-v0.3.0} command: workspaces serve -v restart: unless-stopped ports: @@ -28,7 +28,7 @@ services: replicas: 1 platform: linux/amd64 container_name: ai-unlimited-workspaces-ui - image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_UI_IMAGE_TAG:-v0.0.6} + image: ${AI_UNLIMITED_UI_IMAGE_NAME:-teradata/ai-unlimited-workspaces-ui}:${AI_UNLIMITED_UI_IMAGE_TAG:-v0.1.0} ports: - "443:443/tcp" - "80:80/tcp" diff --git a/deployments/docker/jupyter.yaml b/deployments/docker/jupyter.yaml index 4878888..f9f9013 100644 --- a/deployments/docker/jupyter.yaml +++ b/deployments/docker/jupyter.yaml @@ -4,7 +4,7 @@ services: replicas: 1 platform: linux/amd64 container_name: jupyter - image: ${JUPYTER_IMAGE_NAME:-teradata/ai-unlimited-jupyter}:${JUPYTER_IMAGE_TAG:-v0.0.51} + image: ${JUPYTER_IMAGE_NAME:-teradata/ai-unlimited-jupyter}:${JUPYTER_IMAGE_TAG:-v0.1.0} environment: accept_license: "Y" ports: From 3e4e63a54720f80202458ffddfb6188ad73250ee Mon Sep 17 00:00:00 2001 From: Anton Panis Date: Mon, 9 Dec 2024 11:23:12 -0800 Subject: [PATCH 28/28] Remove all in one templates. --- .../all-in-one/all-in-one-with-nlb.yaml | 1589 --------------- .../all-in-one/all-in-one-without-lb.yaml | 1160 ----------- .../aws/templates/all-in-one/readme.txt | 7 - .../arm/all-in-one/all-in-one-with-nlb.json | 1741 ----------------- .../arm/all-in-one/all-in-one-without-lb.json | 1393 ------------- .../azure/templates/arm/all-in-one/readme.txt | 7 - .../all-in-one/all-in-one-with-nlb.bicep | 297 --- .../all-in-one/all-in-one-with-nlb.bicepparam | 32 - .../all-in-one/all-in-one-without-lb.bicep | 275 --- .../all-in-one-without-lb.bicepparam | 32 - 10 files changed, 6533 deletions(-) delete mode 100644 deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml delete mode 100644 deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml delete mode 100644 deployments/aws/templates/all-in-one/readme.txt delete mode 100644 deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json delete mode 100644 deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json delete mode 100644 deployments/azure/templates/arm/all-in-one/readme.txt delete mode 100644 deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep delete mode 100644 deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam delete mode 100644 deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep delete mode 100644 deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam diff --git a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml b/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml deleted file mode 100644 index 7a5dcfb..0000000 --- a/deployments/aws/templates/all-in-one/all-in-one-with-nlb.yaml +++ /dev/null @@ -1,1589 +0,0 @@ -AWSTemplateFormatVersion: "2010-09-09" - -Description: 'AWS CloudFormation Template with AI Unlimited with Jupyter: AI Unlimited is a instance based service for deploying and suspending ai-unlimited clusters, and managing project lifecycles. This template also includes a Jupyter Lab service running on the same host, suitable for demonstration environments. Note: You will be billed for the AWS resources used if you create a stack from this template.' - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AI Unlimited - Parameters: - - AiUnlimitedName - - InstanceType - - RootVolumeSize - - TerminationProtection - - IamRole - - IamRoleName - - IamPermissionsBoundary - - Label: - default: AI Unlimited connection - Parameters: - - AvailabilityZone - - LoadBalancerScheme - - LoadBalancerSubnet - - Private - - Session - - Vpc - - Subnet - - KeyName - - AccessCIDR - - PrefixList - - SecurityGroup - - AiUnlimitedAuthPort - - AiUnlimitedGrpcPort - - AiUnlimitedVersion - - AiUnlimitedSchedulerVersion - - AiUnlimitedSchedulerHttpPort - - AiUnlimitedSchedulerGrpcPort - - AiUnlimitedUiPort - - AiUnlimitedUiHttpsPort - - AiUnlimitedUiVersion - - Label: - default: Persistent volume - Parameters: - - UsePersistentVolume - - PersistentVolumeSize - - ExistingPersistentVolumeId - - PersistentVolumeDeletionPolicy - - Label: - default: Jupyter connection - Parameters: - - JupyterToken - - JupyterHttpPort - - JupyterVersion - -Parameters: - LatestAmiId: - Type: AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 - - AiUnlimitedName: - Description: The AI Unlimited instance name - Type: String - Default: ai-unlimited - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "20" - MinLength: "1" - - JupyterToken: - Description: The token or password equivalent used to access Jupyter. - Type: String - NoEcho: true - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "64" - - Private: - Description: Will AI Unlimited be deployed in a private network without public IPs? - Type: String - AllowedValues: - - true - - false - Default: false - - LoadBalancerScheme: - Description: "Will the load balancer be internal or internet-facing? \nThe DNS name of an Internet-facing load balancer is publicly resolvable to the public IP addresses of the nodes.\nTherefore, Internet-facing load balancers can route requests from clients over the internet. The nodes of an \ninternal load balancer have only private IP addresses. The DNS name of an internal load balancer is publicly\nresolvable to the private IP addresses of the nodes. Therefore, internal load balancers can route requests only\nfrom clients with access to the VPC for the load balancer.\n" - Type: String - AllowedValues: - - internal - - internet-facing - Default: internet-facing - - LoadBalancerSubnet: - Description: Subnetwork to deploy the AI Unlimited service to. - Type: AWS::EC2::Subnet::Id - ConstraintDescription: must be the name of a existing subnet. - - Session: - Description: Should AI Unlimited be accessible via AWS Session Manager? - Type: String - AllowedValues: - - true - - false - Default: false - - Vpc: - Description: Network to deploy the AI Unlimited to. - Type: AWS::EC2::VPC::Id - ConstraintDescription: must be the name of an existing vpc. - - Subnet: - Description: Subnetwork to deploy the AI Unlimited to. - Type: AWS::EC2::Subnet::Id - ConstraintDescription: must be the name of a existing subnet. - - AvailabilityZone: - Description: "Availability zone to deploy the AI Unlimited to.\nThis must match the subnet, the zone of any pre existing volumes if used, \nand the instance type must be available in the selected zone.\n" - Type: AWS::EC2::AvailabilityZone::Name - ConstraintDescription: must be the name of a existing subnet. - - AiUnlimitedAuthPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 3000 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedGrpcPort: - Description: port to access the AI Unlimited API. - Type: Number - Default: 3282 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerHttpPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50061 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerGrpcPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50051 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedUiPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 80 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedUiHttpsPort: - Description: port to allow https access the AI Unlimited UI. - Type: Number - Default: 443 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedVersion: - Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.3.0 - - AiUnlimitedUiVersion: - Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.1.0 - - AiUnlimitedSchedulerVersion: - Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" - Type: String - Default: latest - - JupyterHttpPort: - Description: port to access the Jupyter UI. - Type: Number - Default: 8888 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - JupyterVersion: - Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.1.0 - - RootVolumeSize: - Description: size of the root disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - UsePersistentVolume: - Description: Should we use a new or existing volume for persistent data on the AI Unlimited server. - Type: String - AllowedValues: - - New - - Existing - Default: New - ConstraintDescription: Specify if you are using a a new persistent volume, an existing one, or none. - - PersistentVolumeSize: - Description: size of the optional persistent disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - ExistingPersistentVolumeId: - Description: Id of the existing persistent volume to attach. Must be in the same availability zone as the AI Unlimited instance. - Type: String - Default: None - - PersistentVolumeDeletionPolicy: - Description: Behavior for the Persistent Volume when deleting the cloudformations deployment. - Type: String - AllowedValues: - - Delete - - Retain - - RetainExceptOnCreate - - Snapshot - Default: Retain - - TerminationProtection: - Description: Enable instance termination protection. - Type: String - AllowedValues: - - true - - false - Default: false - - InstanceType: - Description: AI Unlimited EC2 instance type - Type: String - AllowedValues: - - t3.small - - t3.medium - - t3.large - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - i2.xlarge - - i2.2xlarge - - i2.4xlarge - - i2.8xlarge - Default: t3.small - ConstraintDescription: must be a valid EC2 instance type. - - KeyName: - Description: Name of an existing EC2 KeyPair to enable SSH access to the AI Unlimited instance, leave empty if no ssh keys should be included - Type: String - - IamRole: - Description: | - Create a new IAM role for AI Unlimited or use an exiting one. - Requires CAPABILITY_IAM if creating a new IAM Role - Type: String - AllowedValues: - - New - - Existing - Default: New - - IamRoleName: - Description: | - Name of an existing IAM Role to assign to AI Unlimited, - or the name to give to the newly created role. - Leave blank to use an autogenerated name. - Requires CAPABILITY_NAMED_IAM if naming a new IAM Role. - Type: String - - IamPermissionsBoundary: - Description: | - Optional: Arn of a permissions boundary to pass to the IAM Role assigned to AI Unlimited. - Type: String - - AccessCIDR: - Description: The IP address range that can be used to communicate with the AI Unlimited instance. - Type: String - 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. - - PrefixList: - Description: The PrefixList that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid prefixlist - - SecurityGroup: - Description: The SecurityGroup that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid securityGroup ID - -Rules: - subnetsInVpc: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - - instanceTypeInZone: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - -Conditions: - NEEDSROLE: !Equals - - !Ref IamRole - - New - - HASPUBLICIP: !Not - - !Equals - - !Ref Private - - "true" - - HASKEY: !Not - - !Equals - - !Ref KeyName - - "" - - HASCIDR: !Not - - !Equals - - !Ref AccessCIDR - - "" - - HASPREFIXLIST: !Not - - !Equals - - !Ref PrefixList - - "" - - HASSECURITYGROUP: !Not - - !Equals - - !Ref SecurityGroup - - "" - - HASCIDRORPREFIXLIST: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - HASCIDRORPREFIXLISTORSECGROUP: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - !Condition HASSECURITYGROUP - - USESESSIONMANAGER: !Equals - - !Ref Session - - "true" - - NEEDSROLEANDSESSIONMANAGER: !And - - !Condition NEEDSROLE - - !Condition USESESSIONMANAGER - - HASKEYANDPUBLIC: !And - - !Condition HASKEY - - !Condition HASPUBLICIP - - HASKEYANDCIDRORPREFIXLISTORSECGROUP: !And - - !Condition HASKEY - - !Condition HASCIDRORPREFIXLISTORSECGROUP - - USENEWPERSISTENTVOLUME: !Equals - - !Ref UsePersistentVolume - - New - - HASIAMPERMISSIONSBOUNDARY: !Not - - !Equals - - !Ref IamPermissionsBoundary - - "" - - HASIAMROLENAME: !Not - - !Equals - - !Ref IamRoleName - - "" - - PortIsNotEighty: !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - -Resources: - AiUnlimitedVolume: - DeletionPolicy: !Ref PersistentVolumeDeletionPolicy - Type: AWS::EC2::Volume - Properties: - AvailabilityZone: !Ref AvailabilityZone - Size: !Ref PersistentVolumeSize - Encrypted: true - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - Key: Usage - Value: persistent storage - Condition: USENEWPERSISTENTVOLUME - - AiUnlimitedServer: - CreationPolicy: - ResourceSignal: - Timeout: PT15M - Type: AWS::EC2::Instance - Metadata: - AWS::CloudFormation::Init: - configSets: - ai_unlimited_install: - - prepare_directory - - !If - - USENEWPERSISTENTVOLUME - - prepare_new_storage - - !Ref AWS::NoValue - - bind_storage - - mount_storage - - create_ai_unlimited_folder - - create_init_api_key - - install_docker - - configure_ai_unlimited_ui_service - - configure_ai_unlimited_service - - configure_jupyter_service - - start_ai_unlimited_ui_service - - start_ai_unlimited_service - - configure_ai_unlimited_scheduler_service - - start_ai_unlimited_scheduler_service - - start_jupyter_service - prepare_directory: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - mkdir -p /etc/td - prepare_new_storage: - commands: - mkfs: - command: !Sub | - #!/bin/bash -xe - /usr/sbin/mkfs -t ext4 /dev/nvme1n1 - bind_storage: - commands: - fstab: - command: !Sub | - #!/bin/bash -xe - /usr/bin/echo "/dev/nvme1n1 /etc/td ext4 defaults 0 2" >> /etc/fstab - mount_storage: - commands: - mount: - command: !Sub | - #!/bin/bash -xe - /usr/bin/mount -a - create_ai_unlimited_folder: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - mkdir -p /etc/td/ai-unlimited - create_init_api_key: - commands: - run_command: - command: !Sub | - #!/bin/bash -xe - echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt - install_docker: - files: - /usr/lib/systemd/system/docker-install.service: - content: !Sub | - [Unit] - Description=Install docker - - [Service] - Type=oneshot - ExecStart=/bin/bash -c "while ! dnf update; do sleep 2; done && while ! dnf install -y docker; do sleep 2; done" - RemainAfterExit=yes - - [Install] - WantedBy=multi-user.target - commands: - verify_docker: - command: !Sub | - #!/bin/bash -xe - systemctl start docker-install - systemctl start docker - systemctl enable docker - services: - systemd: - docker: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_ui_service: - files: - /usr/lib/systemd/system/ai-unlimited-ui.service: - content: !Sub | - [Unit] - Description=ai-unlimited-ui - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - - ExecStartPre=-/bin/bash -c '/usr/bin/docker volume create ssl_certs || true' - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' - ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui - EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ - -e TD_VCD_USE_TLS=false \ - -e TD_VCD_API_PORT=3282 \ - -e TD_VCD_AUTH_PORT=3000 \ - -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedUiPort }:80 \ - -p ${ AiUnlimitedUiHttpsPort }:443 \ - -v ssl_certs:/etc/ssl/td \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_ui_service: - services: - systemd: - ai-unlimited-ui: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_service: - files: - /usr/lib/systemd/system/ai-unlimited.service: - content: !Sub | - [Unit] - Description=AI Unlimited - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ - -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedAuthPort }:3000 \ - -p ${ AiUnlimitedGrpcPort }:3282 \ - -v /etc/td/ai-unlimited:/etc/td \ - -v ssl_certs:/etc/td/ssl \ - --network ai_unlimited \ - --net-alias ${ LoadBalancer.DNSName } \ - --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_service: - services: - systemd: - ai-unlimited: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_scheduler_service: - files: - /usr/lib/systemd/system/ai-unlimited-scheduler.service: - content: !Sub | - [Unit] - Description=AI Unlimited Scheduler - After=ai-unlimited.service - Requires=ai-unlimited.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:${ AiUnlimitedSchedulerVersion } - ExecStart=/usr/bin/docker run \ - --network ai_unlimited \ - -p ${ AiUnlimitedSchedulerGrpcPort }:50051 \ - -p ${ AiUnlimitedSchedulerHttpPort }:50061 \ - -v /etc/td/ai-unlimited:/etc/td \ - -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \ - -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \ - -e TD_WSSCHED_POL_INTERVAL=2 \ - -e TD_WS_CONTAINER_NAME=ai-unlimited.service \ - --rm --name %n teradata/ai-unlimited-scheduler:${ AiUnlimitedSchedulerVersion } workspace-event-scheduler serve - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_scheduler_service: - services: - systemd: - ai-unlimited-scheduler: - enabled: "true" - ensureRunning: "true" - configure_jupyter_service: - files: - /usr/lib/systemd/system/jupyter.service: - content: !Sub | - [Unit] - Description=jupyter - After=ai-unlimited.service - Requires=ai-unlimited.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited - ExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{userdata,ipython} - ExecStartPre=-/usr/bin/docker exec %n stop || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-jupyter:${ JupyterVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e JUPYTER_TOKEN=${ JupyterToken } \ - -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \ - -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \ - -p ${ JupyterHttpPort }:8888 \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-jupyter:${ JupyterVersion } - - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_jupyter_service: - services: - systemd: - jupyter: - enabled: "true" - ensureRunning: "true" - Properties: - PropagateTagsToVolumeOnCreation: true - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - VolumeSize: !Ref RootVolumeSize - Encrypted: true - NetworkInterfaces: - - DeviceIndex: 0 - SubnetId: !Ref Subnet - GroupSet: - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - !GetAtt JupyterSecurityGroup.GroupId - AssociatePublicIpAddress: !If - - HASPUBLICIP - - true - - !Ref AWS::NoValue - ImageId: !Ref LatestAmiId - InstanceType: !Ref InstanceType - KeyName: !If - - HASKEY - - !Ref KeyName - - !Ref AWS::NoValue - DisableApiTermination: !Ref TerminationProtection - IamInstanceProfile: !Ref AiUnlimitedInstanceProfile - Volumes: - - Device: /dev/xvdb - VolumeId: !If - - USENEWPERSISTENTVOLUME - - !Ref AiUnlimitedVolume - - !Ref ExistingPersistentVolumeId - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - UserData: !Base64 - Fn::Sub: | - #!/bin/bash -xe - yum update -y - yum update -y aws-cfn-bootstrap - /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource AiUnlimitedServer --configsets ai_unlimited_install --region ${AWS::Region} - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource AiUnlimitedServer --region ${AWS::Region} - - LoadBalancerAiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedAuthPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedAuthPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiHttpsPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiHttpsPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancerSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedSchedulerHttpPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancerJupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server from LoadBalancer over http, grpc, and ssh - SecurityGroupIngress: - - FromPort: !Ref JupyterHttpPort - IpProtocol: tcp - ToPort: !Ref JupyterHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Scheme: !Ref LoadBalancerScheme - Subnets: - - !Ref LoadBalancerSubnet - SecurityGroups: - - !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - Type: network - - AiUnlimitedHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedAuthPort - Protocol: TCP - - AiUnlimitedUIListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedUITargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedUiPort - Protocol: TCP - - AiUnlimitedUISSLListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedUIHTTPSTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedUiHttpsPort - Protocol: TCP - - JupyterHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref JupyterHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref JupyterHttpPort - Protocol: TCP - - AiUnlimitedSchedulerHTTPListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedSchedulerHTTPTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedSchedulerHttpPort - Protocol: TCP - - AiUnlimitedSchedulerGRPCListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedSchedulerGRPCTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedSchedulerGrpcPort - Protocol: TCP - - AiUnlimitedGRPCListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - DefaultActions: - - Type: forward - TargetGroupArn: !Ref AiUnlimitedGRPCTargetGroup - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref AiUnlimitedGrpcPort - Protocol: TCP - - AiUnlimitedHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - ui - - http - Port: !Ref AiUnlimitedAuthPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedAuthPort - VpcId: !Ref Vpc - - AiUnlimitedUITargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - ui - - http - - api - Port: !Ref AiUnlimitedUiPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedUiPort - VpcId: !Ref Vpc - - AiUnlimitedUIHTTPSTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTPS - HealthCheckTimeoutSeconds: 15 - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - ui - - https - - api - Port: !Ref AiUnlimitedUiHttpsPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedUiHttpsPort - VpcId: !Ref Vpc - - JupyterHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - jupyter - - ui - - http - Port: !Ref JupyterHttpPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref JupyterHttpPort - VpcId: !Ref Vpc - - AiUnlimitedSchedulerHTTPTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 15 - HealthCheckPath: /healthcheck - Matcher: - HttpCode: "200" - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - aisch - - ui - - http - Port: !Ref AiUnlimitedSchedulerHttpPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedSchedulerHttpPort - VpcId: !Ref Vpc - - AiUnlimitedSchedulerGRPCTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: TCP - HealthCheckTimeoutSeconds: 15 - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - aisch - - api - - grpc - Port: !Ref AiUnlimitedSchedulerGrpcPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedSchedulerGrpcPort - VpcId: !Ref Vpc - - AiUnlimitedGRPCTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - HealthCheckIntervalSeconds: 30 - HealthCheckProtocol: TCP - HealthCheckTimeoutSeconds: 15 - HealthyThresholdCount: 5 - Name: !Join - - '-' - - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - td-aiu - - api - - grpc - Port: !Ref AiUnlimitedGrpcPort - Protocol: TCP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: true - - Key: stickiness.type - Value: source_ip - - Key: deregistration_delay.timeout_seconds - Value: "20" - Targets: - - Id: !Ref AiUnlimitedServer - Port: !Ref AiUnlimitedGrpcPort - VpcId: !Ref Vpc - - AiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedAuthPort - ToPort: !Ref AiUnlimitedAuthPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedGrpcPort - ToPort: !Ref AiUnlimitedGrpcPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiPort - ToPort: !Ref AiUnlimitedUiPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiHttpsPort - ToPort: !Ref AiUnlimitedUiHttpsPort - SourceSecurityGroupId: !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedAuthPort - ToPort: !Ref AiUnlimitedAuthPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedGrpcPort - ToPort: !Ref AiUnlimitedGrpcPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiPort - ToPort: !Ref AiUnlimitedUiPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedUiHttpsPort - ToPort: !Ref AiUnlimitedUiHttpsPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - AiUnlimitedSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - SourceSecurityGroupId: !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerHttpPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerHttpPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - !If - - HASSECURITYGROUP - - IpProtocol: tcp - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - ToPort: !Ref AiUnlimitedSchedulerHttpPort - SourceSecurityGroupId: !Ref SecurityGroup - - !Ref AWS::NoValue - - JupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to jupyter server over http - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref JupyterHttpPort - ToPort: !Ref JupyterHttpPort - SourceSecurityGroupId: !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - - FromPort: !Ref JupyterHttpPort - IpProtocol: tcp - ToPort: !Ref JupyterHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - SecurityGroupIngress: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !GetAtt AiUnlimitedSecurityGroup.GroupId - FromPort: 22 - IpProtocol: tcp - ToPort: 22 - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASKEYANDCIDRORPREFIXLISTORSECGROUP - - AiUnlimitedRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - Path: / - RoleName: !If - - HASIAMROLENAME - - !Ref IamRoleName - - !Ref AWS::NoValue - PermissionsBoundary: !If - - HASIAMPERMISSIONSBOUNDARY - - !Ref IamPermissionsBoundary - - !Ref AWS::NoValue - Condition: NEEDSROLE - - SessionManagerPolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - session - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ssm:DescribeAssociation - - ssm:GetDeployablePatchSnapshotForInstance - - ssm:GetDocument - - ssm:DescribeDocument - - ssm:GetManifest - - ssm:ListAssociations - - ssm:ListInstanceAssociations - - ssm:PutInventory - - ssm:PutComplianceItems - - ssm:PutConfigurePackageResult - - ssm:UpdateAssociationStatus - - ssm:UpdateInstanceAssociationStatus - - ssm:UpdateInstanceInformation - Resource: '*' - - Effect: Allow - Action: - - ssmmessages:CreateControlChannel - - ssmmessages:CreateDataChannel - - ssmmessages:OpenControlChannel - - ssmmessages:OpenDataChannel - Resource: '*' - - Effect: Allow - Action: - - ec2messages:AcknowledgeMessage - - ec2messages:DeleteMessage - - ec2messages:FailMessage - - ec2messages:GetEndpoint - - ec2messages:GetMessages - - ec2messages:SendReply - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLEANDSESSIONMANAGER - - AiUnlimitedRolePolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - deploy - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - iam:PassRole - - iam:AddRoleToInstanceProfile - - iam:CreateInstanceProfile - - iam:CreateRole - - iam:DeleteInstanceProfile - - iam:DeleteRole - - iam:DeleteRolePolicy - - iam:GetInstanceProfile - - iam:GetRole - - iam:GetRolePolicy - - iam:ListAttachedRolePolicies - - iam:ListInstanceProfilesForRole - - iam:ListRolePolicies - - iam:PutRolePolicy - - iam:RemoveRoleFromInstanceProfile - - iam:TagRole - - iam:TagInstanceProfile - - ec2:TerminateInstances - - ec2:RunInstances - - ec2:RevokeSecurityGroupEgress - - ec2:ModifyInstanceAttribute - - ec2:ImportKeyPair - - ec2:DescribeVpcs - - ec2:DescribeVolumes - - ec2:DescribeTags - - ec2:DescribeSubnets - - ec2:DescribeSecurityGroups - - ec2:DescribePlacementGroups - - ec2:DescribeNetworkInterfaces - - ec2:DescribeLaunchTemplates - - ec2:DescribeLaunchTemplateVersions - - ec2:DescribeKeyPairs - - ec2:DescribeInstanceTypes - - ec2:DescribeInstanceTypeOfferings - - ec2:DescribeInstances - - ec2:DescribeInstanceAttribute - - ec2:DescribeImages - - ec2:DescribeAccountAttributes - - ec2:DescribeAvailabilityZones - - ec2:DescribeManagedPrefixLists - - ec2:DescribeVpcAttribute - - ec2:DeleteTags - - ec2:DeleteSecurityGroup - - ec2:DeletePlacementGroup - - ec2:DeleteLaunchTemplate - - ec2:DeleteLaunchTemplateVersions - - ec2:DeleteKeyPair - - ec2:CreateTags - - ec2:CreateSecurityGroup - - ec2:CreatePlacementGroup - - ec2:CreateLaunchTemplateVersion - - ec2:CreateLaunchTemplate - - ec2:AuthorizeSecurityGroupIngress - - ec2:AuthorizeSecurityGroupEgress - - secretsmanager:CreateSecret - - secretsmanager:DeleteSecret - - secretsmanager:DescribeSecret - - secretsmanager:GetResourcePolicy - - secretsmanager:GetSecretValue - - secretsmanager:PutSecretValue - - secretsmanager:TagResource - - s3:CreateBucket - - s3:DeleteBucket - - s3:PutObject - - s3:GetObject - - s3:DeleteObject - - cloudformation:CreateStack - - cloudformation:DeleteStack - - cloudformation:DescribeStacks - - cloudformation:ListStacks - - cloudformation:DescribeStackEvents - - ssm:PutParameter - - ssm:GetParameter - - ssm:DeleteParameter - - ec2:RevokeSecurityGroupIngress - - ec2:CreateInternetGateway - - ec2:CreateVpc - - ec2:DescribeInternetGateways - - ec2:DeleteVpc - - ec2:ModifyVpcAttribute - - ec2:DeleteInternetGateway - - ec2:CreateSubnet - - ec2:CreateRouteTable - - ec2:DescribeRouteTables - - ec2:DeleteSubnet - - ec2:DeleteRouteTable - - ec2:AttachInternetGateway - - ec2:ModifySubnetAttribute - - ec2:DetachInternetGateway - - ec2:AssociateRouteTable - - ec2:CreateRoute - - ec2:DisassociateRouteTable - - ec2:DeleteRoute - - ec2:DescribeAddresses - - ec2:AssociateAddress - - ec2:DisassociateAddress - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLE - - AiUnlimitedInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: !If - - NEEDSROLE - - - !Ref AiUnlimitedRole - - - !Ref IamRoleName - -Outputs: - PublicIP: - Description: EC2 public IP - Value: !GetAtt AiUnlimitedServer.PublicIp - Condition: HASPUBLICIP - - PrivateIP: - Description: EC2 private IP - Value: !GetAtt AiUnlimitedServer.PrivateIp - - AiUnlimitedUiAccess: - Description: Loadbalancer access endpoint for AI Unlimited UI Access - Value: !If - - PortIsNotEighty - - !Sub http://${ LoadBalancer.DNSName }:${ AiUnlimitedUiPort }/healthcheck - - !Sub http://${ LoadBalancer.DNSName } - - AiUnlimitedApiAccess: - Description: Loadbalancer access endpoint for AI Unlimited API Access - Value: !Sub ${ LoadBalancer.DNSName }:${ AiUnlimitedGrpcPort } - - InstanceSecurityGroups: - Description: AI Unlimited Security Groups - Value: !Join - - ', ' - - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - !GetAtt JupyterSecurityGroup.GroupId - - LoadBalancerSecurityGroups: - Description: AI Unlimited Load Balancer Security Group - Value: !Join - - ', ' - - - !GetAtt LoadBalancerAiUnlimitedSecurityGroup.GroupId - - !GetAtt LoadBalancerSchedulerSecurityGroup.GroupId - - !GetAtt LoadBalancerJupyterSecurityGroup.GroupId - - PublicSSHConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PublicIp } - Condition: HASKEYANDPUBLIC - - PrivateSSHConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PrivateIp } - Condition: HASKEY - - PersistentVolumeId: - Description: Id of the new persistent volume created for AI Unlimited - Value: !Ref AiUnlimitedVolume - Condition: USENEWPERSISTENTVOLUME - - JupyterUIAccess: - Description: Loadbalancer access endpoint for API Access - Value: !Sub http://${ LoadBalancer.DNSName }:${ JupyterHttpPort }?token=${ JupyterToken } - - JupyterInternalAccessToAiUnlimited: - Description: AI Unlimited endpoint for local Jupyter access - Value: !Sub ai-unlimited.service:${ AiUnlimitedGrpcPort } diff --git a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml b/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml deleted file mode 100644 index 3be4131..0000000 --- a/deployments/aws/templates/all-in-one/all-in-one-without-lb.yaml +++ /dev/null @@ -1,1160 +0,0 @@ -AWSTemplateFormatVersion: "2010-09-09" - -Description: 'AWS CloudFormation Template with AI Unlimited with Jupyter: AI Unlimited is a instance based service for deploying and suspending ai-unlimited clusters, and managing project lifecycles. This template also includes a Jupyter Lab service running on the same host, suitable for demonstration environments. Note: You will be billed for the AWS resources used if you create a stack from this template.' - -Metadata: - AWS::CloudFormation::Interface: - ParameterGroups: - - Label: - default: AI Unlimited - Parameters: - - AiUnlimitedName - - InstanceType - - RootVolumeSize - - TerminationProtection - - IamRole - - IamRoleName - - IamPermissionsBoundary - - Label: - default: AI Unlimited connection - Parameters: - - AvailabilityZone - - Private - - Session - - Vpc - - Subnet - - KeyName - - AccessCIDR - - PrefixList - - SecurityGroup - - AiUnlimitedAuthPort - - AiUnlimitedGrpcPort - - AiUnlimitedVersion - - AiUnlimitedSchedulerVersion - - AiUnlimitedSchedulerHttpPort - - AiUnlimitedSchedulerGrpcPort - - AiUnlimitedUiPort - - AiUnlimitedUiHttpsPort - - AiUnlimitedUiVersion - - Label: - default: Persistent volume - Parameters: - - UsePersistentVolume - - PersistentVolumeSize - - ExistingPersistentVolumeId - - PersistentVolumeDeletionPolicy - - Label: - default: Jupyter connection - Parameters: - - JupyterToken - - JupyterHttpPort - - JupyterVersion - -Parameters: - LatestAmiId: - Type: AWS::SSM::Parameter::Value - Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 - - AiUnlimitedName: - Description: The AI Unlimited instance name - Type: String - Default: ai-unlimited - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "20" - MinLength: "1" - - JupyterToken: - Description: The token or password equivalent used to access Jupyter. - Type: String - NoEcho: true - AllowedPattern: ^[a-zA-Z][a-zA-Z0-9-]* - ConstraintDescription: must begin with a letter and contain only alphanumeric characters. - MaxLength: "64" - - Private: - Description: Will AI Unlimited be deployed in a private network without public IPs? - Type: String - AllowedValues: - - true - - false - Default: false - - Session: - Description: Should AI Unlimited be accessible via AWS Session Manager? - Type: String - AllowedValues: - - true - - false - Default: false - - Vpc: - Description: Network to deploy the AI Unlimited to. - Type: AWS::EC2::VPC::Id - ConstraintDescription: must be the name of an existing vpc. - - Subnet: - Description: Subnetwork to deploy the AI Unlimited to. - Type: AWS::EC2::Subnet::Id - ConstraintDescription: must be the name of a existing subnet. - - AvailabilityZone: - Description: "Availability zone to deploy the AI Unlimited to.\nThis must match the subnet, the zone of any pre existing volumes if used, \nand the instance type must be available in the selected zone.\n" - Type: AWS::EC2::AvailabilityZone::Name - ConstraintDescription: must be the name of a existing subnet. - - AiUnlimitedAuthPort: - Description: port to access the AI Unlimited Authentication Service. - Type: Number - Default: 3000 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedGrpcPort: - Description: port to access the AI Unlimited API. - Type: Number - Default: 3282 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerHttpPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50061 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedSchedulerGrpcPort: - Description: port to access the AI Unlimited Scheduler API. - Type: Number - Default: 50051 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedUiPort: - Description: port to access the AI Unlimited UI. - Type: Number - Default: 80 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedUiHttpsPort: - Description: port to allow https access the AI Unlimited UI. - Type: Number - Default: 443 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - AiUnlimitedVersion: - Description: Which version of AI Unlimited to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.3.0 - - AiUnlimitedSchedulerVersion: - Description: Which version of AI Unlimited Scheduler to deploy, uses container version tags, defaults to "latest" - Type: String - Default: latest - - AiUnlimitedUiVersion: - Description: Which version of AI Unlimited UI to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.1.0 - - JupyterHttpPort: - Description: port to access the Jupyter UI. - Type: Number - Default: 8888 - ConstraintDescription: must be a valid ununsed port between 0 and 65535. - MinValue: 0 - MaxValue: 65535 - - JupyterVersion: - Description: Which version of Jupyter to deploy, uses container version tags, defaults to "latest" - Type: String - Default: v0.1.0 - - RootVolumeSize: - Description: size of the root disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - UsePersistentVolume: - Description: Should we use a new or existing volume for persistent data on the AI Unlimited server. - Type: String - AllowedValues: - - New - - Existing - Default: New - ConstraintDescription: Specify if you are using a a new persistent volume, an existing one, or none. - - PersistentVolumeSize: - Description: size of the optional persistent disk to the AI Unlimited server. - Type: Number - Default: 20 - ConstraintDescription: Size in GB, between 10 and 1000. - MinValue: 8 - MaxValue: 1000 - - ExistingPersistentVolumeId: - Description: Id of the existing persistent volume to attach. Must be in the same availability zone as the AI Unlimited instance. - Type: String - Default: None - - PersistentVolumeDeletionPolicy: - Description: Behavior for the Persistent Volume when deleting the cloudformations deployment. - Type: String - AllowedValues: - - Delete - - Retain - - RetainExceptOnCreate - - Snapshot - Default: Retain - - TerminationProtection: - Description: Enable instance termination protection. - Type: String - AllowedValues: - - true - - false - Default: false - - InstanceType: - Description: AI Unlimited EC2 instance type - Type: String - AllowedValues: - - t3.small - - t3.medium - - t3.large - - m4.large - - m4.xlarge - - m4.2xlarge - - m4.4xlarge - - m4.10xlarge - - c4.large - - c4.xlarge - - c4.2xlarge - - c4.4xlarge - - c4.8xlarge - - r3.large - - r3.xlarge - - r3.2xlarge - - r3.4xlarge - - r3.8xlarge - - i2.xlarge - - i2.2xlarge - - i2.4xlarge - - i2.8xlarge - Default: t3.small - ConstraintDescription: must be a valid EC2 instance type. - - KeyName: - Description: Name of an existing EC2 KeyPair to enable SSH access to the AI Unlimited instance, leave empty if no ssh keys should be included - Type: String - - IamRole: - Description: | - Create a new IAM role for AI Unlimited or use an exiting one. - Requires CAPABILITY_IAM if creating a new IAM Role - Type: String - AllowedValues: - - New - - Existing - Default: New - - IamRoleName: - Description: | - Name of an existing IAM Role to assign to AI Unlimited, - or the name to give to the newly created role. - Leave blank to use an autogenerated name. - Requires CAPABILITY_NAMED_IAM if naming a new IAM Role. - Type: String - - IamPermissionsBoundary: - Description: | - Optional: Arn of a permissions boundary to pass to the IAM Role assigned to AI Unlimited. - Type: String - - AccessCIDR: - Description: The IP address range that can be used to communicate with the AI Unlimited instance. - Type: String - 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. - - PrefixList: - Description: The PrefixList that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid prefixlist - - SecurityGroup: - Description: The SecurityGroup that can be used to communicate with the AI Unlimited instance. - Type: String - ConstraintDescription: must be a valid securityGroup ID - -Rules: - subnetsInVpc: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - - instanceTypeInZone: - Assertions: - - Assert: - Fn::EachMemberEquals: - - Fn::ValueOfAll: - - AWS::EC2::Subnet::Id - - VpcId - - !Ref Vpc - AssertDescription: The subnet you selected is not in the VPC - -Conditions: - NEEDSROLE: !Equals - - !Ref IamRole - - New - - HASPUBLICIP: !Not - - !Equals - - !Ref Private - - "true" - - HASKEY: !Not - - !Equals - - !Ref KeyName - - "" - - HASCIDR: !Not - - !Equals - - !Ref AccessCIDR - - "" - - HASPREFIXLIST: !Not - - !Equals - - !Ref PrefixList - - "" - - HASSECURITYGROUP: !Not - - !Equals - - !Ref SecurityGroup - - "" - - HASCIDRORPREFIXLIST: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - HASCIDRORPREFIXLISTORSECGROUP: !Or - - !Condition HASCIDR - - !Condition HASPREFIXLIST - - !Condition HASSECURITYGROUP - - USESESSIONMANAGER: !Equals - - !Ref Session - - "true" - - NEEDSROLEANDSESSIONMANAGER: !And - - !Condition NEEDSROLE - - !Condition USESESSIONMANAGER - - HASKEYANDPUBLIC: !And - - !Condition HASKEY - - !Condition HASPUBLICIP - - HASKEYANDCIDRORPREFIXLISTORSECGROUP: !And - - !Condition HASKEY - - !Condition HASCIDRORPREFIXLISTORSECGROUP - - USENEWPERSISTENTVOLUME: !Equals - - !Ref UsePersistentVolume - - New - - HASIAMPERMISSIONSBOUNDARY: !Not - - !Equals - - !Ref IamPermissionsBoundary - - "" - - HASIAMROLENAME: !Not - - !Equals - - !Ref IamRoleName - - "" - - PortIsNotEightyAndHasPublicIp: !And - - !Not - - !Equals - - !Ref Private - - "true" - - !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - - PortIsNotEighty: !Not - - !Equals - - !Ref AiUnlimitedUiPort - - 80 - -Resources: - AiUnlimitedVolume: - DeletionPolicy: !Ref PersistentVolumeDeletionPolicy - Type: AWS::EC2::Volume - Properties: - AvailabilityZone: !Ref AvailabilityZone - Size: !Ref PersistentVolumeSize - Encrypted: true - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - - Key: Usage - Value: persistent storage - Condition: USENEWPERSISTENTVOLUME - - AiUnlimitedServer: - CreationPolicy: - ResourceSignal: - Timeout: PT15M - Type: AWS::EC2::Instance - Metadata: - AWS::CloudFormation::Init: - configSets: - ai_unlimited_install: - - prepare_directory - - !If - - USENEWPERSISTENTVOLUME - - prepare_new_storage - - !Ref AWS::NoValue - - bind_storage - - mount_storage - - create_ai_unlimited_folder - - create_init_api_key - - install_docker - - configure_ai_unlimited_ui_service - - configure_ai_unlimited_service - - start_ai_unlimited_ui_service - - start_ai_unlimited_service - - configure_jupyter_service - - configure_ai_unlimited_scheduler_service - - start_ai_unlimited_scheduler_service - - start_jupyter_service - prepare_directory: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - mkdir -p /etc/td - prepare_new_storage: - commands: - mkfs: - command: !Sub | - #!/bin/bash -xe - /usr/sbin/mkfs -t ext4 /dev/nvme1n1 - bind_storage: - commands: - fstab: - command: !Sub | - #!/bin/bash -xe - /usr/bin/echo "/dev/nvme1n1 /etc/td ext4 defaults 0 2" >> /etc/fstab - mount_storage: - commands: - mount: - command: !Sub | - #!/bin/bash -xe - /usr/bin/mount -a - create_ai_unlimited_folder: - commands: - mkdir: - command: !Sub | - #!/bin/bash -xe - mkdir -p /etc/td/ai-unlimited - create_init_api_key: - commands: - run_command: - command: !Sub | - #!/bin/bash -xe - echo "TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt - install_docker: - files: - /usr/lib/systemd/system/docker-install.service: - content: !Sub | - [Unit] - Description=Install docker - - [Service] - Type=oneshot - ExecStart=/bin/bash -c "while ! dnf update; do sleep 2; done && while ! dnf install -y docker; do sleep 2; done" - RemainAfterExit=yes - - [Install] - WantedBy=multi-user.target - commands: - verify_docker: - command: !Sub | - #!/bin/bash -xe - systemctl start docker-install - systemctl start docker - systemctl enable docker - services: - systemd: - docker: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_ui_service: - files: - /usr/lib/systemd/system/ai-unlimited-ui.service: - content: !Sub | - [Unit] - Description=ai-unlimited-ui - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - - ExecStartPre=-/bin/bash -c '/usr/bin/docker volume create ssl_certs || true' - ExecStartPre=-/bin/bash -c '/usr/bin/docker network create -d bridge ai_unlimited || true' - ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited-ui - EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ - -e TD_VCD_USE_TLS=false \ - -e TD_VCD_API_PORT=${ AiUnlimitedGrpcPort } \ - -e TD_VCD_AUTH_PORT=${ AiUnlimitedAuthPort } \ - -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedUiPort }:80 \ - -p ${ AiUnlimitedUiHttpsPort }:443 \ - -v ssl_certs:/etc/ssl/td \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-workspaces-ui:${ AiUnlimitedUiVersion } - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_ui_service: - services: - systemd: - ai-unlimited-ui: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_service: - files: - /usr/lib/systemd/system/ai-unlimited.service: - content: !Sub | - [Unit] - Description=AI Unlimited - After=docker.service - Requires=docker.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited - EnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e PLATFORM=aws \ - -e TD_VCD_INIT_API_KEY \ - -p ${ AiUnlimitedAuthPort }:3000 \ - -p ${ AiUnlimitedGrpcPort }:3282 \ - -v /etc/td/ai-unlimited:/etc/td \ - -v ssl_certs:/etc/td/ssl \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-workspaces:${ AiUnlimitedVersion } workspaces serve -v - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_service: - services: - systemd: - ai-unlimited: - enabled: "true" - ensureRunning: "true" - configure_ai_unlimited_scheduler_service: - files: - /usr/lib/systemd/system/ai-unlimited-scheduler.service: - content: !Sub | - [Unit] - Description=AI Unlimited Scheduler - After=ai-unlimited.service - Requires=ai-unlimited.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-scheduler:latest - ExecStart=/usr/bin/docker run \ - --network ai_unlimited \ - -p ${ AiUnlimitedSchedulerGrpcPort }:50051 \ - -p ${ AiUnlimitedSchedulerHttpPort }:50061 \ - -v /etc/td/ai-unlimited:/etc/td \ - -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \ - -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \ - -e TD_WSSCHED_POL_INTERVAL=2 \ - -e TD_WS_CONTAINER_NAME=ai-unlimited.service \ - --rm --name %n teradata/ai-unlimited-scheduler:latest workspace-event-scheduler serve - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_ai_unlimited_scheduler_service: - services: - systemd: - ai-unlimited-scheduler: - enabled: "true" - ensureRunning: "true" - configure_jupyter_service: - files: - /usr/lib/systemd/system/jupyter.service: - content: !Sub | - [Unit] - Description=jupyter - After=ai-unlimited.service - Requires=ai-unlimited.service - StartLimitInterval=200 - StartLimitBurst=10 - - [Service] - TimeoutStartSec=0 - Restart=always - RestartSec=2 - ExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{userdata,ipython} - ExecStartPre=-/usr/bin/docker stop %n || true - ExecStartPre=-/usr/bin/docker rm %n || true - ExecStartPre=/usr/bin/docker pull teradata/ai-unlimited-jupyter:${ JupyterVersion } - ExecStart=/usr/bin/docker run \ - -e accept_license=Y \ - -e JUPYTER_TOKEN=${ JupyterToken } \ - -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \ - -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \ - -p ${ JupyterHttpPort }:8888 \ - --network ai_unlimited \ - --rm --name %n teradata/ai-unlimited-jupyter:${ JupyterVersion } - - [Install] - WantedBy=multi-user.target - group: root - mode: "000400" - owner: root - start_jupyter_service: - services: - systemd: - jupyter: - enabled: "true" - ensureRunning: "true" - Properties: - PropagateTagsToVolumeOnCreation: true - BlockDeviceMappings: - - DeviceName: /dev/xvda - Ebs: - VolumeSize: !Ref RootVolumeSize - Encrypted: true - NetworkInterfaces: - - DeviceIndex: 0 - SubnetId: !Ref Subnet - GroupSet: - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - !GetAtt JupyterSecurityGroup.GroupId - AssociatePublicIpAddress: !If - - HASPUBLICIP - - true - - !Ref AWS::NoValue - ImageId: !Ref LatestAmiId - InstanceType: !Ref InstanceType - KeyName: !If - - HASKEY - - !Ref KeyName - - !Ref AWS::NoValue - DisableApiTermination: !Ref TerminationProtection - IamInstanceProfile: !Ref AiUnlimitedInstanceProfile - Volumes: - - Device: /dev/xvdb - VolumeId: !If - - USENEWPERSISTENTVOLUME - - !Ref AiUnlimitedVolume - - !Ref ExistingPersistentVolumeId - Tags: - - Key: Name - Value: !Join - - '-' - - - !Ref AiUnlimitedName - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - UserData: !Base64 - Fn::Sub: | - #!/bin/bash -xe - yum update -y - yum update -y aws-cfn-bootstrap - /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource AiUnlimitedServer --configsets ai_unlimited_install --region ${AWS::Region} - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource AiUnlimitedServer --region ${AWS::Region} - - AiUnlimitedSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedAuthPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedAuthPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedUiHttpsPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedUiHttpsPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - AiUnlimitedSchedulerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to AI Unlimited server over http and grpc - SecurityGroupIngress: - - FromPort: !Ref AiUnlimitedSchedulerHttpPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - FromPort: !Ref AiUnlimitedSchedulerGrpcPort - IpProtocol: tcp - ToPort: !Ref AiUnlimitedSchedulerGrpcPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - - JupyterSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref Vpc - GroupDescription: Enable access to jupyter server over http - SecurityGroupIngress: - - FromPort: !Ref JupyterHttpPort - IpProtocol: tcp - ToPort: !Ref JupyterHttpPort - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASCIDRORPREFIXLISTORSECGROUP - - SecurityGroupIngress: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !GetAtt AiUnlimitedSecurityGroup.GroupId - FromPort: 22 - IpProtocol: tcp - ToPort: 22 - CidrIp: !If - - HASCIDR - - !Ref AccessCIDR - - !Ref AWS::NoValue - SourcePrefixListId: !If - - HASPREFIXLIST - - !Ref PrefixList - - !Ref AWS::NoValue - SourceSecurityGroupId: !If - - HASSECURITYGROUP - - !Ref SecurityGroup - - !Ref AWS::NoValue - Condition: HASKEYANDCIDRORPREFIXLISTORSECGROUP - - AiUnlimitedRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Principal: - Service: - - ec2.amazonaws.com - Action: - - sts:AssumeRole - Path: / - RoleName: !If - - HASIAMROLENAME - - !Ref IamRoleName - - !Ref AWS::NoValue - PermissionsBoundary: !If - - HASIAMPERMISSIONSBOUNDARY - - !Ref IamPermissionsBoundary - - !Ref AWS::NoValue - Condition: NEEDSROLE - - SessionManagerPolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - session - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - ssm:DescribeAssociation - - ssm:GetDeployablePatchSnapshotForInstance - - ssm:GetDocument - - ssm:DescribeDocument - - ssm:GetManifest - - ssm:ListAssociations - - ssm:ListInstanceAssociations - - ssm:PutInventory - - ssm:PutComplianceItems - - ssm:PutConfigurePackageResult - - ssm:UpdateAssociationStatus - - ssm:UpdateInstanceAssociationStatus - - ssm:UpdateInstanceInformation - Resource: '*' - - Effect: Allow - Action: - - ssmmessages:CreateControlChannel - - ssmmessages:CreateDataChannel - - ssmmessages:OpenControlChannel - - ssmmessages:OpenDataChannel - Resource: '*' - - Effect: Allow - Action: - - ec2messages:AcknowledgeMessage - - ec2messages:DeleteMessage - - ec2messages:FailMessage - - ec2messages:GetEndpoint - - ec2messages:GetMessages - - ec2messages:SendReply - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLEANDSESSIONMANAGER - - AiUnlimitedRolePolicies: - Type: AWS::IAM::Policy - Properties: - PolicyName: !Join - - '-' - - - ai-unlimited - - deploy - - !Select - - 4 - - !Split - - '-' - - !Select - - 2 - - !Split - - / - - !Ref AWS::StackId - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - iam:PassRole - - iam:AddRoleToInstanceProfile - - iam:CreateInstanceProfile - - iam:CreateRole - - iam:DeleteInstanceProfile - - iam:DeleteRole - - iam:DeleteRolePolicy - - iam:GetInstanceProfile - - iam:GetRole - - iam:GetRolePolicy - - iam:ListAttachedRolePolicies - - iam:ListInstanceProfilesForRole - - iam:ListRolePolicies - - iam:PutRolePolicy - - iam:RemoveRoleFromInstanceProfile - - iam:TagRole - - iam:TagInstanceProfile - - ec2:TerminateInstances - - ec2:RunInstances - - ec2:RevokeSecurityGroupEgress - - ec2:ModifyInstanceAttribute - - ec2:ImportKeyPair - - ec2:DescribeVpcs - - ec2:DescribeVolumes - - ec2:DescribeTags - - ec2:DescribeSubnets - - ec2:DescribeSecurityGroups - - ec2:DescribePlacementGroups - - ec2:DescribeNetworkInterfaces - - ec2:DescribeLaunchTemplates - - ec2:DescribeLaunchTemplateVersions - - ec2:DescribeKeyPairs - - ec2:DescribeInstanceTypes - - ec2:DescribeInstanceTypeOfferings - - ec2:DescribeInstances - - ec2:DescribeInstanceAttribute - - ec2:DescribeImages - - ec2:DescribeAccountAttributes - - ec2:DescribeAvailabilityZones - - ec2:DescribeManagedPrefixLists - - ec2:DescribeVpcAttribute - - ec2:DeleteTags - - ec2:DeleteSecurityGroup - - ec2:DeletePlacementGroup - - ec2:DeleteLaunchTemplate - - ec2:DeleteLaunchTemplateVersions - - ec2:DeleteKeyPair - - ec2:CreateTags - - ec2:CreateSecurityGroup - - ec2:CreatePlacementGroup - - ec2:CreateLaunchTemplateVersion - - ec2:CreateLaunchTemplate - - ec2:AuthorizeSecurityGroupIngress - - ec2:AuthorizeSecurityGroupEgress - - secretsmanager:CreateSecret - - secretsmanager:DeleteSecret - - secretsmanager:DescribeSecret - - secretsmanager:GetResourcePolicy - - secretsmanager:GetSecretValue - - secretsmanager:PutSecretValue - - secretsmanager:TagResource - - s3:CreateBucket - - s3:DeleteBucket - - s3:PutObject - - s3:GetObject - - s3:DeleteObject - - cloudformation:CreateStack - - cloudformation:DeleteStack - - cloudformation:DescribeStacks - - cloudformation:ListStacks - - cloudformation:DescribeStackEvents - - ssm:PutParameter - - ssm:GetParameter - - ssm:DeleteParameter - - ec2:RevokeSecurityGroupIngress - - ec2:CreateInternetGateway - - ec2:CreateVpc - - ec2:DescribeInternetGateways - - ec2:DeleteVpc - - ec2:ModifyVpcAttribute - - ec2:DeleteInternetGateway - - ec2:CreateSubnet - - ec2:CreateRouteTable - - ec2:DescribeRouteTables - - ec2:DeleteSubnet - - ec2:DeleteRouteTable - - ec2:AttachInternetGateway - - ec2:ModifySubnetAttribute - - ec2:DetachInternetGateway - - ec2:AssociateRouteTable - - ec2:CreateRoute - - ec2:DisassociateRouteTable - - ec2:DeleteRoute - - ec2:DescribeAddresses - - ec2:AssociateAddress - - ec2:DisassociateAddress - Resource: '*' - Roles: - - !Ref AiUnlimitedRole - Condition: NEEDSROLE - - AiUnlimitedInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: !If - - NEEDSROLE - - - !Ref AiUnlimitedRole - - - !Ref IamRoleName - -Outputs: - PublicIP: - Description: EC2 public IP - Value: !GetAtt AiUnlimitedServer.PublicIp - Condition: HASPUBLICIP - - PrivateIP: - Description: EC2 private IP - Value: !GetAtt AiUnlimitedServer.PrivateIp - - AiUnlimitedPublicUIAccess: - Description: Teradata AI Unlimited public UI Access - Value: !Sub http://${AiUnlimitedServer.PublicDnsName} - Condition: HASPUBLICIP - - AiUnlimitedPrivateUIAccess: - Description: Teradata AI Unlimited private UI Access - Value: !Sub http://${AiUnlimitedServer.PrivateDnsName} - - AiUnlimitedPublicAPIAccess: - Description: Teradata AI Unlimited public API Access - Value: !Sub http://${AiUnlimitedServer.PublicDnsName}:${ AiUnlimitedGrpcPort } - Condition: HASPUBLICIP - - AiUnlimitedPrivateAPIAccess: - Description: Teradata AI Unlimited private API Access - Value: !Sub http://${AiUnlimitedServer.PrivateDnsName}:${ AiUnlimitedGrpcPort } - - InstanceSecurityGroups: - Description: AI Unlimited Security Group - Value: !Join - - ', ' - - - !GetAtt AiUnlimitedSecurityGroup.GroupId - - !GetAtt AiUnlimitedSchedulerSecurityGroup.GroupId - - !GetAtt JupyterSecurityGroup.GroupId - - PublicSSHConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PublicIp } - Condition: HASKEYANDPUBLIC - - PrivateSSHConeection: - Description: AI Unlimited ssh connnection string - Value: !Sub ssh ec2-user@${ AiUnlimitedServer.PrivateIp } - Condition: HASKEY - - PersistentVolumeId: - Description: Id of the new persistent volume created for AI Unlimited - Value: !Ref AiUnlimitedVolume - Condition: USENEWPERSISTENTVOLUME - - JupyterPublicHttpAccess: - Description: Teradata AI Unlimited Server - Value: !Sub http://${AiUnlimitedServer.PublicDnsName}:${ JupyterHttpPort }?token=${ JupyterToken } - Condition: HASPUBLICIP - - JupyterPrivateHttpAccess: - Description: Teradata jupyter Server - Value: !Sub http://${AiUnlimitedServer.PrivateDnsName}:${ JupyterHttpPort }?token=${ JupyterToken } - - JupyterInternalAccessToAiUnlimited: - Description: AI Unlimited endpoint for local Jupyter access - Value: !Sub ai-unlimited.service:${ AiUnlimitedGrpcPort } diff --git a/deployments/aws/templates/all-in-one/readme.txt b/deployments/aws/templates/all-in-one/readme.txt deleted file mode 100644 index 5d795a4..0000000 --- a/deployments/aws/templates/all-in-one/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Disclaimer - -**IMPORTANT NOTICE** - -The all-in-one CloudFormation templates provided in this directory are for informational purposes only. These templates are currently not supported by Teradata Corporation. - -**Use of these templates is at your own risk. Teradata Corporation assumes no responsibility or liability for any damages or issues that may arise from using these templates.** \ No newline at end of file diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json deleted file mode 100644 index 462abaf..0000000 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-with-nlb.json +++ /dev/null @@ -1,1741 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "7316600174603488782" - } - }, - "parameters": { - "ResourceGroupName": { - "type": "string", - "defaultValue": "ai-unlimited-workspace", - "metadata": { - "description": "name for the resource group." - } - }, - "AiUnlimitedName": { - "type": "string", - "metadata": { - "description": "Name for the Workspace service's virtual machine." - } - }, - "OSVersion": { - "type": "string", - "defaultValue": "Ubuntu-2004", - "allowedValues": [ - "Ubuntu-1804", - "Ubuntu-2004", - "Ubuntu-2204" - ], - "metadata": { - "description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version." - } - }, - "InstanceType": { - "type": "string", - "defaultValue": "Standard_D2s_v3", - "metadata": { - "description": "The AI Unlimited VM type" - } - }, - "Network": { - "type": "string", - "metadata": { - "description": "Name of the network to run the AI Unlimited service in" - } - }, - "Subnet": { - "type": "string", - "metadata": { - "description": "Name of the subnet to run the AI Unlimited service in" - } - }, - "SecurityGroup": { - "type": "string", - "defaultValue": "AiUnlimitedSecurityGroup", - "metadata": { - "description": "Name of the network security group" - } - }, - "AccessCIDRs": { - "type": "array", - "defaultValue": [ - "0.0.0.0/0" - ], - "metadata": { - "description": "The CIDR ranges that can be used to communicate with the AI Unlimited service instance." - } - }, - "JupyterHttpPort": { - "type": "int", - "defaultValue": 8888, - "metadata": { - "description": "port to access the Jupyter Labs UI." - } - }, - "AiUnlimitedAuthPort": { - "type": "int", - "defaultValue": 3000, - "metadata": { - "description": "port to access the AI Unlimited auth service." - } - }, - "AiUnlimitedGrpcPort": { - "type": "int", - "defaultValue": 3282, - "metadata": { - "description": "port to access the AI Unlimited service api." - } - }, - "SourceAppSecGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Source Application Security Groups to access the AI Unlimited service api." - } - }, - "detinationAppSecGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Destination Application Security Groups to give access to AI Unlimited service instance." - } - }, - "RoleDefinitionId": { - "type": "string", - "metadata": { - "description": "GUID of the AI Unlimited Role" - } - }, - "UseKeyVault": { - "type": "string", - "defaultValue": "New", - "allowedValues": [ - "New", - "None" - ], - "metadata": { - "description": "should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes." - } - }, - "UsePersistentVolume": { - "type": "string", - "defaultValue": "New", - "allowedValues": [ - "New", - "Existing" - ], - "metadata": { - "description": "should we use a new or existing volume for persistent data on the AI Unlimited server." - } - }, - "PersistentVolumeSize": { - "type": "int", - "defaultValue": 100, - "metadata": { - "description": "size of the optional persistent disk to the AI Unlimited server." - } - }, - "ExistingPersistentVolume": { - "type": "string", - "defaultValue": "NONE", - "metadata": { - "description": "Name of the existing persistent volume to attach. Must be in the same region and resourcegroup zone as the AI Unlimited server." - } - }, - "AiUnlimitedVersion": { - "type": "string", - "defaultValue": "v0.3.0", - "metadata": { - "description": "Container Version of the AI Unlimited service" - } - }, - "AiUnlimitedUIVersion": { - "type": "string", - "defaultValue": "v0.1.0", - "metadata": { - "description": "Container Version of the AI Unlimited UI service" - } - }, - "JupyterVersion": { - "type": "string", - "defaultValue": "v0.1.0", - "metadata": { - "description": "Container Version of the Jupyter Labs service" - } - }, - "JupyterToken": { - "type": "securestring", - "metadata": { - "description": "Join token for the Jupyter Labs service" - } - }, - "Tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to all newly created resources, in the form of {\"key_one\":\"value_one\",\"key_two\":\"value_two\"}" - } - } - }, - "variables": { - "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{3}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker volume create ssl_certs\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -v ssl_certs:/etc/td/ssl \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", - "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", - "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", - "AiUnlimitedSchedulerHttpPort": 50061, - "AiUnlimitedUIHttpPort": 80, - "AiUnlimitedUIHttpsPort": 443, - "AiUnlimitedSchedulerVersion": "latest", - "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", - "dnsId": "[uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('AiUnlimitedName'))]", - "dnsLabelPrefix": "[format('td{0}', variables('dnsId'))]", - "nlbDnsLabelPrefix": "[format('td{0}-nlb', variables('dnsId'))]", - "registry": "teradata", - "workspaceRepository": "ai-unlimited-workspaces", - "jupyterRepository": "ai-unlimited-jupyter", - "workspaceSchedulerRepository": "ai-unlimited-scheduler", - "workspaceUIRepository": "ai-unlimited-workspaces-ui" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[variables('roleAssignmentName')]", - "properties": { - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleDefinitionId'))]", - "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrincipleId.value]" - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited')]" - ] - }, - { - "condition": "[equals(parameters('UseKeyVault'), 'New')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "vault", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "encryptVolumes": { - "value": true - }, - "keyVaultName": { - "value": "[parameters('AiUnlimitedName')]" - }, - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "29287785012335710" - } - }, - "parameters": { - "encryptVolumes": { - "type": "bool" - }, - "keyVaultName": { - "type": "string" - }, - "location": { - "type": "string" - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "uuid": { - "type": "string", - "defaultValue": "[newGuid()]" - } - }, - "variables": { - "nameCharLimit": 24, - "uniqueName": "[format('{0}-{1}', parameters('keyVaultName'), uniqueString(parameters('uuid')))]", - "uniqueKeyVaultName": "[substring(format('{0}', variables('uniqueName')), 0, if(less(length(variables('uniqueName')), variables('nameCharLimit')), length(variables('uniqueName')), variables('nameCharLimit')))]" - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "name": "[variables('uniqueKeyVaultName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "sku": { - "family": "A", - "name": "standard" - }, - "tenantId": "[subscription().tenantId]", - "softDeleteRetentionInDays": 7, - "enableSoftDelete": true, - "enablePurgeProtection": "[if(parameters('encryptVolumes'), true(), null())]", - "enabledForDiskEncryption": "[parameters('encryptVolumes')]", - "accessPolicies": [] - } - } - ], - "outputs": { - "id": { - "type": "string", - "value": "[resourceId('Microsoft.KeyVault/vaults', variables('uniqueKeyVaultName'))]" - }, - "name": { - "type": "string", - "value": "[variables('uniqueKeyVaultName')]" - } - } - } - } - }, - { - "condition": "[equals(parameters('UseKeyVault'), 'New')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "vault-access-policy", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "vaultName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" - }, - "accessPolicy": { - "value": { - "tenantId": "[subscription().tenantId]", - "objectId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrincipleId.value]", - "permissions": { - "keys": [ - "Create", - "Delete", - "Get", - "List", - "Update", - "Purge", - "Recover", - "Decrypt", - "Encrypt", - "Sign", - "UnwrapKey", - "Verify", - "WrapKey", - "GetRotationPolicy", - "SetRotationPolicy" - ], - "secrets": [ - "Get", - "Set", - "Delete", - "List", - "Purge" - ], - "storage": [ - "Get" - ] - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "16095084913002426133" - } - }, - "parameters": { - "vaultName": { - "type": "string" - }, - "accessPolicy": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/accessPolicies", - "apiVersion": "2022-07-01", - "name": "[format('{0}/add', parameters('vaultName'))]", - "properties": { - "accessPolicies": [ - "[parameters('accessPolicy')]" - ] - } - } - ] - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "firewall", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "name": { - "value": "[parameters('SecurityGroup')]" - }, - "accessCidrs": { - "value": "[parameters('AccessCIDRs')]" - }, - "sshAccess": { - "value": false - }, - "aiUnlimitedAuthPort": { - "value": "[parameters('AiUnlimitedAuthPort')]" - }, - "aiUnlimitedGrpcPort": { - "value": "[parameters('AiUnlimitedGrpcPort')]" - }, - "aiUnlimitedSchedulerHttpPort": { - "value": "[variables('AiUnlimitedSchedulerHttpPort')]" - }, - "aiUnlimitedUIHttpPort": { - "value": "[variables('AiUnlimitedUIHttpPort')]" - }, - "aiUnlimitedUIHttpsPort": { - "value": "[variables('AiUnlimitedUIHttpsPort')]" - }, - "jupyterHttpPort": { - "value": "[parameters('JupyterHttpPort')]" - }, - "sourceAppSecGroups": { - "value": "[parameters('SourceAppSecGroups')]" - }, - "detinationAppSecGroups": { - "value": "[parameters('detinationAppSecGroups')]" - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "392354314460473239" - } - }, - "parameters": { - "location": { - "type": "string" - }, - "name": { - "type": "string" - }, - "accessCidrs": { - "type": "array", - "defaultValue": [] - }, - "sourceAppSecGroups": { - "type": "array", - "defaultValue": [] - }, - "detinationAppSecGroups": { - "type": "array", - "defaultValue": [] - }, - "sshAccess": { - "type": "bool", - "defaultValue": false - }, - "aiUnlimitedAuthPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedGrpcPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedSchedulerHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 0 - }, - "jupyterHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "uuid": { - "type": "string", - "defaultValue": "[newGuid()]" - } - }, - "variables": { - "nameCharLimit": 60, - "uniqueName": "[format('{0}-{1}', parameters('name'), uniqueString(parameters('uuid')))]", - "uniqueSecurityGroupName": "[substring(format('{0}', variables('uniqueName')), 0, if(less(length(variables('uniqueName')), variables('nameCharLimit')), length(variables('uniqueName')), variables('nameCharLimit')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2022-11-01", - "name": "[variables('uniqueSecurityGroupName')]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]" - }, - { - "condition": "[parameters('sshAccess')]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-ssh-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow ssh to the workspace instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "22", - "direction": "Inbound", - "priority": 700, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the workspace instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", - "direction": "Inbound", - "priority": 701, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedGrpcPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-grpc-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow grpc to the workspace instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedGrpcPort'))]", - "direction": "Inbound", - "priority": 702, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('jupyterHttpPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-juptyer-http-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the jupyter instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('jupyterHttpPort'))]", - "direction": "Inbound", - "priority": 703, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-scheduler-http-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the scheduler instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedSchedulerHttpPort'))]", - "direction": "Inbound", - "priority": 704, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the workspace ui instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", - "direction": "Inbound", - "priority": 705, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow https to the workspace ui instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", - "direction": "Inbound", - "priority": 706, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - } - ], - "outputs": { - "Id": { - "type": "string", - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "loadbalancer", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('AiUnlimitedName')]" - }, - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "dnsPrefix": { - "value": "[variables('dnsLabelPrefix')]" - }, - "aiUnlimitedAuthPort": { - "value": "[parameters('AiUnlimitedAuthPort')]" - }, - "aiUnlimitedGrpcPort": { - "value": "[parameters('AiUnlimitedGrpcPort')]" - }, - "aiUnlimitedSchedulerHttpPort": { - "value": "[variables('AiUnlimitedSchedulerHttpPort')]" - }, - "aiUnlimitedUIHttpPort": { - "value": "[variables('AiUnlimitedUIHttpPort')]" - }, - "aiUnlimitedUIHttpsPort": { - "value": "[variables('AiUnlimitedUIHttpsPort')]" - }, - "jupyterHttpPort": { - "value": "[parameters('JupyterHttpPort')]" - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "370499549708602593" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "dnsPrefix": { - "type": "string" - }, - "aiUnlimitedAuthPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedGrpcPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedSchedulerHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "jupyterHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 0 - }, - "tags": { - "type": "object", - "defaultValue": {} - } - }, - "resources": [ - { - "type": "Microsoft.Network/loadBalancers", - "apiVersion": "2021-08-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" - }, - "properties": { - "frontendIPConfigurations": [ - { - "name": "[format('{0}Inbound', parameters('name'))]", - "properties": { - "publicIPAddress": { - "id": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-inbound', parameters('name'))), '2022-09-01').outputs.Id.value]" - } - } - }, - { - "name": "[format('{0}Outbound', parameters('name'))]", - "properties": { - "publicIPAddress": { - "id": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-outbound', parameters('name'))), '2022-09-01').outputs.Id.value]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "[format('{0}InboundBackendPool', parameters('name'))]" - }, - { - "name": "[format('{0}OutboundBackendPool', parameters('name'))]" - } - ], - "loadBalancingRules": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', 'AiUnlimitedAuth', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedAuthPort'), 'backendPort', parameters('aiUnlimitedAuthPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}AuthLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', 'AiUnlimitedAPI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedGrpcPort'), 'backendPort', parameters('aiUnlimitedGrpcPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}APILbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', 'JupyterUI', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('jupyterHttpPort'), 'backendPort', parameters('jupyterHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}JupyterLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedSchedulerHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'backendPort', parameters('aiUnlimitedSchedulerHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}SchedulerHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttp', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpPort'), 'backendPort', parameters('aiUnlimitedUIHttpPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpLbProbe', parameters('name'))))))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', 'AiUnlimitedUIHttps', 'properties', createObject('frontendIPConfiguration', createObject('id', resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Inbound', parameters('name')))), 'backendAddressPool', createObject('id', resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))), 'frontendPort', parameters('aiUnlimitedUIHttpsPort'), 'backendPort', parameters('aiUnlimitedUIHttpsPort'), 'enableFloatingIP', false(), 'idleTimeoutInMinutes', 15, 'protocol', 'Tcp', 'enableTcpReset', true(), 'loadDistribution', 'Default', 'disableOutboundSnat', true(), 'probe', createObject('id', resourceId('Microsoft.Network/loadBalancers/probes', parameters('name'), format('{0}UIHttpsLbProbe', parameters('name'))))))), createArray())))]", - "probes": "[flatten(createArray(if(not(equals(parameters('aiUnlimitedAuthPort'), 0)), createArray(createObject('name', format('{0}AuthLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedAuthPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedGrpcPort'), 0)), createArray(createObject('name', format('{0}APILbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('aiUnlimitedGrpcPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('jupyterHttpPort'), 0)), createArray(createObject('name', format('{0}JupyterLbProbe', parameters('name')), 'properties', createObject('protocol', 'Tcp', 'port', parameters('jupyterHttpPort'), 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0)), createArray(createObject('name', format('{0}SchedulerHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedSchedulerHttpPort'), 'requestPath', '/healthcheck', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpPort'), 0)), createArray(createObject('name', format('{0}UIHttpLbProbe', parameters('name')), 'properties', createObject('protocol', 'Http', 'port', parameters('aiUnlimitedUIHttpPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray()), if(not(equals(parameters('aiUnlimitedUIHttpsPort'), 0)), createArray(createObject('name', format('{0}UIHttpsLbProbe', parameters('name')), 'properties', createObject('protocol', 'Https', 'port', parameters('aiUnlimitedUIHttpsPort'), 'requestPath', '/', 'intervalInSeconds', 5, 'numberOfProbes', 2))), createArray())))]", - "outboundRules": [ - { - "name": "myOutboundRule", - "properties": { - "allocatedOutboundPorts": 10000, - "protocol": "All", - "enableTcpReset": false, - "idleTimeoutInMinutes": 15, - "backendAddressPool": { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), format('{0}OutboundBackendPool', parameters('name')))]" - }, - "frontendIPConfigurations": [ - { - "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), format('{0}Outbound', parameters('name')))]" - } - ] - } - } - ] - }, - "tags": "[parameters('tags')]", - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-inbound', parameters('name')))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-outbound', parameters('name')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-inbound', parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-inbound', parameters('name'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "dnsPrefix": { - "value": "[parameters('dnsPrefix')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "4325662974998231491" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "dnsPrefix": { - "type": "string" - }, - "tags": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" - }, - "properties": { - "dnsSettings": "[if(not(equals(parameters('dnsPrefix'), '')), createObject('domainNameLabel', parameters('dnsPrefix')), null())]", - "publicIPAddressVersion": "IPv4", - "publicIPAllocationMethod": "Static", - "idleTimeoutInMinutes": 5 - }, - "tags": "[parameters('tags')]" - } - ], - "outputs": { - "Id": { - "type": "string", - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "Ip": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').ipAddress]" - }, - "Dns": { - "type": "string", - "value": "[if(not(equals(parameters('dnsPrefix'), '')), reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').dnsSettings.fqdn, '')]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-outbound', parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-outbound', parameters('name'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "dnsPrefix": { - "value": "" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "4325662974998231491" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "dnsPrefix": { - "type": "string" - }, - "tags": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" - }, - "properties": { - "dnsSettings": "[if(not(equals(parameters('dnsPrefix'), '')), createObject('domainNameLabel', parameters('dnsPrefix')), null())]", - "publicIPAddressVersion": "IPv4", - "publicIPAllocationMethod": "Static", - "idleTimeoutInMinutes": 5 - }, - "tags": "[parameters('tags')]" - } - ], - "outputs": { - "Id": { - "type": "string", - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "Ip": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').ipAddress]" - }, - "Dns": { - "type": "string", - "value": "[if(not(equals(parameters('dnsPrefix'), '')), reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').dnsSettings.fqdn, '')]" - } - } - } - } - } - ], - "outputs": { - "nlbPools": { - "type": "array", - "value": [ - "[format('{0}InboundBackendPool', parameters('name'))]", - "[format('{0}OutboundBackendPool', parameters('name'))]" - ] - }, - "PublicIp": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-inbound', parameters('name'))), '2022-09-01').outputs.Ip.value]" - }, - "PublicDns": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-inbound', parameters('name'))), '2022-09-01').outputs.Dns.value]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "ai-unlimited", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "name": { - "value": "[parameters('AiUnlimitedName')]" - }, - "adminUsername": { - "value": "azureuser" - }, - "sshPublicKey": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key'), '2022-09-01').outputs.PublicKey.value]" - }, - "dnsLabelPrefix": { - "value": "[variables('dnsLabelPrefix')]" - }, - "vmSize": { - "value": "[parameters('InstanceType')]" - }, - "subnetId": { - "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Network/virtualNetworks/subnets', parameters('Network'), parameters('Subnet'))]" - }, - "networkSecurityGroupID": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" - }, - "osVersion": { - "value": "[parameters('OSVersion')]" - }, - "cloudInitData": { - "value": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value))), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), variables('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), format('--network-alias {0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value)))))]" - }, - "usePersistentVolume": { - "value": "[parameters('UsePersistentVolume')]" - }, - "persistentVolumeSize": { - "value": "[parameters('PersistentVolumeSize')]" - }, - "existingPersistentVolume": { - "value": "[parameters('ExistingPersistentVolume')]" - }, - "nlbName": { - "value": "[parameters('AiUnlimitedName')]" - }, - "nlbPoolNames": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.nlbPools.value]" - }, - "usePublicIp": { - "value": false - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "11687747621230861550" - } - }, - "parameters": { - "location": { - "type": "string" - }, - "name": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "sshPublicKey": { - "type": "string" - }, - "vmSize": { - "type": "string" - }, - "subnetId": { - "type": "string" - }, - "networkSecurityGroupID": { - "type": "string" - }, - "osVersion": { - "type": "string" - }, - "usePersistentVolume": { - "type": "string" - }, - "persistentVolumeSize": { - "type": "int" - }, - "existingPersistentVolume": { - "type": "string" - }, - "cloudInitData": { - "type": "string" - }, - "usePublicIp": { - "type": "bool", - "defaultValue": false - }, - "nlbName": { - "type": "string", - "defaultValue": "" - }, - "albName": { - "type": "string", - "defaultValue": "" - }, - "nlbPoolNames": { - "type": "array", - "defaultValue": [] - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "dnsLabelPrefix": { - "type": "string", - "defaultValue": "" - } - }, - "variables": { - "copy": [ - { - "name": "resourcePools", - "count": "[length(parameters('nlbPoolNames'))]", - "input": { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('nlbName'), parameters('nlbPoolNames')[copyIndex('resourcePools')])]" - } - } - ], - "imageReference": { - "Ubuntu-1804": { - "publisher": "Canonical", - "offer": "UbuntuServer", - "sku": "18_04-lts-gen2", - "version": "latest" - }, - "Ubuntu-2004": { - "publisher": "Canonical", - "offer": "0001-com-ubuntu-server-focal", - "sku": "20_04-lts-gen2", - "version": "latest" - }, - "Ubuntu-2204": { - "publisher": "Canonical", - "offer": "0001-com-ubuntu-server-jammy", - "sku": "22_04-lts-gen2", - "version": "latest" - } - }, - "publicIPAddressName": "[format('{0}PublicIP', parameters('name'))]", - "networkInterfaceName": "[format('{0}-nic', parameters('name'))]", - "osDiskType": "Standard_LRS", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]", - "keyData": "[parameters('sshPublicKey')]" - } - ] - } - }, - "trustedExtensionName": "GuestAttestation", - "trustedExtensionPublisher": "Microsoft.Azure.Security.LinuxAttestation", - "trustedExtensionVersion": "1.0", - "trustedMaaTenantName": "GuestAttestation", - "trustedMaaEndpoint": "[substring('emptystring', 0, 0)]", - "dockerExtensionName": "DockerExtension", - "dockerExtensionPublisher": "Microsoft.Azure.Extensions", - "dockerExtensionVersion": "1.1" - }, - "resources": [ - { - "condition": "[equals(parameters('usePersistentVolume'), 'New')]", - "type": "Microsoft.Compute/disks", - "apiVersion": "2023-04-02", - "name": "[format('{0}-disk', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "creationData": { - "createOption": "Empty" - }, - "diskSizeGB": "[parameters('persistentVolumeSize')]", - "maxShares": 1, - "osType": "Linux" - } - }, - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2022-11-01", - "name": "[variables('networkInterfaceName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "ipConfigurations": [ - "[if(parameters('usePublicIp'), createObject('name', 'ipconfigpublic', 'properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', parameters('subnetId')), 'publicIPAddress', createObject('id', reference(resourceId('Microsoft.Resources/deployments', variables('publicIPAddressName')), '2022-09-01').outputs.Id.value), 'loadBalancerBackendAddressPools', variables('resourcePools'))), if(equals(parameters('albName'), ''), createObject('name', 'ipconfigprivate', 'properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', parameters('subnetId')), 'loadBalancerBackendAddressPools', variables('resourcePools'))), createObject('name', 'ipconfigprivate', 'properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', parameters('subnetId'))))))]" - ], - "networkSecurityGroup": { - "id": "[parameters('networkSecurityGroupID')]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', variables('publicIPAddressName'))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-03-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "[variables('osDiskType')]" - } - }, - "dataDisks": [ - { - "lun": 0, - "createOption": "Attach", - "managedDisk": { - "id": "[if(equals(parameters('usePersistentVolume'), 'New'), resourceId('Microsoft.Compute/disks', format('{0}-disk', parameters('name'))), resourceId('Microsoft.Compute/disks', parameters('existingPersistentVolume')))]" - } - } - ], - "imageReference": "[variables('imageReference')[parameters('osVersion')]]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" - } - ] - }, - "osProfile": { - "computerName": "[parameters('name')]", - "adminUsername": "[parameters('adminUsername')]", - "linuxConfiguration": "[variables('linuxConfiguration')]" - }, - "securityProfile": { - "securityType": "TrustedLaunch", - "uefiSettings": { - "secureBootEnabled": true, - "vTpmEnabled": true - } - }, - "userData": "[parameters('cloudInitData')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]", - "[resourceId('Microsoft.Compute/disks', format('{0}-disk', parameters('name')))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2023-03-01", - "name": "[format('{0}/{1}', parameters('name'), variables('trustedExtensionName'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "properties": { - "publisher": "[variables('trustedExtensionPublisher')]", - "type": "[variables('trustedExtensionName')]", - "typeHandlerVersion": "[variables('trustedExtensionVersion')]", - "autoUpgradeMinorVersion": true, - "settings": { - "AttestationConfig": { - "MaaSettings": { - "maaEndpoint": "[variables('trustedMaaEndpoint')]", - "maaTenantName": "[variables('trustedMaaTenantName')]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2023-03-01", - "name": "[format('{0}/{1}', parameters('name'), variables('dockerExtensionName'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "properties": { - "publisher": "[variables('dockerExtensionPublisher')]", - "type": "[variables('dockerExtensionName')]", - "typeHandlerVersion": "[variables('dockerExtensionVersion')]", - "autoUpgradeMinorVersion": true - }, - "dependsOn": [ - "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - ] - }, - { - "condition": "[parameters('usePublicIp')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[variables('publicIPAddressName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('publicIPAddressName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "dnsPrefix": { - "value": "[parameters('dnsLabelPrefix')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "4325662974998231491" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "dnsPrefix": { - "type": "string" - }, - "tags": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" - }, - "properties": { - "dnsSettings": "[if(not(equals(parameters('dnsPrefix'), '')), createObject('domainNameLabel', parameters('dnsPrefix')), null())]", - "publicIPAddressVersion": "IPv4", - "publicIPAllocationMethod": "Static", - "idleTimeoutInMinutes": 5 - }, - "tags": "[parameters('tags')]" - } - ], - "outputs": { - "Id": { - "type": "string", - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "Ip": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').ipAddress]" - }, - "Dns": { - "type": "string", - "value": "[if(not(equals(parameters('dnsPrefix'), '')), reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').dnsSettings.fqdn, '')]" - } - } - } - } - } - ], - "outputs": { - "PublicIP": { - "type": "string", - "value": "[if(parameters('usePublicIp'), reference(resourceId('Microsoft.Resources/deployments', variables('publicIPAddressName')), '2022-09-01').outputs.Ip.value, '')]" - }, - "PrivateIP": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName')), '2022-11-01').ipConfigurations[0].properties.privateIPAddress]" - }, - "PrincipleId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), '2023-03-01', 'full').identity.principalId]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key')]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "Public-Key", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "Name": { - "value": "[parameters('AiUnlimitedName')]" - }, - "Location": { - "value": "[deployment().location]" - }, - "VaultName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" - }, - "RoleID": { - "value": "[parameters('RoleDefinitionId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "9690061458974637253" - } - }, - "parameters": { - "Location": { - "type": "string" - }, - "Name": { - "type": "string" - }, - "VaultName": { - "type": "string" - }, - "RoleID": { - "type": "string" - }, - "Uuid": { - "type": "string", - "defaultValue": "[newGuid()]" - } - }, - "variables": { - "SecretName": "[format('{0}-PrivateKey', parameters('Name'))]", - "ScriptName": "[format('{0}-createKeys', parameters('Name'))]", - "IdentityName": "[format('{0}-scratch', parameters('Name'))]", - "RoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleID'))]", - "RoleDefinitionName": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), variables('RoleDefinitionId'), resourceGroup().id)]" - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[variables('IdentityName')]", - "location": "[parameters('Location')]" - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[variables('RoleDefinitionName')]", - "properties": { - "roleDefinitionId": "[variables('RoleDefinitionId')]", - "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), '2023-01-31').principalId]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]" - ] - }, - { - "type": "Microsoft.Resources/deploymentScripts", - "apiVersion": "2023-08-01", - "name": "[variables('ScriptName')]", - "location": "[parameters('Location')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')))]": {} - } - }, - "kind": "AzureCLI", - "properties": { - "forceUpdateTag": "[parameters('Uuid')]", - "azCliVersion": "2.0.80", - "timeout": "PT30M", - "retentionInterval": "P1D", - "cleanupPreference": "OnSuccess", - "scriptContent": " #/bin/bash -e\n\n echo -e 'y' | ssh-keygen -f scratch\n\n privateKey=$(cat scratch)\n publicKey=$(cat 'scratch.pub')\n\n json=\"{\\\"keyinfo\\\":{\\\"privateKey\\\":\\\"$privateKey\\\",\\\"publicKey\\\":\\\"$publicKey\\\"}}\"\n\n echo \"$json\" > $AZ_SCRIPTS_OUTPUT_PATH\n " - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]", - "[resourceId('Microsoft.Authorization/roleAssignments', variables('RoleDefinitionName'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('VaultName'), variables('SecretName'))]", - "properties": { - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.privateKey]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName'))]" - ] - } - ], - "outputs": { - "PublicKey": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.publicKey]" - }, - "Status": { - "type": "object", - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').status]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" - ] - } - ], - "outputs": { - "PublicIP": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicIp.value]" - }, - "PrivateIP": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value]" - }, - "AiUnlimitedPublicHttpAccess": { - "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" - }, - "AiUnlimitedPrivateHttpAccess": { - "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" - }, - "AiUnlimitedPublicGrpcAccess": { - "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value, parameters('AiUnlimitedGrpcPort'))]" - }, - "AiUnlimitedPrivateGrpcAccess": { - "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedGrpcPort'))]" - }, - "JupyterLabPublicHttpAccess": { - "type": "string", - "value": "[format('http://{0}:{1}?token={2}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'loadbalancer'), '2022-09-01').outputs.PublicDns.value, parameters('JupyterHttpPort'), parameters('JupyterToken'))]" - }, - "JupyterLabPrivateHttpAccess": { - "type": "string", - "value": "[format('http://{0}:{1}?token={2}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('JupyterHttpPort'), parameters('JupyterToken'))]" - }, - "SecurityGroup": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" - } - } -} \ No newline at end of file diff --git a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json b/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json deleted file mode 100644 index bc1c757..0000000 --- a/deployments/azure/templates/arm/all-in-one/all-in-one-without-lb.json +++ /dev/null @@ -1,1393 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "17623174102781456375" - } - }, - "parameters": { - "ResourceGroupName": { - "type": "string", - "defaultValue": "ai-unlimited-workspace", - "metadata": { - "description": "name for the resource group." - } - }, - "AiUnlimitedName": { - "type": "string", - "metadata": { - "description": "Name for the Workspace service's virtual machine." - } - }, - "OSVersion": { - "type": "string", - "defaultValue": "Ubuntu-2004", - "allowedValues": [ - "Ubuntu-1804", - "Ubuntu-2004", - "Ubuntu-2204" - ], - "metadata": { - "description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version." - } - }, - "InstanceType": { - "type": "string", - "defaultValue": "Standard_D2s_v3", - "metadata": { - "description": "The AI Unlimited VM type" - } - }, - "Network": { - "type": "string", - "metadata": { - "description": "Name of the network to run the AI Unlimited service in" - } - }, - "Subnet": { - "type": "string", - "metadata": { - "description": "Name of the subnet to run the AI Unlimited service in" - } - }, - "SecurityGroup": { - "type": "string", - "defaultValue": "AiUnlimitedSecurityGroup", - "metadata": { - "description": "Name of the network security group" - } - }, - "AccessCIDRs": { - "type": "array", - "defaultValue": [ - "0.0.0.0/0" - ], - "metadata": { - "description": "The CIDR ranges that can be used to communicate with the AI Unlimited service instance." - } - }, - "JupyterHttpPort": { - "type": "int", - "defaultValue": 8888, - "metadata": { - "description": "port to access the Jupyter Labs UI." - } - }, - "AiUnlimitedAuthPort": { - "type": "int", - "defaultValue": 3000, - "metadata": { - "description": "port to access the AI Unlimited auth service." - } - }, - "AiUnlimitedGrpcPort": { - "type": "int", - "defaultValue": 3282, - "metadata": { - "description": "port to access the AI Unlimited service api." - } - }, - "SourceAppSecGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Source Application Security Groups to access the AI Unlimited service api." - } - }, - "detinationAppSecGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Destination Application Security Groups to give access to AI Unlimited service instance." - } - }, - "RoleDefinitionId": { - "type": "string", - "metadata": { - "description": "GUID of the AI Unlimited Role" - } - }, - "UseKeyVault": { - "type": "string", - "defaultValue": "New", - "allowedValues": [ - "New", - "None" - ], - "metadata": { - "description": "should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes." - } - }, - "UsePersistentVolume": { - "type": "string", - "defaultValue": "New", - "allowedValues": [ - "New", - "Existing" - ], - "metadata": { - "description": "should we use a new or existing volume for persistent data on the AI Unlimited server." - } - }, - "PersistentVolumeSize": { - "type": "int", - "defaultValue": 100, - "metadata": { - "description": "size of the optional persistent disk to the AI Unlimited server." - } - }, - "ExistingPersistentVolume": { - "type": "string", - "defaultValue": "NONE", - "metadata": { - "description": "Name of the existing persistent volume to attach. Must be in the same region and resourcegroup zone as the AI Unlimited server." - } - }, - "AiUnlimitedVersion": { - "type": "string", - "defaultValue": "v0.3.0", - "metadata": { - "description": "Container Version of the AI Unlimited service" - } - }, - "AiUnlimitedUIVersion": { - "type": "string", - "defaultValue": "v0.1.0", - "metadata": { - "description": "Container Version of the AI Unlimited UI service" - } - }, - "JupyterVersion": { - "type": "string", - "defaultValue": "v0.1.0", - "metadata": { - "description": "Container Version of the Jupyter Labs service" - } - }, - "JupyterToken": { - "type": "securestring", - "metadata": { - "description": "Join token for the Jupyter Labs service" - } - }, - "Tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to apply to all newly created resources, in the form of {\"key_one\":\"value_one\",\"key_two\":\"value_two\"}" - } - } - }, - "variables": { - "$fxv#0": "#cloud-config\nwrite_files:\n- encoding: b64\n content: \"{0}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited.service\n permissions: '0640'\n- encoding: b64\n content: \"{1}\"\n owner: root:root\n path: /usr/lib/systemd/system/jupyter.service\n permissions: '0640'\n- encoding: b64\n content: \"{2}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-scheduler.service\n permissions: '0640'\n- encoding: b64\n content: \"{3}\"\n owner: root:root\n path: /usr/lib/systemd/system/ai-unlimited-ui.service\n permissions: '0640'\n\nruncmd:\n- mkdir -p /etc/td \n- |\n export PERMDISK=$(lsscsi 1:0:0:0 -b | awk '{{print $2}}');\n if [ -n \"${{PERMDISK}}\" ]; then blkid --match-token TYPE=ext4 ${{PERMDISK}} || (mkfs.ext4 -m0 ${{PERMDISK}} && e2label ${{PERMDISK}} WORKSPACES); fi\n /usr/bin/echo \"LABEL=WORKSPACES /etc/td ext4 defaults 0 2\" >> /etc/fstab\n /usr/bin/mount -a\n- while [ $(systemctl status docker | grep \"active (running)\" | wc -l) -lt 1 ]; do sleep 5; done\n- mkdir -p /etc/td/ai-unlimited\n- echo \"TD_VCD_INIT_API_KEY=$(LC_ALL=C tr -dc A-Za-z0-9 /etc/td/ai-unlimited/init_api_key.txt\n- sleep 60\n- systemctl enable ai-unlimited.service\n- systemctl start ai-unlimited.service\n- systemctl enable jupyter.service\n- systemctl start jupyter.service\n- systemctl enable ai-unlimited-scheduler.service\n- systemctl start ai-unlimited-scheduler.service\n- systemctl enable ai-unlimited-ui.service\n- systemctl start ai-unlimited-ui.service\n", - "$fxv#1": "[Unit]\nDescription=AI Unlimited\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker volume create ssl_certs\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/ai-unlimited\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e PLATFORM=azure \\\n -e ARM_USE_MSI=true \\\n -e ARM_SUBSCRIPTION_ID={5} \\\n -e ARM_TENANT_ID={6} \\\n -e TD_VCD_INIT_API_KEY \\\n -p {3}:3000 \\\n -p {4}:3282 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -v ssl_certs:/etc/td/ssl \\\n --network ai_unlimited {7} \\\n --rm --name %n {0}/{1}:{2} workspaces serve -v\n\n[Install]\nWantedBy=multi-user.target", - "$fxv#2": "[Unit]\nDescription=jupyter\nAfter=docker.service\nRequires=docker.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker network create -d bridge ai_unlimited\nExecStartPre=-/usr/bin/mkdir -p /etc/td/jupyter/{{userdata,ipython}}\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e accept_license=Y \\\n -e JUPYTER_TOKEN={4} \\\n -v /etc/td/jupyter/userdata:/home/jovyan/JupyterLabRoot/userdata \\\n -v /etc/td/jupyter/ipython:/home/jovyan/.ipython \\\n -p {3}:8888 \\\n --network ai_unlimited \\\n --rm --name %n {0}/{1}:{2}\n\n[Install]\nWantedBy=multi-user.target\n", - "$fxv#3": "[Unit]\nDescription=AI Unlimited Scheduler\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\nExecStart=/usr/bin/docker run \\\n --network ai_unlimited \\\n -p {3}:50061 \\\n -v /etc/td/ai-unlimited:/etc/td \\\n -e TD_WSSCHED_LOG_PATH=/etc/td/workspaces/scheduler_logs \\\n -e TD_WSSCHED_TASK_LOG_PATH=/etc/td/workspaces/scheduler_logs/projects \\\n -e TD_WSSCHED_POL_INTERVAL=2 \\\n -e TD_WS_CONTAINER_NAME=ai-unlimited.service \\\n --rm --name %n {0}/{1}:{2} workspace-event-scheduler serve\n[Install]\nWantedBy=multi-user.target", - "$fxv#4": "[Unit]\nDescription=AI Unlimited UI\nAfter=ai-unlimited.service\nRequires=ai-unlimited.service\nStartLimitInterval=200\nStartLimitBurst=10\n\n[Service]\nTimeoutStartSec=0\nRestart=always\nRestartSec=2\nEnvironmentFile=/etc/td/ai-unlimited/init_api_key.txt\nExecStartPre=-/usr/bin/docker stop %n\nExecStartPre=-/usr/bin/docker rm %n\nExecStartPre=/usr/bin/docker pull {0}/{1}:{2}\n\nExecStart=/usr/bin/docker run \\\n -e TD_VCD_USE_TLS=false \\\n -e TD_VCD_AUTH_PORT={4}\\\n -e TD_VCD_API_PORT={5}\\\n -e TD_VCD_INIT_API_KEY \\\n -p 80:80 \\\n -p 443:443 \\\n -v ssl_certs:/etc/ssl/td \\\n --network ai_unlimited {6} \\\n --rm --name %n {0}/{1}:{2} \n\n[Install]\nWantedBy=multi-user.target", - "AiUnlimitedSchedulerHttpPort": 50061, - "AiUnlimitedUIHttpPort": 80, - "AiUnlimitedUIHttpsPort": 443, - "AiUnlimitedSchedulerVersion": "latest", - "roleAssignmentName": "[guid(subscription().id, parameters('AiUnlimitedName'), subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), parameters('RoleDefinitionId'))]", - "dnsLabelPrefix": "[format('td{0}', uniqueString(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), deployment().name, parameters('AiUnlimitedName')))]", - "registry": "teradata", - "workspaceRepository": "ai-unlimited-workspaces", - "jupyterRepository": "ai-unlimited-jupyter", - "workspaceSchedulerRepository": "ai-unlimited-scheduler", - "workspaceUIRepository": "ai-unlimited-workspaces-ui", - "cloudInitData": "[base64(format(variables('$fxv#0'), base64(format(variables('$fxv#1'), variables('registry'), variables('workspaceRepository'), parameters('AiUnlimitedVersion'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), subscription().subscriptionId, subscription().tenantId, '--network-alias ai-unlimited')), base64(format(variables('$fxv#2'), variables('registry'), variables('jupyterRepository'), parameters('JupyterVersion'), parameters('JupyterHttpPort'), parameters('JupyterToken'))), base64(format(variables('$fxv#3'), variables('registry'), variables('workspaceSchedulerRepository'), variables('AiUnlimitedSchedulerVersion'), variables('AiUnlimitedSchedulerHttpPort'))), base64(format(variables('$fxv#4'), variables('registry'), variables('workspaceUIRepository'), parameters('AiUnlimitedUIVersion'), variables('AiUnlimitedUIHttpPort'), parameters('AiUnlimitedAuthPort'), parameters('AiUnlimitedGrpcPort'), '--network-alias ai-unlimited'))))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[variables('roleAssignmentName')]", - "properties": { - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleDefinitionId'))]", - "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrincipleId.value]" - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited')]" - ] - }, - { - "condition": "[equals(parameters('UseKeyVault'), 'New')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "vault", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "encryptVolumes": { - "value": true - }, - "keyVaultName": { - "value": "[parameters('AiUnlimitedName')]" - }, - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "29287785012335710" - } - }, - "parameters": { - "encryptVolumes": { - "type": "bool" - }, - "keyVaultName": { - "type": "string" - }, - "location": { - "type": "string" - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "uuid": { - "type": "string", - "defaultValue": "[newGuid()]" - } - }, - "variables": { - "nameCharLimit": 24, - "uniqueName": "[format('{0}-{1}', parameters('keyVaultName'), uniqueString(parameters('uuid')))]", - "uniqueKeyVaultName": "[substring(format('{0}', variables('uniqueName')), 0, if(less(length(variables('uniqueName')), variables('nameCharLimit')), length(variables('uniqueName')), variables('nameCharLimit')))]" - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "name": "[variables('uniqueKeyVaultName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "sku": { - "family": "A", - "name": "standard" - }, - "tenantId": "[subscription().tenantId]", - "softDeleteRetentionInDays": 7, - "enableSoftDelete": true, - "enablePurgeProtection": "[if(parameters('encryptVolumes'), true(), null())]", - "enabledForDiskEncryption": "[parameters('encryptVolumes')]", - "accessPolicies": [] - } - } - ], - "outputs": { - "id": { - "type": "string", - "value": "[resourceId('Microsoft.KeyVault/vaults', variables('uniqueKeyVaultName'))]" - }, - "name": { - "type": "string", - "value": "[variables('uniqueKeyVaultName')]" - } - } - } - } - }, - { - "condition": "[equals(parameters('UseKeyVault'), 'New')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "vault-access-policy", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "vaultName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" - }, - "accessPolicy": { - "value": { - "tenantId": "[subscription().tenantId]", - "objectId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrincipleId.value]", - "permissions": { - "keys": [ - "Create", - "Delete", - "Get", - "List", - "Update", - "Purge", - "Recover", - "Decrypt", - "Encrypt", - "Sign", - "UnwrapKey", - "Verify", - "WrapKey", - "GetRotationPolicy", - "SetRotationPolicy" - ], - "secrets": [ - "Get", - "Set", - "Delete", - "List", - "Purge" - ], - "storage": [ - "Get" - ] - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "16095084913002426133" - } - }, - "parameters": { - "vaultName": { - "type": "string" - }, - "accessPolicy": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/accessPolicies", - "apiVersion": "2022-07-01", - "name": "[format('{0}/add', parameters('vaultName'))]", - "properties": { - "accessPolicies": [ - "[parameters('accessPolicy')]" - ] - } - } - ] - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "firewall", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "name": { - "value": "[parameters('SecurityGroup')]" - }, - "accessCidrs": { - "value": "[parameters('AccessCIDRs')]" - }, - "sshAccess": { - "value": false - }, - "aiUnlimitedAuthPort": { - "value": "[parameters('AiUnlimitedAuthPort')]" - }, - "aiUnlimitedGrpcPort": { - "value": "[parameters('AiUnlimitedGrpcPort')]" - }, - "aiUnlimitedSchedulerHttpPort": { - "value": "[variables('AiUnlimitedSchedulerHttpPort')]" - }, - "aiUnlimitedUIHttpPort": { - "value": "[variables('AiUnlimitedUIHttpPort')]" - }, - "aiUnlimitedUIHttpsPort": { - "value": "[variables('AiUnlimitedUIHttpsPort')]" - }, - "jupyterHttpPort": { - "value": "[parameters('JupyterHttpPort')]" - }, - "sourceAppSecGroups": { - "value": "[parameters('SourceAppSecGroups')]" - }, - "detinationAppSecGroups": { - "value": "[parameters('detinationAppSecGroups')]" - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "392354314460473239" - } - }, - "parameters": { - "location": { - "type": "string" - }, - "name": { - "type": "string" - }, - "accessCidrs": { - "type": "array", - "defaultValue": [] - }, - "sourceAppSecGroups": { - "type": "array", - "defaultValue": [] - }, - "detinationAppSecGroups": { - "type": "array", - "defaultValue": [] - }, - "sshAccess": { - "type": "bool", - "defaultValue": false - }, - "aiUnlimitedAuthPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedGrpcPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedSchedulerHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedUIHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "aiUnlimitedUIHttpsPort": { - "type": "int", - "defaultValue": 0 - }, - "jupyterHttpPort": { - "type": "int", - "defaultValue": 0 - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "uuid": { - "type": "string", - "defaultValue": "[newGuid()]" - } - }, - "variables": { - "nameCharLimit": 60, - "uniqueName": "[format('{0}-{1}', parameters('name'), uniqueString(parameters('uuid')))]", - "uniqueSecurityGroupName": "[substring(format('{0}', variables('uniqueName')), 0, if(less(length(variables('uniqueName')), variables('nameCharLimit')), length(variables('uniqueName')), variables('nameCharLimit')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2022-11-01", - "name": "[variables('uniqueSecurityGroupName')]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]" - }, - { - "condition": "[parameters('sshAccess')]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-ssh-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow ssh to the workspace instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "22", - "direction": "Inbound", - "priority": 700, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedAuthPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-auth-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the workspace instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedAuthPort'))]", - "direction": "Inbound", - "priority": 701, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedGrpcPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-grpc-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow grpc to the workspace instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedGrpcPort'))]", - "direction": "Inbound", - "priority": 702, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('jupyterHttpPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-juptyer-http-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the jupyter instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('jupyterHttpPort'))]", - "direction": "Inbound", - "priority": 703, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedSchedulerHttpPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-scheduler-http-allow', variables('uniqueSecurityGroupName')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the scheduler instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedSchedulerHttpPort'))]", - "direction": "Inbound", - "priority": 704, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedUIHttpPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-http-allow', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow http to the workspace ui instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpPort'))]", - "direction": "Inbound", - "priority": 705, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - }, - { - "condition": "[not(equals(parameters('aiUnlimitedUIHttpsPort'), 0))]", - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', variables('uniqueSecurityGroupName'), format('{0}-workspace-ui-https-allow', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "destinationApplicationSecurityGroups", - "count": "[length(parameters('detinationAppSecGroups'))]", - "input": { - "id": "[parameters('detinationAppSecGroups')[copyIndex('destinationApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - }, - { - "name": "sourceApplicationSecurityGroups", - "count": "[length(parameters('sourceAppSecGroups'))]", - "input": { - "id": "[parameters('sourceAppSecGroups')[copyIndex('sourceApplicationSecurityGroups')]]", - "location": "[parameters('location')]" - } - } - ], - "access": "Allow", - "description": "allow https to the workspace ui instance", - "destinationAddressPrefix": "*", - "destinationPortRange": "[string(parameters('aiUnlimitedUIHttpsPort'))]", - "direction": "Inbound", - "priority": 706, - "protocol": "Tcp", - "sourceAddressPrefixes": "[parameters('accessCidrs')]", - "sourcePortRange": "*" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - ] - } - ], - "outputs": { - "Id": { - "type": "string", - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('uniqueSecurityGroupName'))]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "ai-unlimited", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('ResourceGroupName')), '2022-09-01', 'full').location]" - }, - "name": { - "value": "[parameters('AiUnlimitedName')]" - }, - "adminUsername": { - "value": "azureuser" - }, - "sshPublicKey": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key'), '2022-09-01').outputs.PublicKey.value]" - }, - "dnsLabelPrefix": { - "value": "[variables('dnsLabelPrefix')]" - }, - "vmSize": { - "value": "[parameters('InstanceType')]" - }, - "subnetId": { - "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Network/virtualNetworks/subnets', parameters('Network'), parameters('Subnet'))]" - }, - "networkSecurityGroupID": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" - }, - "osVersion": { - "value": "[parameters('OSVersion')]" - }, - "cloudInitData": { - "value": "[variables('cloudInitData')]" - }, - "usePersistentVolume": { - "value": "[parameters('UsePersistentVolume')]" - }, - "persistentVolumeSize": { - "value": "[parameters('PersistentVolumeSize')]" - }, - "existingPersistentVolume": { - "value": "[parameters('ExistingPersistentVolume')]" - }, - "usePublicIp": { - "value": true - }, - "tags": { - "value": "[parameters('Tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "11687747621230861550" - } - }, - "parameters": { - "location": { - "type": "string" - }, - "name": { - "type": "string" - }, - "adminUsername": { - "type": "string" - }, - "sshPublicKey": { - "type": "string" - }, - "vmSize": { - "type": "string" - }, - "subnetId": { - "type": "string" - }, - "networkSecurityGroupID": { - "type": "string" - }, - "osVersion": { - "type": "string" - }, - "usePersistentVolume": { - "type": "string" - }, - "persistentVolumeSize": { - "type": "int" - }, - "existingPersistentVolume": { - "type": "string" - }, - "cloudInitData": { - "type": "string" - }, - "usePublicIp": { - "type": "bool", - "defaultValue": false - }, - "nlbName": { - "type": "string", - "defaultValue": "" - }, - "albName": { - "type": "string", - "defaultValue": "" - }, - "nlbPoolNames": { - "type": "array", - "defaultValue": [] - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "dnsLabelPrefix": { - "type": "string", - "defaultValue": "" - } - }, - "variables": { - "copy": [ - { - "name": "resourcePools", - "count": "[length(parameters('nlbPoolNames'))]", - "input": { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('nlbName'), parameters('nlbPoolNames')[copyIndex('resourcePools')])]" - } - } - ], - "imageReference": { - "Ubuntu-1804": { - "publisher": "Canonical", - "offer": "UbuntuServer", - "sku": "18_04-lts-gen2", - "version": "latest" - }, - "Ubuntu-2004": { - "publisher": "Canonical", - "offer": "0001-com-ubuntu-server-focal", - "sku": "20_04-lts-gen2", - "version": "latest" - }, - "Ubuntu-2204": { - "publisher": "Canonical", - "offer": "0001-com-ubuntu-server-jammy", - "sku": "22_04-lts-gen2", - "version": "latest" - } - }, - "publicIPAddressName": "[format('{0}PublicIP', parameters('name'))]", - "networkInterfaceName": "[format('{0}-nic', parameters('name'))]", - "osDiskType": "Standard_LRS", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]", - "keyData": "[parameters('sshPublicKey')]" - } - ] - } - }, - "trustedExtensionName": "GuestAttestation", - "trustedExtensionPublisher": "Microsoft.Azure.Security.LinuxAttestation", - "trustedExtensionVersion": "1.0", - "trustedMaaTenantName": "GuestAttestation", - "trustedMaaEndpoint": "[substring('emptystring', 0, 0)]", - "dockerExtensionName": "DockerExtension", - "dockerExtensionPublisher": "Microsoft.Azure.Extensions", - "dockerExtensionVersion": "1.1" - }, - "resources": [ - { - "condition": "[equals(parameters('usePersistentVolume'), 'New')]", - "type": "Microsoft.Compute/disks", - "apiVersion": "2023-04-02", - "name": "[format('{0}-disk', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "creationData": { - "createOption": "Empty" - }, - "diskSizeGB": "[parameters('persistentVolumeSize')]", - "maxShares": 1, - "osType": "Linux" - } - }, - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2022-11-01", - "name": "[variables('networkInterfaceName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "ipConfigurations": [ - "[if(parameters('usePublicIp'), createObject('name', 'ipconfigpublic', 'properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', parameters('subnetId')), 'publicIPAddress', createObject('id', reference(resourceId('Microsoft.Resources/deployments', variables('publicIPAddressName')), '2022-09-01').outputs.Id.value), 'loadBalancerBackendAddressPools', variables('resourcePools'))), if(equals(parameters('albName'), ''), createObject('name', 'ipconfigprivate', 'properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', parameters('subnetId')), 'loadBalancerBackendAddressPools', variables('resourcePools'))), createObject('name', 'ipconfigprivate', 'properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', parameters('subnetId'))))))]" - ], - "networkSecurityGroup": { - "id": "[parameters('networkSecurityGroupID')]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', variables('publicIPAddressName'))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-03-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "[variables('osDiskType')]" - } - }, - "dataDisks": [ - { - "lun": 0, - "createOption": "Attach", - "managedDisk": { - "id": "[if(equals(parameters('usePersistentVolume'), 'New'), resourceId('Microsoft.Compute/disks', format('{0}-disk', parameters('name'))), resourceId('Microsoft.Compute/disks', parameters('existingPersistentVolume')))]" - } - } - ], - "imageReference": "[variables('imageReference')[parameters('osVersion')]]" - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" - } - ] - }, - "osProfile": { - "computerName": "[parameters('name')]", - "adminUsername": "[parameters('adminUsername')]", - "linuxConfiguration": "[variables('linuxConfiguration')]" - }, - "securityProfile": { - "securityType": "TrustedLaunch", - "uefiSettings": { - "secureBootEnabled": true, - "vTpmEnabled": true - } - }, - "userData": "[parameters('cloudInitData')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]", - "[resourceId('Microsoft.Compute/disks', format('{0}-disk', parameters('name')))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2023-03-01", - "name": "[format('{0}/{1}', parameters('name'), variables('trustedExtensionName'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "properties": { - "publisher": "[variables('trustedExtensionPublisher')]", - "type": "[variables('trustedExtensionName')]", - "typeHandlerVersion": "[variables('trustedExtensionVersion')]", - "autoUpgradeMinorVersion": true, - "settings": { - "AttestationConfig": { - "MaaSettings": { - "maaEndpoint": "[variables('trustedMaaEndpoint')]", - "maaTenantName": "[variables('trustedMaaTenantName')]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2023-03-01", - "name": "[format('{0}/{1}', parameters('name'), variables('dockerExtensionName'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "properties": { - "publisher": "[variables('dockerExtensionPublisher')]", - "type": "[variables('dockerExtensionName')]", - "typeHandlerVersion": "[variables('dockerExtensionVersion')]", - "autoUpgradeMinorVersion": true - }, - "dependsOn": [ - "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - ] - }, - { - "condition": "[parameters('usePublicIp')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[variables('publicIPAddressName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('publicIPAddressName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "dnsPrefix": { - "value": "[parameters('dnsLabelPrefix')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "4325662974998231491" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "dnsPrefix": { - "type": "string" - }, - "tags": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "sku": { - "name": "Standard" - }, - "properties": { - "dnsSettings": "[if(not(equals(parameters('dnsPrefix'), '')), createObject('domainNameLabel', parameters('dnsPrefix')), null())]", - "publicIPAddressVersion": "IPv4", - "publicIPAllocationMethod": "Static", - "idleTimeoutInMinutes": 5 - }, - "tags": "[parameters('tags')]" - } - ], - "outputs": { - "Id": { - "type": "string", - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "Ip": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').ipAddress]" - }, - "Dns": { - "type": "string", - "value": "[if(not(equals(parameters('dnsPrefix'), '')), reference(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), '2021-05-01').dnsSettings.fqdn, '')]" - } - } - } - } - } - ], - "outputs": { - "PublicIP": { - "type": "string", - "value": "[if(parameters('usePublicIp'), reference(resourceId('Microsoft.Resources/deployments', variables('publicIPAddressName')), '2022-09-01').outputs.Ip.value, '')]" - }, - "PrivateIP": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName')), '2022-11-01').ipConfigurations[0].properties.privateIPAddress]" - }, - "PrincipleId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), '2023-03-01', 'full').identity.principalId]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall')]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'Public-Key')]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "Public-Key", - "resourceGroup": "[parameters('ResourceGroupName')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "Name": { - "value": "[parameters('AiUnlimitedName')]" - }, - "Location": { - "value": "[deployment().location]" - }, - "VaultName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault'), '2022-09-01').outputs.name.value]" - }, - "RoleID": { - "value": "[parameters('RoleDefinitionId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "9690061458974637253" - } - }, - "parameters": { - "Location": { - "type": "string" - }, - "Name": { - "type": "string" - }, - "VaultName": { - "type": "string" - }, - "RoleID": { - "type": "string" - }, - "Uuid": { - "type": "string", - "defaultValue": "[newGuid()]" - } - }, - "variables": { - "SecretName": "[format('{0}-PrivateKey', parameters('Name'))]", - "ScriptName": "[format('{0}-createKeys', parameters('Name'))]", - "IdentityName": "[format('{0}-scratch', parameters('Name'))]", - "RoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('RoleID'))]", - "RoleDefinitionName": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), variables('RoleDefinitionId'), resourceGroup().id)]" - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[variables('IdentityName')]", - "location": "[parameters('Location')]" - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[variables('RoleDefinitionName')]", - "properties": { - "roleDefinitionId": "[variables('RoleDefinitionId')]", - "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')), '2023-01-31').principalId]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]" - ] - }, - { - "type": "Microsoft.Resources/deploymentScripts", - "apiVersion": "2023-08-01", - "name": "[variables('ScriptName')]", - "location": "[parameters('Location')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName')))]": {} - } - }, - "kind": "AzureCLI", - "properties": { - "forceUpdateTag": "[parameters('Uuid')]", - "azCliVersion": "2.0.80", - "timeout": "PT30M", - "retentionInterval": "P1D", - "cleanupPreference": "OnSuccess", - "scriptContent": " #/bin/bash -e\n\n echo -e 'y' | ssh-keygen -f scratch\n\n privateKey=$(cat scratch)\n publicKey=$(cat 'scratch.pub')\n\n json=\"{\\\"keyinfo\\\":{\\\"privateKey\\\":\\\"$privateKey\\\",\\\"publicKey\\\":\\\"$publicKey\\\"}}\"\n\n echo \"$json\" > $AZ_SCRIPTS_OUTPUT_PATH\n " - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('IdentityName'))]", - "[resourceId('Microsoft.Authorization/roleAssignments', variables('RoleDefinitionName'))]" - ] - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('VaultName'), variables('SecretName'))]", - "properties": { - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.privateKey]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName'))]" - ] - } - ], - "outputs": { - "PublicKey": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').outputs.keyinfo.publicKey]" - }, - "Status": { - "type": "object", - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', variables('ScriptName')), '2023-08-01').status]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'vault')]" - ] - } - ], - "outputs": { - "PublicIP": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value]" - }, - "PrivateIP": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value]" - }, - "AiUnlimitedPublicHttpAccess": { - "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" - }, - "AiUnlimitedPrivateHttpAccess": { - "type": "string", - "value": "[concat(format('http://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value), if(not(equals(variables('AiUnlimitedUIHttpPort'), 80)), concat(':', string(variables('AiUnlimitedUIHttpPort'))), ''))]" - }, - "AiUnlimitedPublicGrpcAccess": { - "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value, parameters('AiUnlimitedGrpcPort'))]" - }, - "AiUnlimitedPrivateGrpcAccess": { - "type": "string", - "value": "[format('http://{0}:{1}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('AiUnlimitedGrpcPort'))]" - }, - "JupyterLabPublicHttpAccess": { - "type": "string", - "value": "[format('http://{0}:{1}?token={2}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PublicIP.value, parameters('JupyterHttpPort'), parameters('JupyterToken'))]" - }, - "JupyterLabPrivateHttpAccess": { - "type": "string", - "value": "[format('http://{0}:{1}?token={2}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'ai-unlimited'), '2022-09-01').outputs.PrivateIP.value, parameters('JupyterHttpPort'), parameters('JupyterToken'))]" - }, - "SecurityGroup": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('ResourceGroupName')), 'Microsoft.Resources/deployments', 'firewall'), '2022-09-01').outputs.Id.value]" - } - } -} \ No newline at end of file diff --git a/deployments/azure/templates/arm/all-in-one/readme.txt b/deployments/azure/templates/arm/all-in-one/readme.txt deleted file mode 100644 index b07593c..0000000 --- a/deployments/azure/templates/arm/all-in-one/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Disclaimer - -**IMPORTANT NOTICE** - -The all-in-one arm templates provided in this directory are for informational purposes only. These templates are currently not supported by Teradata Corporation. - -**Use of these templates is at your own risk. Teradata Corporation assumes no responsibility or liability for any damages or issues that may arise from using these templates.** \ No newline at end of file diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep deleted file mode 100644 index 35a9a1f..0000000 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicep +++ /dev/null @@ -1,297 +0,0 @@ -targetScope = 'subscription' - -@description('name for the resource group.') -param ResourceGroupName string = 'ai-unlimited-workspace' - -@description('Name for the Workspace service\'s virtual machine.') -param AiUnlimitedName string - -@description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') -@allowed([ - 'Ubuntu-1804' - 'Ubuntu-2004' - 'Ubuntu-2204' -]) -param OSVersion string = 'Ubuntu-2004' - -@description('The AI Unlimited VM type') -param InstanceType string = 'Standard_D2s_v3' - -@description('Name of the network to run the AI Unlimited service in') -param Network string - -@description('Name of the subnet to run the AI Unlimited service in') -param Subnet string - -@description('Name of the network security group') -param SecurityGroup string = 'AiUnlimitedSecurityGroup' - -@description('The CIDR ranges that can be used to communicate with the AI Unlimited service instance.') -param AccessCIDRs array = ['0.0.0.0/0'] - -@description('port to access the Jupyter Labs UI.') -param JupyterHttpPort int = 8888 - -@description('port to access the AI Unlimited auth service.') -param AiUnlimitedAuthPort int = 3000 - -@description('port to access the AI Unlimited service api.') -param AiUnlimitedGrpcPort int = 3282 - -// @description('port to access the AI Unlimited scheduler service grpc api.') -// var AiUnlimitedSchedulerGrpcPort = 50051 - -// @description('port to access the AI Unlimited scheduler service http api.') -var AiUnlimitedSchedulerHttpPort = 50061 - -// @description('port to access the AI Unlimited service UI http.') -var AiUnlimitedUIHttpPort = 80 - -// @description('port to access the AI Unlimited service UI https.') -var AiUnlimitedUIHttpsPort = 443 - -@description('Source Application Security Groups to access the AI Unlimited service api.') -param SourceAppSecGroups array = [] - -@description('Destination Application Security Groups to give access to AI Unlimited service instance.') -param detinationAppSecGroups array = [] - -@description('GUID of the AI Unlimited Role') -param RoleDefinitionId string - -@description('should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes.') -@allowed(['New', 'None']) -param UseKeyVault string = 'New' - -@description('should we use a new or existing volume for persistent data on the AI Unlimited server.') -@allowed(['New', 'Existing']) -param UsePersistentVolume string = 'New' - -@description('size of the optional persistent disk to the AI Unlimited server.') -param PersistentVolumeSize int = 100 - -@description('Name of the existing persistent volume to attach. Must be in the same region and resourcegroup zone as the AI Unlimited server.') -param ExistingPersistentVolume string = 'NONE' - -@description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.0' - -@description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.1.0' - -@description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.1.0' - -// @description('Container Version of the AI Unlimited scheduler service') -var AiUnlimitedSchedulerVersion = 'latest' - -@description('Join token for the Jupyter Labs service') -@secure() -param JupyterToken string - -@description('Tags to apply to all newly created resources, in the form of {"key_one":"value_one","key_two":"value_two"}') -param Tags object = {} - -var roleAssignmentName = guid(subscription().id, AiUnlimitedName, rg.id, RoleDefinitionId) -var dnsId = uniqueString(rg.id, deployment().name, AiUnlimitedName) -var dnsLabelPrefix = 'td${dnsId}' -var nlbDnsLabelPrefix = 'td${dnsId}-nlb' - -// below are static and are not expected to be changed -var registry = 'teradata' -var workspaceRepository = 'ai-unlimited-workspaces' -var jupyterRepository = 'ai-unlimited-jupyter' -var workspaceSchedulerRepository = 'ai-unlimited-scheduler' -var workspaceUIRepository = 'ai-unlimited-workspaces-ui' - -var cloudInitData = base64(format( - loadTextContent('../../../scripts/all-in-one.cloudinit.yaml'), - base64(format( - loadTextContent('../../../scripts/ai-unlimited.service'), - registry, - workspaceRepository, - AiUnlimitedVersion, - AiUnlimitedAuthPort, - AiUnlimitedGrpcPort, - subscription().subscriptionId, - subscription().tenantId, - '--network-alias ${nlb.outputs.PublicDns}' - )), - base64(format( - loadTextContent('../../../scripts/jupyter.service'), - registry, - jupyterRepository, - JupyterVersion, - JupyterHttpPort, - JupyterToken - )), - base64(format( - loadTextContent('../../../scripts/ai-unlimited-scheduler.service'), - registry, - workspaceSchedulerRepository, - AiUnlimitedSchedulerVersion, - // AiUnlimitedSchedulerGrpcPort, - AiUnlimitedSchedulerHttpPort - )), - base64(format( - loadTextContent('../../../scripts/ai-unlimited-ui.service'), - registry, - workspaceUIRepository, - AiUnlimitedUIVersion, - AiUnlimitedUIHttpPort, - AiUnlimitedAuthPort, - AiUnlimitedGrpcPort, - '--network-alias ${nlb.outputs.PublicDns}' - )) -)) - -resource rg 'Microsoft.Resources/resourceGroups@2022-09-01' existing = { - name: ResourceGroupName -} - -resource network 'Microsoft.Network/virtualNetworks@2022-11-01' existing = { - scope: rg - name: Network -} - -resource subnet 'Microsoft.Network/virtualNetworks/subnets@2022-11-01' existing = { - parent: network - name: Subnet -} - -module vault '../modules/vault/vault.bicep' = if (UseKeyVault == 'New') { - scope: rg - name: 'vault' - params: { - encryptVolumes: true - keyVaultName: AiUnlimitedName - location: rg.location - tags: Tags - } -} - -module vaultAccessPolicy '../modules/vault/access-policy.bicep' = if (UseKeyVault == 'New') { - scope: rg - name: 'vault-access-policy' - params: { - vaultName: vault.outputs.name - accessPolicy: { - tenantId: subscription().tenantId - objectId: aiUnlimited.outputs.PrincipleId - permissions: { - keys: [ - 'Create' - 'Delete' - 'Get' - 'List' - 'Update' - 'Purge' - 'Recover' - 'Decrypt' - 'Encrypt' - 'Sign' - 'UnwrapKey' - 'Verify' - 'WrapKey' - 'GetRotationPolicy' - 'SetRotationPolicy' - ] - secrets: ['Get', 'Set', 'Delete', 'List', 'Purge'] - storage: ['Get'] - } - } - } -} - -module firewall '../modules/firewall.bicep' = { - scope: rg - name: 'firewall' - params: { - location: rg.location - name: SecurityGroup - accessCidrs: AccessCIDRs - sshAccess: false - aiUnlimitedAuthPort: AiUnlimitedAuthPort - aiUnlimitedGrpcPort: AiUnlimitedGrpcPort - aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort - // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort - aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort - aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort - jupyterHttpPort: JupyterHttpPort - sourceAppSecGroups: SourceAppSecGroups - detinationAppSecGroups: detinationAppSecGroups - tags: Tags - } -} - -module nlb '../modules/nlb.bicep' = { - scope: rg - name: 'loadbalancer' - params: { - name: AiUnlimitedName - location: rg.location - dnsPrefix: dnsLabelPrefix - aiUnlimitedAuthPort: AiUnlimitedAuthPort - aiUnlimitedGrpcPort: AiUnlimitedGrpcPort - aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort - // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort - aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort - aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort - jupyterHttpPort: JupyterHttpPort - tags: Tags - } -} - -module aiUnlimited '../modules/instance.bicep' = { - scope: rg - name: 'ai-unlimited' - params: { - location: rg.location - name: AiUnlimitedName - adminUsername: 'azureuser' - sshPublicKey: PublicKey.outputs.PublicKey - dnsLabelPrefix: dnsLabelPrefix - vmSize: InstanceType - subnetId: subnet.id - networkSecurityGroupID: firewall.outputs.Id - osVersion: OSVersion - cloudInitData: cloudInitData - usePersistentVolume: UsePersistentVolume - persistentVolumeSize: PersistentVolumeSize - existingPersistentVolume: ExistingPersistentVolume - nlbName: AiUnlimitedName - nlbPoolNames: nlb.outputs.nlbPools - usePublicIp: false - tags: Tags - } -} - -module PublicKey '../modules/public-key.bicep' = { - scope: rg - name: 'Public-Key' - params: { - Name: AiUnlimitedName - Location: deployment().location - VaultName: vault.outputs.name - RoleID: RoleDefinitionId - } -} - -resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - scope: subscription() - name: roleAssignmentName - properties: { - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', RoleDefinitionId) - principalId: aiUnlimited.outputs.PrincipleId - } -} - -output PublicIP string = nlb.outputs.PublicIp -output PrivateIP string = aiUnlimited.outputs.PrivateIP -output AiUnlimitedPublicHttpAccess string = concat('http://${nlb.outputs.PublicDns}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) -output AiUnlimitedPrivateHttpAccess string = concat('http://${aiUnlimited.outputs.PrivateIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) -output AiUnlimitedPublicGrpcAccess string = 'http://${nlb.outputs.PublicDns}:${AiUnlimitedGrpcPort}' -output AiUnlimitedPrivateGrpcAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedGrpcPort}' -output JupyterLabPublicHttpAccess string = 'http://${nlb.outputs.PublicDns}:${JupyterHttpPort}?token=${JupyterToken}' -output JupyterLabPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${JupyterHttpPort}?token=${JupyterToken}' -output SecurityGroup string = firewall.outputs.Id diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam deleted file mode 100644 index 9d74d63..0000000 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-with-nlb.bicepparam +++ /dev/null @@ -1,32 +0,0 @@ -using './all-in-one-with-nlb.bicep' - -param ResourceGroupName = 'ai-unlimited-workspace' -param AiUnlimitedName = '' -param OSVersion = 'Ubuntu-2004' -param InstanceType = 'Standard_D2s_v3' -param Network = '' -param Subnet = '' -param SecurityGroup = 'AiUnlimitedSecurityGroup' -param AccessCIDRs = [ - '0.0.0.0/0' -] -param JupyterHttpPort = 8888 -param AiUnlimitedAuthPort = 3000 -param AiUnlimitedGrpcPort = 3282 -// param AiUnlimitedSchedulerGrpcPort = 50051 -// param AiUnlimitedSchedulerHttpPort = 50061 -// param AiUnlimitedUIHttpPort = 80 -// param AiUnlimitedUIHttpsPort = 443 -param SourceAppSecGroups = [] -param detinationAppSecGroups = [] -param RoleDefinitionId = '' -param UseKeyVault = 'New' -param UsePersistentVolume = 'New' -param PersistentVolumeSize = 100 -param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.1.0' -param JupyterVersion = 'v0.1.0' -// param AiUnlimitedSchedulerVersion = 'latest' -param JupyterToken = 'USE_A_SECURE_TOKEN' /* TODO : please fix the value assigned to this parameter `uniqueString()` */ -param Tags = {} diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep deleted file mode 100644 index 1e62e1d..0000000 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicep +++ /dev/null @@ -1,275 +0,0 @@ -targetScope = 'subscription' - -@description('name for the resource group.') -param ResourceGroupName string = 'ai-unlimited-workspace' - -@description('Name for the Workspace service\'s virtual machine.') -param AiUnlimitedName string - -@description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') -@allowed([ - 'Ubuntu-1804' - 'Ubuntu-2004' - 'Ubuntu-2204' -]) -param OSVersion string = 'Ubuntu-2004' - -@description('The AI Unlimited VM type') -param InstanceType string = 'Standard_D2s_v3' - -@description('Name of the network to run the AI Unlimited service in') -param Network string - -@description('Name of the subnet to run the AI Unlimited service in') -param Subnet string - -@description('Name of the network security group') -param SecurityGroup string = 'AiUnlimitedSecurityGroup' - -@description('The CIDR ranges that can be used to communicate with the AI Unlimited service instance.') -param AccessCIDRs array = ['0.0.0.0/0'] - -@description('port to access the Jupyter Labs UI.') -param JupyterHttpPort int = 8888 - -@description('port to access the AI Unlimited auth service.') -param AiUnlimitedAuthPort int = 3000 - -@description('port to access the AI Unlimited service api.') -param AiUnlimitedGrpcPort int = 3282 - -// @description('port to access the AI Unlimited scheduler service grpc api.') -// var AiUnlimitedSchedulerGrpcPort = 50051 - -// @description('port to access the AI Unlimited scheduler service http api.') -var AiUnlimitedSchedulerHttpPort = 50061 - -// @description('port to access the AI Unlimited service UI http.') -var AiUnlimitedUIHttpPort = 80 - -// @description('port to access the AI Unlimited service UI https.') -var AiUnlimitedUIHttpsPort = 443 - -@description('Source Application Security Groups to access the AI Unlimited service api.') -param SourceAppSecGroups array = [] - -@description('Destination Application Security Groups to give access to AI Unlimited service instance.') -param detinationAppSecGroups array = [] - -@description('GUID of the AI Unlimited Role') -param RoleDefinitionId string - -@description('should we create a new Azure Key Vault for bootstrapping the AI Unlimited Engine nodes.') -@allowed(['New', 'None']) -param UseKeyVault string = 'New' - -@description('should we use a new or existing volume for persistent data on the AI Unlimited server.') -@allowed(['New', 'Existing']) -param UsePersistentVolume string = 'New' - -@description('size of the optional persistent disk to the AI Unlimited server.') -param PersistentVolumeSize int = 100 - -@description('Name of the existing persistent volume to attach. Must be in the same region and resourcegroup zone as the AI Unlimited server.') -param ExistingPersistentVolume string = 'NONE' - -@description('Container Version of the AI Unlimited service') -param AiUnlimitedVersion string = 'v0.3.0' - -@description('Container Version of the AI Unlimited UI service') -param AiUnlimitedUIVersion string = 'v0.1.0' - -@description('Container Version of the Jupyter Labs service') -param JupyterVersion string = 'v0.1.0' - -// @description('Container Version of the AI Unlimited scheduler service') -var AiUnlimitedSchedulerVersion = 'latest' - -@description('Join token for the Jupyter Labs service') -@secure() -param JupyterToken string - -@description('Tags to apply to all newly created resources, in the form of {"key_one":"value_one","key_two":"value_two"}') -param Tags object = {} - -var roleAssignmentName = guid(subscription().id, AiUnlimitedName, rg.id, RoleDefinitionId) -var dnsLabelPrefix = 'td${uniqueString(rg.id, deployment().name, AiUnlimitedName)}' - -// below are static and are not expected to be changed -var registry = 'teradata' -var workspaceRepository = 'ai-unlimited-workspaces' -var jupyterRepository = 'ai-unlimited-jupyter' -var workspaceSchedulerRepository = 'ai-unlimited-scheduler' -var workspaceUIRepository = 'ai-unlimited-workspaces-ui' - -var cloudInitData = base64(format( - loadTextContent('../../../scripts/all-in-one.cloudinit.yaml'), - base64(format( - loadTextContent('../../../scripts/ai-unlimited.service'), - registry, - workspaceRepository, - AiUnlimitedVersion, - AiUnlimitedAuthPort, - AiUnlimitedGrpcPort, - subscription().subscriptionId, - subscription().tenantId, - '--network-alias ai-unlimited' - )), - base64(format( - loadTextContent('../../../scripts/jupyter.service'), - registry, - jupyterRepository, - JupyterVersion, - JupyterHttpPort, - JupyterToken - )), - base64(format( - loadTextContent('../../../scripts/ai-unlimited-scheduler.service'), - registry, - workspaceSchedulerRepository, - AiUnlimitedSchedulerVersion, - // AiUnlimitedSchedulerGrpcPort, - AiUnlimitedSchedulerHttpPort - )), - base64(format( - loadTextContent('../../../scripts/ai-unlimited-ui.service'), - registry, - workspaceUIRepository, - AiUnlimitedUIVersion, - AiUnlimitedUIHttpPort, - AiUnlimitedAuthPort, - AiUnlimitedGrpcPort, - '--network-alias ai-unlimited' - )) -)) - -resource rg 'Microsoft.Resources/resourceGroups@2022-09-01' existing = { - name: ResourceGroupName -} - -resource network 'Microsoft.Network/virtualNetworks@2022-11-01' existing = { - scope: rg - name: Network -} - -resource subnet 'Microsoft.Network/virtualNetworks/subnets@2022-11-01' existing = { - parent: network - name: Subnet -} - -module vault '../modules/vault/vault.bicep' = if (UseKeyVault == 'New') { - scope: rg - name: 'vault' - params: { - encryptVolumes: true - keyVaultName: AiUnlimitedName - location: rg.location - tags: Tags - } -} - -module vaultAccessPolicy '../modules/vault/access-policy.bicep' = if (UseKeyVault == 'New') { - scope: rg - name: 'vault-access-policy' - params: { - vaultName: vault.outputs.name - accessPolicy: { - tenantId: subscription().tenantId - objectId: aiUnlimited.outputs.PrincipleId - permissions: { - keys: [ - 'Create' - 'Delete' - 'Get' - 'List' - 'Update' - 'Purge' - 'Recover' - 'Decrypt' - 'Encrypt' - 'Sign' - 'UnwrapKey' - 'Verify' - 'WrapKey' - 'GetRotationPolicy' - 'SetRotationPolicy' - ] - secrets: ['Get', 'Set', 'Delete', 'List', 'Purge'] - storage: ['Get'] - } - } - } -} - -module firewall '../modules/firewall.bicep' = { - scope: rg - name: 'firewall' - params: { - location: rg.location - name: SecurityGroup - accessCidrs: AccessCIDRs - sshAccess: false - aiUnlimitedAuthPort: AiUnlimitedAuthPort - aiUnlimitedGrpcPort: AiUnlimitedGrpcPort - aiUnlimitedSchedulerHttpPort: AiUnlimitedSchedulerHttpPort - // aiUnlimitedSchedulerGrpcPort: AiUnlimitedSchedulerGrpcPort - aiUnlimitedUIHttpPort: AiUnlimitedUIHttpPort - aiUnlimitedUIHttpsPort: AiUnlimitedUIHttpsPort - jupyterHttpPort: JupyterHttpPort - sourceAppSecGroups: SourceAppSecGroups - detinationAppSecGroups: detinationAppSecGroups - tags: Tags - } -} - -module aiUnlimited '../modules/instance.bicep' = { - scope: rg - name: 'ai-unlimited' - params: { - location: rg.location - name: AiUnlimitedName - adminUsername: 'azureuser' - sshPublicKey: PublicKey.outputs.PublicKey - dnsLabelPrefix: dnsLabelPrefix - vmSize: InstanceType - subnetId: subnet.id - networkSecurityGroupID: firewall.outputs.Id - osVersion: OSVersion - cloudInitData: cloudInitData - usePersistentVolume: UsePersistentVolume - persistentVolumeSize: PersistentVolumeSize - existingPersistentVolume: ExistingPersistentVolume - usePublicIp: true - tags: Tags - } -} - -module PublicKey '../modules/public-key.bicep' = { - scope: rg - name: 'Public-Key' - params: { - Name: AiUnlimitedName - Location: deployment().location - VaultName: vault.outputs.name - RoleID: RoleDefinitionId - } -} - -resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - scope: subscription() - name: roleAssignmentName - properties: { - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', RoleDefinitionId) - principalId: aiUnlimited.outputs.PrincipleId - } -} - -output PublicIP string = aiUnlimited.outputs.PublicIP -output PrivateIP string = aiUnlimited.outputs.PrivateIP -output AiUnlimitedPublicHttpAccess string = concat('http://${aiUnlimited.outputs.PublicIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) -output AiUnlimitedPrivateHttpAccess string = concat('http://${aiUnlimited.outputs.PrivateIP}', (AiUnlimitedUIHttpPort != 80 ? concat(':', string(AiUnlimitedUIHttpPort)) : '')) -output AiUnlimitedPublicGrpcAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${AiUnlimitedGrpcPort}' -output AiUnlimitedPrivateGrpcAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${AiUnlimitedGrpcPort}' -output JupyterLabPublicHttpAccess string = 'http://${aiUnlimited.outputs.PublicIP}:${JupyterHttpPort}?token=${JupyterToken}' -output JupyterLabPrivateHttpAccess string = 'http://${aiUnlimited.outputs.PrivateIP}:${JupyterHttpPort}?token=${JupyterToken}' -output SecurityGroup string = firewall.outputs.Id diff --git a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam b/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam deleted file mode 100644 index d99c519..0000000 --- a/deployments/azure/templates/bicep/all-in-one/all-in-one-without-lb.bicepparam +++ /dev/null @@ -1,32 +0,0 @@ -using './all-in-one-without-lb.bicep' - -param ResourceGroupName = 'ai-unlimited-workspace' -param AiUnlimitedName = '' -param OSVersion = 'Ubuntu-2004' -param InstanceType = 'Standard_D2s_v3' -param Network = '' -param Subnet = '' -param SecurityGroup = 'AiUnlimitedSecurityGroup' -param AccessCIDRs = [ - '0.0.0.0/0' -] -param JupyterHttpPort = 8888 -param AiUnlimitedAuthPort = 3000 -param AiUnlimitedGrpcPort = 3282 -// param AiUnlimitedSchedulerGrpcPort = 50051 -// param AiUnlimitedSchedulerHttpPort = 50061 -// param AiUnlimitedUIHttpPort = 80 -// param AiUnlimitedUIHttpsPort = 443 -param SourceAppSecGroups = [] -param detinationAppSecGroups = [] -param RoleDefinitionId = '' -param UseKeyVault = 'New' -param UsePersistentVolume = 'New' -param PersistentVolumeSize = 100 -param ExistingPersistentVolume = 'NONE' -param AiUnlimitedVersion = 'v0.3.0' -param AiUnlimitedUIVersion = 'v0.1.0' -param JupyterVersion = 'v0.1.0' -// param AiUnlimitedSchedulerVersion = 'latest' -param JupyterToken = 'USE_A_SECURE_TOKEN' -param Tags = {}