AWSTemplateFormatVersion: 2010-09-09
Description: >-
  This template deploys a Spring Boot application to AWS CloudFormation.

Parameters:
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m1.small
      - m1.medium
      - m1.large
      - m1.xlarge
      - m2.xlarge
      - m2.2xlarge
      - m2.4xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.12xlarge
      - m5.24xlarge
      - m5d.large
      - m5d.xlarge
      - m5d.2xlarge
      - m5d.4xlarge
      - m5d.12xlarge
      - m5d.24xlarge
      - c1.medium
      - c1.xlarge
      - c3.large
      - c3.xlarge
      - c3.2xlarge
      - c3.4xlarge
      - c3.8xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
    ConstraintDescription: must be a valid EC2 instance type.
  AMI:
    Description: >-
      The ID of the Amazon Machine Image (AMI) that you want to use to launch
      the instances.
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: EC2 Instance Configuration
        Parameters:
          - KeyName
          - InstanceType
          - AMI
    ParameterLabels:
      KeyName:
        default: EC2 Key Pair
      InstanceType:
        default: EC2 Instance Type
      AMI:
        default: Amazon Machine Image (AMI)

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 15.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-VPC

  PublicSubnet:
    Type: AWS::EC2::Subnet
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 15.0.0.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PublicSubnet

  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-IGW
  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    DependsOn:
      - VPC
      - IGW
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn:
      - VPC
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PublicRouteTable

  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    DependsOn:
      - PublicRouteTable
      - PublicSubnet
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  SpringBootSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn:
      - VPC
    Properties:
      GroupDescription: Security group for Spring Boot application
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SpringBootSG

  S3CodeBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join
        - '-'
        - - code-bucket
          - !Ref AWS::Region
          - !Select
            - 0
            - !Split
              - '-'
              - !Select
                - 2
                - !Split
                  - '/'
                  - !Ref 'AWS::StackId'
      AccessControl: Private
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-S3CodeBucket

  SprerBootEC2:
    Type: AWS::EC2::Instance
    DependsOn:
      - SpringBootSG
      - PublicSubnet
    Properties:
      ImageId: !Ref AMI
      InstanceType: !Ref InstanceType
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref SpringBootSG
          SubnetId: !Ref PublicSubnet
      UserData:
        Fn::Base64: !Sub
          - |
            #!/bin/bash
            sudo yum update -y
            sudo amazon-linux-extras enable java-openjdk11 -y
            sudo amazon-linux-extras install java-openjdk11 -y
            sudo yum install -y java-11-openjdk-devel
          - {}
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-SpringBootEC2

Outputs:
  S3CodeBucket:
    Description: S3 bucket to store the Spring Boot application code
    Value: !Ref S3CodeBucket
  SpringBootEC2:
    Description: Spring Boot EC2 instance
    Value: !Ref SprerBootEC2
  SpringBootEC2PublicIP:
    Description: Spring Boot EC2 instance public IP
    Value: !GetAtt SprerBootEC2.PublicIp
  SpringBootEC2PublicDNS:
    Description: Spring Boot EC2 instance public DNS
    Value: !GetAtt SprerBootEC2.PublicDnsName
