in source/soca/cluster_web_ui/api/v1/dcv/create_linux_desktop.py [0:0]
def post(self, session_number):
"""
Create a new DCV desktop session (Linux)
---
tags:
- DCV
parameters:
- in: body
name: body
schema:
required:
- instance_type
- disk_size
- session_number
- instance_ami
- subnet_id
- hibernate
properties:
instance_type:
type: string
description: Type of EC2 instance to provision
disk_size:
type: string
description: EBS size to provision for root device
session_number:
type: string
description: DCV Session Number
session_name:
type: string
description: DCV Session Name
instance_ami:
type: string
description: Custom AMI to use
subnet_id:
type: string
description: Specify a subnet id to launch the EC2
hibernate:
type: string
description: True/False.
user:
type: string
description: owner of the session
responses:
200:
description: Pair of user/token is valid
401:
description: Invalid user/token pair
"""
parser = reqparse.RequestParser()
parser.add_argument("instance_type", type=str, location='form')
parser.add_argument("disk_size", type=str, location='form')
parser.add_argument("session_name", type=str, location='form')
parser.add_argument("instance_ami", type=str, location='form')
parser.add_argument("subnet_id", type=str, location='form')
parser.add_argument("hibernate", type=str, location='form')
args = parser.parse_args()
logger.info(f"Received parameter for new Linux DCV session: {args}")
if session_number is None:
return errors.all_errors('CLIENT_MISSING_PARAMETER', "session_number not found in URL. Endpoint is /api/dcv/desktop/<session_number>/linux")
else:
args["session_number"] = str(session_number)
try:
user = request.headers.get("X-SOCA-USER")
if user is None:
return errors.all_errors("X-SOCA-USER_MISSING")
if not args["hibernate"]:
args["hibernate"] = False
elif args["hibernate"].lower() == "false":
args["hibernate"] = False
elif args["hibernate"].lower() == "true":
args["hibernate"] = True
else:
return errors.all_errors("DCV_LAUNCH_ERROR", f"hibernate must be either true or false")
if args["instance_type"] is None:
return errors.all_errors('CLIENT_MISSING_PARAMETER', "instance_type (str) is required.")
args["disk_size"] = 30 if args["disk_size"] is None else args["disk_size"]
try:
args["disk_size"] = int(args["disk_size"])
except ValueError:
return errors.all_errors("DCV_LAUNCH_ERROR", f"disk_size must be an integer")
try:
if int(args["session_number"]) > int(config.Config.DCV_LINUX_SESSION_COUNT):
return errors.all_errors("DCV_LAUNCH_ERROR", f"session_number {args['session_number']} is greater than the max number of session allowed ({config.Config.DCV_LINUX_SESSION_COUNT}). Contact admin for increase.")
except Exception as err:
return errors.all_errors("DCV_LAUNCH_ERROR", f"Session Number {args['session_number']} must be a number. Err: {err}")
session_uuid = str(uuid.uuid4())
region = os.environ["AWS_DEFAULT_REGION"]
instance_type = args["instance_type"]
soca_configuration = read_secretmanager.get_soca_configuration()
instance_profile = soca_configuration["ComputeNodeInstanceProfileArn"]
security_group_id = soca_configuration["ComputeNodeSecurityGroup"]
if session_already_exist(args["session_number"]) is True:
return errors.all_errors("DCV_LAUNCH_ERROR", f"Session Number {args['session_number']} is already used by an active desktop. Terminate it first before being able to use the same number")
# sanitize session_name, limit to 255 chars
if args["session_name"] is None:
session_name = 'LinuxDesktop' + str(args["session_number"])
else:
session_name = re.sub(r'\W+', '', args["session_name"])[:255]
if session_name == "":
# handle case when session name specified by user only contains invalid char
session_name = 'LinuxDesktop' + str(args["session_number"])
if args["instance_ami"] is None or args["instance_ami"] == "base":
image_id = soca_configuration["CustomAMI"]
base_os = read_secretmanager.get_soca_configuration()['BaseOS']
else:
if len(args["instance_ami"].split(",")) != 2:
return errors.all_errors("DCV_LAUNCH_ERROR", f"Invalid format for instance_ami,base_os : {args['instance_ami']}")
image_id = args["instance_ami"].split(',')[0]
base_os = args["instance_ami"].split(',')[1]
if not image_id.startswith("ami-"):
return errors.all_errors("DCV_LAUNCH_ERROR", f"AMI {image_id} does not seems to be valid. Must start with ami-<id>")
else:
if validate_ec2_image(image_id) is False:
return errors.all_errors("DCV_LAUNCH_ERROR",
f"AMI {image_id} does not seems to be registered on SOCA. Refer to https://awslabs.github.io/scale-out-computing-on-aws/web-interface/create-virtual-desktops-images/")
user_data = '''#!/bin/bash -x
export PATH=$PATH:/usr/local/bin
if [[ "''' + base_os + '''" == "centos7" ]] || [[ "''' + base_os + '''" == "rhel7" ]];
then
yum install -y python3-pip
PIP=$(which pip3)
$PIP install awscli
yum install -y nfs-utils # enforce install of nfs-utils
else
yum install -y python3-pip
PIP=$(which pip3)
$PIP install awscli
fi
if [[ "''' + base_os + '''" == "amazonlinux2" ]];
then
/usr/sbin/update-motd --disable
fi
GET_INSTANCE_TYPE=$(curl http://169.254.169.254/latest/meta-data/instance-type)
echo export "SOCA_DCV_AUTHENTICATOR="https://''' + soca_configuration[
'SchedulerPrivateDnsName'] + ''':''' + config.Config.FLASK_PORT + '''/api/dcv/authenticator"" >> /etc/environment
echo export "SOCA_DCV_SESSION_ID="''' + str(session_uuid) + '''"" >> /etc/environment
echo export "SOCA_CONFIGURATION="''' + str(soca_configuration['ClusterId']) + '''"" >> /etc/environment
echo export "SOCA_DCV_OWNER="''' + user + '''"" >> /etc/environment
echo export "SOCA_BASE_OS="''' + str(base_os) + '''"" >> /etc/environment
echo export "SOCA_JOB_TYPE="dcv"" >> /etc/environment
echo export "SOCA_INSTALL_BUCKET="''' + str(soca_configuration['S3Bucket']) + '''"" >> /etc/environment
echo export "SOCA_FSX_LUSTRE_BUCKET="false"" >> /etc/environment
echo export "SOCA_FSX_LUSTRE_DNS="false"" >> /etc/environment
echo export "SOCA_INSTALL_BUCKET_FOLDER="''' + str(soca_configuration['S3InstallFolder']) + '''"" >> /etc/environment
echo export "SOCA_INSTANCE_TYPE=$GET_INSTANCE_TYPE" >> /etc/environment
echo export "SOCA_HOST_SYSTEM_LOG="/apps/soca/''' + str(
soca_configuration['ClusterId']) + '''/cluster_node_bootstrap/logs/desktop/''' + user + '''/''' + session_name + '''/$(hostname -s)"" >> /etc/environment
echo export "AWS_DEFAULT_REGION="''' + region + '''"" >> /etc/environment
echo export "SOCA_AUTH_PROVIDER="''' + str(soca_configuration['AuthProvider']).lower() + '''"" >> /etc/environment
echo export "AWS_STACK_ID=${AWS::StackName}" >> /etc/environment
echo export "AWS_DEFAULT_REGION=${AWS::Region}" >> /etc/environment
# Required for proper EBS tagging
echo export "SOCA_JOB_ID="''' + str(session_name) + '''"" >> /etc/environment
echo export "SOCA_JOB_OWNER="''' + user + '''"" >> /etc/environment
echo export "SOCA_JOB_PROJECT="dcv"" >> /etc/environment
echo export "SOCA_JOB_QUEUE="dcv"" >> /etc/environment
source /etc/environment
AWS=$(which aws)
# Give yum permission to the user on this specific machine
echo "''' + user + ''' ALL=(ALL) /bin/yum" >> /etc/sudoers
mkdir -p /apps
mkdir -p /data
FS_DATA_PROVIDER='''+soca_configuration['FileSystemDataProvider']+'''
FS_DATA='''+soca_configuration['FileSystemData']+'''
FS_APPS_PROVIDER='''+soca_configuration['FileSystemAppsProvider']+'''
FS_APPS='''+soca_configuration['FileSystemApps']+'''
if [[ "$FS_DATA_PROVIDER" == "fsx_lustre" ]] || [[ "$FS_APPS_PROVIDER" == "fsx_lustre" ]]; then
if [[ -z "$(rpm -qa lustre-client)" ]]; then
# Install FSx for Lustre Client
if [[ "$SOCA_BASE_OS" == "amazonlinux2" ]]; then
amazon-linux-extras install -y lustre2.10
else
kernel=$(uname -r)
machine=$(uname -m)
echo "Found kernel version: $kernel running on: $machine"
yum -y install wget
if [[ $kernel == *"3.10.0-957"*$machine ]]; then
yum -y install https://downloads.whamcloud.com/public/lustre/lustre-2.10.8/el7/client/RPMS/x86_64/kmod-lustre-client-2.10.8-1.el7.x86_64.rpm
yum -y install https://downloads.whamcloud.com/public/lustre/lustre-2.10.8/el7/client/RPMS/x86_64/lustre-client-2.10.8-1.el7.x86_64.rpm
elif [[ $kernel == *"3.10.0-1062"*$machine ]]; then
wget https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-rpm-public-key.asc -O /tmp/fsx-rpm-public-key.asc
rpm --import /tmp/fsx-rpm-public-key.asc
wget https://fsx-lustre-client-repo.s3.amazonaws.com/el/7/fsx-lustre-client.repo -O /etc/yum.repos.d/aws-fsx.repo
sed -i 's#7#7.7#' /etc/yum.repos.d/aws-fsx.repo
yum clean all
yum install -y kmod-lustre-client lustre-client
elif [[ $kernel == *"3.10.0-1127"*$machine ]]; then
wget https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-rpm-public-key.asc -O /tmp/fsx-rpm-public-key.asc
rpm --import /tmp/fsx-rpm-public-key.asc
wget https://fsx-lustre-client-repo.s3.amazonaws.com/el/7/fsx-lustre-client.repo -O /etc/yum.repos.d/aws-fsx.repo
sed -i 's#7#7.8#' /etc/yum.repos.d/aws-fsx.repo
yum clean all
yum install -y kmod-lustre-client lustre-client
elif [[ $kernel == *"3.10.0-1160"*$machine ]]; then
wget https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-rpm-public-key.asc -O /tmp/fsx-rpm-public-key.asc
rpm --import /tmp/fsx-rpm-public-key.asc
wget https://fsx-lustre-client-repo.s3.amazonaws.com/el/7/fsx-lustre-client.repo -O /etc/yum.repos.d/aws-fsx.repo
yum clean all
yum install -y kmod-lustre-client lustre-client
elif [[ $kernel == *"4.18.0-193"*$machine ]]; then
# FSX for Lustre on aarch64 is supported only on 4.18.0-193
wget https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-rpm-public-key.asc -O /tmp/fsx-rpm-public-key.asc
rpm --import /tmp/fsx-rpm-public-key.asc
wget https://fsx-lustre-client-repo.s3.amazonaws.com/centos/7/fsx-lustre-client.repo -O /etc/yum.repos.d/aws-fsx.repo
yum clean all
yum install -y kmod-lustre-client lustre-client
else
echo "ERROR: Can't install FSx for Lustre client as kernel version: $kernel isn't matching expected versions: (x86_64: 3.10.0-957, -1062, -1127, -1160, aarch64: 4.18.0-193)!"
fi
fi
fi
fi
if [[ "$FS_DATA_PROVIDER" == "efs" ]]; then
echo "$FS_DATA:/ /data nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport 0 0" >> /etc/fstab
elif [[ "$FS_DATA_PROVIDER" == "fsx_lustre" ]]; then
FSX_ID=$(echo $FS_DATA | cut -d. -f1)
FSX_DATA_MOUNT_NAME=$($AWS fsx describe-file-systems --file-system-ids $FSX_ID --query FileSystems[].LustreConfiguration.MountName --output text)
echo "$FS_DATA@tcp:/$FSX_DATA_MOUNT_NAME /data lustre defaults,noatime,flock,_netdev 0 0" >> /etc/fstab
fi
if [[ "$FS_APPS_PROVIDER" == "efs" ]]; then
echo "$FS_APPS:/ /apps nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport 0 0" >> /etc/fstab
elif [[ "$FS_APPS_PROVIDER" == "fsx_lustre" ]]; then
FSX_ID=$(echo $FS_APPS | cut -d. -f1)
FSX_APPS_MOUNT_NAME=$($AWS fsx describe-file-systems --file-system-ids $FSX_ID --query FileSystems[].LustreConfiguration.MountName --output text)
echo "$FS_APPS@tcp:/$FSX_APPS_MOUNT_NAME /apps lustre defaults,noatime,flock,_netdev 0 0" >> /etc/fstab
fi
FS_MOUNT=0
mount -a
while [[ $? -ne 0 ]] && [[ $FS_MOUNT -lt 5 ]]
do
SLEEP_TIME=$(( RANDOM % 60 ))
echo "Failed to mount FS, retrying in $SLEEP_TIME seconds and Loop $FS_MOUNT/5..."
sleep $SLEEP_TIME
((FS_MOUNT++))
mount -a
done
# Configure Chrony
yum remove -y ntp
yum install -y chrony
mv /etc/chrony.conf /etc/chrony.conf.original
echo -e """