def post()

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 """