AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template to create a VS Code server on EC2'

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Network Configuration"
        Parameters:
          - VpcId
          - SubnetId
      - Label:
          default: "Instance Configuration"
        Parameters:
          - InstanceType
          - VSCodeServerName
          - VSCodeServerPassword
          - LatestAmiId
      - Label:
          default: "Access Control"
        Parameters:
          - SourceIPAddress
    ParameterLabels:
      VpcId:
        default: "VPCId"
      SubnetId:
        default: "SubnetId"

Parameters:
  VSCodeServerPassword:
    Description: The password for the VS Code server
    Type: String
    NoEcho: true
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Description: Latest AMI ID for Amazon Linux 2023, You don't need to change this value.
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64'
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VPC in which to launch VS Code server instance
  SubnetId:
    Type: AWS::EC2::Subnet::Id
    Description: Public Subnet in which to launch VS Code server instance within VPC
  VSCodeServerName:
    Type: String
    Description: EC2 instance name for VS Code server
    Default: 'VSCode-Server'
  InstanceType:
    Type: String
    Description: EC2 instannce type for VS Code server. Recommended to use t3.medium or larger for best performance
    Default: 't3.large'
    AllowedValues:
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
  SourceIPAddress:
    Type: String
    Description: "Allowed source IP address (CIDR notation) to http to the VS Code server. It is recommeded to restrict to your client ip address. Please refer to https://ifconfig.me/"
    Default: 0.0.0.0/0
    ConstraintDescription: "Must be a valid CIDR notation IP address range (e.g., 0.0.0.0/0)"

Resources:
  VSCodeServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow SSH and VS Code server access
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: !Ref SourceIPAddress
      VpcId: !Ref VpcId
  VSCodeServerInstance:
    Type: AWS::EC2::Instance
    DependsOn: VSCodeServerSecurityGroup
    Properties:
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          GroupSet: 
          - !Ref VSCodeServerSecurityGroup
          SubnetId: !Ref SubnetId
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 30
            VolumeType: gp3
      Tags:
        - Key: Name
          Value: !Ref VSCodeServerName
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash

          echo "####################################################################################################"
          echo "Trying to install utilities"
          dnf update -y && rm -rf /var/lib/rpm/.rpm.lock
          dnf install -y docker git pip && systemctl start docker && chmod 777 /var/run/docker.sock

          echo "####################################################################################################"
          echo "Trying to install nodejs"
          dnf update -y && rm -rf /var/lib/rpm/.rpm.lock
          curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - && rm -rf /var/lib/rpm/.rpm.lock && dnf install nodejs -y

          echo "####################################################################################################"
          echo "Trying to install code-server"
          dnf update -y && rm -rf /var/lib/rpm/.rpm.lock
          curl -fsSL https://code-server.dev/install.sh | sudo bash - 
          mkdir -p /home/ec2-user/.config/code-server
          echo "bind-addr: 0.0.0.0:8080" > /home/ec2-user/.config/code-server/config.yaml
          echo "auth: password" >> /home/ec2-user/.config/code-server/config.yaml
          echo "password: ${VSCodeServerPassword}" >> /home/ec2-user/.config/code-server/config.yaml
          echo "cert: false" >> /home/ec2-user/.config/code-server/config.yaml
          #sudo systemctl enable code-server@$USER
          su - ec2-user -c 'nohup code-server &'
          chown -R ec2-user:ec2-user /home/ec2-user/.config

          echo "####################################################################################################"
          echo "Trying to install kubectl"
          dnf update -y && rm -rf /var/lib/rpm/.rpm.lock
          curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
          chmod +x ./kubectl
          mv ./kubectl /usr/local/bin

          echo "####################################################################################################"
          echo "Trying to configure shell environment"
          echo "alias ll='ls -la'" >> /home/ec2-user/.bash_profile
          echo "alias h='history'" >> /home/ec2-user/.bash_profile
          echo "alias rm='rm -i'" >> /home/ec2-user/.bash_profile
          echo "alias k='kubectl'" >> /home/ec2-user/.bash_profile
  
Outputs:
  VSCodeServerURL:
    Description: URL to access the VS Code server
    Value: !Sub 'http://${VSCodeServerInstance.PublicDnsName}:8080'
