

{% set COMPUTE_URL_BASE = 'https://www.googleapis.com/compute/v1/' %}
{% set BASE_NAME = properties['baseName'] + '-' + env['name'] %}
{% set REGION = properties['zone'][:-2] %}
{% set DISK_SIZE = properties['zone'][:-2] %}
{% set GOOGLE_FACTORY = '1.0.16' %}

{% set NGINX_IMAGE = 'jwilder/nginx-proxy' %}
{% set LETSENCRYPT_IMAGE = 'jrcs/letsencrypt-nginx-proxy-companion' %}
{% set NGINX = 'nginx' %}
{% set LETSENCRYPT = 'letsencrypt' %}
{%- if properties['enableHttps'] %}
  {% set SERVER_URL = 'https://' + properties['domainName'] %}
{%- else %}
  {% set SERVER_URL = 'http://${COREOS_GCE_HOSTNAME}' %}
{%- endif %}

{% if properties['size'] == 'small' %}
  {% set DISK_SIZE = 30 %}
  {% set DISK_TYPE = 'pd-standard' %}
  {% set MACHINE_TYPE = 'custom-1-3072' %}
{% elif properties['size'] == 'large' %}
  {% set DISK_SIZE = 100 %}
  {% set DISK_TYPE = 'pd-ssd' %}
  {% set MACHINE_TYPE = 'custom-4-8192' %}
{% else %}
  {% set DISK_SIZE = 50 %}
  {% set DISK_TYPE = 'pd-ssd' %}
  {% set MACHINE_TYPE = 'custom-2-4096' %}
{% endif %}

{% macro GlobalComputeUrl(project, collection, name) -%}
{{ COMPUTE_URL_BASE }}projects/{{ project }}/global/{{ collection }}/{{ name }}
{%- endmacro %}

{% macro ZonalComputeUrl(project, zone, collection, name) -%}
{{ COMPUTE_URL_BASE }}projects/{{ project }}/zones/{{ zone }}/{{ collection }}/{{ name }}
{%- endmacro %}

{% macro RegionalComputeUrl(project, region, collection, name) -%}
{{ COMPUTE_URL_BASE }}projects/{{ project }}/regions/{{ region }}/{{ collection }}/{{ name }}
{%- endmacro %}

{% macro SqlInstanceName(project, region, dbName) -%}
{{ project }}:{{ region }}:{{ dbName }}
{%- endmacro %}

resources:
- name: {{ BASE_NAME }}-data
  type: compute.v1.disk
  properties:
    zone: {{ properties["zone"] }}
    sizeGb: {{ DISK_SIZE }}
    type: {{ ZonalComputeUrl(env['project'], properties['zone'], 'diskTypes', DISK_TYPE) }}

{%- if not properties['ipAddress'] %}
- name: {{ BASE_NAME }}-address
  type: compute.v1.address
  properties:
    name: {{ BASE_NAME }}-address
    region: {{ REGION }}
{%- endif %}

- name: {{ BASE_NAME }}
  type: compute.v1.instance
  properties:
    zone: {{ properties['zone'] }}
    machineType: {{ ZonalComputeUrl(env['project'], properties['zone'], 'machineTypes', MACHINE_TYPE) }}
    serviceAccounts:
    - email: {{ properties['serviceAccount'] }}
      scopes:
      - "https://www.googleapis.com/auth/cloud-platform"
    metadata:
      items:
      - key: user-data
        value: |
          #cloud-config
          write_files:
          - path: "/etc/teamcity/version"
            content: |
              TEAMCITY_VERSION={{ properties['teamcityVersion'] }}
          - path: "/etc/teamcity/database.properties"
            content: |
              # Database: MySQL

              connectionUrl=jdbc:mysql://google/{{ properties['database']['name'] }}?cloudSqlInstance={{ env['project'] }}:{{ REGION }}:{{ properties['database']['instance'] }}&socketFactory=com.google.cloud.sql.mysql.SocketFactory&useSSL=false
              connectionProperties.user={{ properties['database']['user'] }}

              maxConnections=50
              testOnBorrow=true
          - path: "/etc/teamcity/disabled-plugins.xml"
            content: |
              <?xml version="1.0" encoding="UTF-8"?>
              <disabled-plugins>
                <disabled-plugin name="cloud-amazon" />
                <disabled-plugin name="s3-artifact-storage" />
                <disabled-plugin name="vsphere" />
              </disabled-plugins>
          - path: "/etc/flatcar/update.conf"
            content: |
              REBOOT_STRATEGY="off"
{%- if properties['enableHttps'] %}
          - path: "/etc/teamcity/checkCertificate.sh"
            permissions: 0755
            content: |
              #!/bin/bash
              attempt=0
              while docker exec {{ LETSENCRYPT }} /app/cert_status | grep {{ properties['domainName'] }} > /dev/null; [[ $? -ne 0 ]]; do
                retry_in_mins=$((3**$attempt))
                echo "Will try to renew certificate for {{ SERVER_URL }} in $retry_in_mins minutes"
                sleep $((60 * $retry_in_mins))
                echo "Trying to renew certificate for {{ SERVER_URL }}..."
                docker exec {{ LETSENCRYPT }} /app/signal_le_service
                sleep 30
                attempt=$(($attempt + 1))
              done
{% endif %}
          coreos:
            units:
            - name: "format-mnt-data.service"
              enable: true
              content: |
                [Unit]
                Requires=network-online.target
                Before=teamcity-server.service mnt-data.mount
                ConditionPathExists=!/dev/mapper/app-data

                [Service]
                Type=oneshot
                ExecStart=/bin/bash -c \
                  '/usr/sbin/pvcreate /dev/disk/by-id/google-{{ BASE_NAME }}-data && \
                  /usr/sbin/vgcreate app /dev/disk/by-id/google-{{ BASE_NAME }}-data && \
                  /usr/sbin/lvcreate -l 100%%FREE -n data app && \
                  /usr/sbin/mkfs.ext4 /dev/mapper/app-data'

                [Install]
                WantedBy=multi-user.target

            - name: "mnt-data.mount"
              enable: true
              content: |
                [Unit]
                Before=teamcity-server.service
                After=format-mnt-data.service
                Requires=format-mnt-data.service
                ConditionVirtualization=!container
                Conflicts=umount.target

                [Mount]
                What=/dev/mapper/app-data
                Where=/mnt/data
                Type=ext4
                Options=

                [Install]
                RequiredBy=teamcity-server.service

            - name: "get-mysql-connector.service"
              enable: true
              content: |
                [Unit]
                Before=teamcity-server.service
                After=mnt-data.mount docker.service
                Requires=mnt-data.mount docker.service
                ConditionPathExists=!/mnt/data/teamcity-server/data/lib/jdbc/

                [Service]
                Type=oneshot
                ExecStart=/bin/mkdir -p /mnt/data/teamcity-server/data/lib/jdbc
                ExecStart=/bin/wget -O /mnt/data/teamcity-server/data/lib/jdbc/mysql-socket-factory.jar \
                  https://repo.maven.apache.org/maven2/com/google/cloud/sql/mysql-socket-factory/{{ GOOGLE_FACTORY }}/mysql-socket-factory-{{ GOOGLE_FACTORY }}.jar
                ExecStart=/bin/wget -O pom.xml https://repo.maven.apache.org/maven2/com/google/cloud/sql/mysql-socket-factory/{{ GOOGLE_FACTORY }}/mysql-socket-factory-{{ GOOGLE_FACTORY }}.pom
                ExecStart=/bin/bash -c 'docker run --rm -v "$(pwd)":/opt/maven -v /mnt/data/teamcity-server/data/lib/jdbc:/opt/maven/target/dependency -w /opt/maven maven:alpine mvn dependency:copy-dependencies && docker rmi maven:alpine'
                ExecStart=/bin/rm pom.xml

                [Install]
                WantedBy=multi-user.target

            - name: "get-google-plugins.service"
              enable: true
              content: |
                [Unit]
                Before=teamcity-server.service
                After=mnt-data.mount
                Requires=mnt-data.mount
                ConditionPathExists=!/mnt/data/teamcity-server/data/plugins/google-plugins.txt

                [Service]
                Type=oneshot
                ExecStart=/bin/mkdir -p /mnt/data/teamcity-server/data/plugins
                ExecStart=/bin/curl https://raw.githubusercontent.com/JetBrains/teamcity-google-template/master/google-plugins.txt \
                  -o /mnt/data/teamcity-server/data/plugins/google-plugins.txt
                ExecStart=/bin/bash -c 'cd /mnt/data/teamcity-server/data/plugins && curl -K google-plugins.txt'

                [Install]
                WantedBy=multi-user.target

            - name: "prepare-config.service"
              enable: true
              content: |
                [Unit]
                Before=teamcity-server.service
                After=mnt-data.mount
                Requires=mnt-data.mount network-online.target
                ConditionPathExists=!/mnt/data/teamcity-server/data/config

                [Service]
                Type=oneshot
                ExecStart=/bin/mkdir -p /mnt/data/teamcity-server/data/config
                ExecStart=/bin/mv /etc/teamcity/database.properties /mnt/data/teamcity-server/data/config/
                ExecStart=/bin/mv /etc/teamcity/disabled-plugins.xml /mnt/data/teamcity-server/data/config/

                [Install]
                WantedBy=multi-user.target

            - name: "teamcity-server.service"
              command: "start"
              content: |
                [Unit]
                Description=TeamCity Server
                After=docker.service mnt-data.mount get-mysql-connector.service get-google-plugins.service prepare-config.service
                Requires=docker.service mnt-data.mount get-mysql-connector.service get-google-plugins.service prepare-config.service

                [Service]
                TimeoutStartSec=1200s
                EnvironmentFile=/etc/teamcity/version
{%- raw %}
                ExecStartPre=/bin/sh -c "docker images --filter 'before=jetbrains/teamcity-server:${TEAMCITY_VERSION}' --format '{{.ID}} {{.Repository}}' | grep 'jetbrains/teamcity-server' | grep -Eo '^[^ ]+' | xargs -r docker rmi"
{%- endraw %}
                ExecStartPre=/usr/bin/docker create \
                  -e TEAMCITY_SERVER_MEM_OPTS="-Xmx$(($(grep MemTotal /proc/meminfo | awk '{print $2}') / 2))k -XX:MaxPermSize=270m -XX:ReservedCodeCacheSize=350m" \
{%- if properties['enableHttps'] %}
                  -e VIRTUAL_PORT=8111 \
                  -e VIRTUAL_HOST={{ properties['domainName'] }} \
                  -e LETSENCRYPT_HOST={{ properties['domainName'] }} \
  {%- if properties['domainOwnerEmail'] %}
                  -e LETSENCRYPT_EMAIL={{ properties['domainOwnerEmail'] }} \
  {%- endif %}
{%- else %}
                  -p 80:8111 \
{%- endif %}
                  -v /mnt/data/teamcity-server/data:/data/teamcity_server/datadir \
                  -v /mnt/data/teamcity-server/logs:/opt/teamcity/logs \
                  -v /mnt/resource/teamcity-server/temp:/opt/teamcity/temp \
                  --name teamcity-server \
                  jetbrains/teamcity-server:${TEAMCITY_VERSION}
                ExecStartPre=/bin/sh -c "echo 'gcp' > dist && docker cp dist teamcity-server:/opt/teamcity/webapps/ROOT/WEB-INF/DistributionType.txt && rm dist"
                ExecStart=/usr/bin/docker start teamcity-server -a
                ExecStop=-/usr/bin/docker exec teamcity-server /opt/teamcity/bin/teamcity-server.sh stop 60
                ExecStopPost=-/usr/bin/docker stop teamcity-server
                ExecStopPost=-/usr/bin/docker rm teamcity-server
                Restart=always

                [Install]
                WantedBy=multi-user.target

            - name: "teamcity-agent.service"
              command: "start"
              content: |
                [Unit]
                Description=TeamCity Agent
                After=teamcity-server.service coreos-metadata.service
                Requires=teamcity-server.service coreos-metadata.service

                [Service]
                TimeoutStartSec=1200s
                EnvironmentFile=/etc/teamcity/version
                EnvironmentFile=/run/metadata/coreos
{%- raw %}
                ExecStartPre=/bin/sh -c "docker images --filter 'before=jetbrains/teamcity-agent:${TEAMCITY_VERSION}' --format '{{.ID}} {{.Repository}}' | grep 'jetbrains/teamcity-agent' | grep -Eo '^[^ ]+' | xargs -r docker rmi" %}
{%- endraw %}
                ExecStart=/usr/bin/docker run \
                  -v /mnt/data/teamcity-agent/conf:/opt/buildagent/conf \
                  -v /mnt/data/teamcity-agent/logs:/opt/buildagent/logs \
                  -v /mnt/data/teamcity-agent/plugins:/opt/buildagent/plugins \
                  -v /mnt/data/teamcity-agent/system:/opt/buildagent/system \
                  -v /mnt/resource/teamcity-agent/temp:/opt/buildagent/temp \
                  -v /mnt/resource/teamcity-server/temp:/opt/teamcity/temp \
                  -v /mnt/data/teamcity-agent/tools:/opt/buildagent/tools \
                  --privileged \
                  -e DOCKER_IN_DOCKER=start \
                  -e SERVER_URL={{ SERVER_URL }} \
                  -e AGENT_NAME=Default \
                  --name teamcity-agent \
                  jetbrains/teamcity-agent:${TEAMCITY_VERSION}
                ExecStop=-/usr/bin/docker exec teamcity-agent /opt/buildagent/bin/agent.sh stop
                ExecStopPost=-/usr/bin/docker stop teamcity-agent
                ExecStopPost=-/usr/bin/docker rm teamcity-agent
                Restart=always

                [Install]
                WantedBy=multi-user.target

{%- if properties['enableHttps'] %}
            - name: "{{ NGINX }}-directories.service"
              enable: true
              content: |
                [Unit]
                Before={{ NGINX }}.service
                After=mnt-data.mount docker.service
                Requires=mnt-data.mount docker.service
                ConditionPathExists=!/opt/domains/vhost.d/default

                [Service]
                Type=oneshot
                ExecStart=/bin/mkdir -p /opt/domains/certs
                ExecStart=/bin/mkdir -p /opt/domains/vhost.d
                ExecStart=/bin/mkdir -p /opt/domains/nginx/html
                ExecStart=/bin/sh -c "echo 'proxy_read_timeout     1200;' >> /opt/domains/vhost.d/default"
                ExecStart=/bin/sh -c "echo 'proxy_connect_timeout  240;'  >> /opt/domains/vhost.d/default"
                ExecStart=/bin/sh -c "echo 'client_max_body_size   0;'    >> /opt/domains/vhost.d/default"

                [Install]
                WantedBy=multi-user.target

            - name: "{{ NGINX }}.service"
              command: "start"
              content: |
                [Unit]
                Description=NGINX reverse proxy
                Requires=docker.service {{ NGINX }}-directories.service

                [Service]
                TimeoutStartSec=1200s
                ExecStart=/usr/bin/docker run \
                  -p 80:80 \
                  -p 443:443 \
                  -v /opt/domains/certs:/etc/nginx/certs:ro \
                  -v /opt/domains/vhost.d:/etc/nginx/vhost.d \
                  -v /opt/domains/nginx/html:/usr/share/nginx/html \
                  -v /var/run/docker.sock:/tmp/docker.sock:ro \
                  --name {{ NGINX }} \
                  {{ NGINX_IMAGE }}
                  ExecStop=-/usr/bin/docker stop {{ NGINX }}
                  ExecStopPost=-/usr/bin/docker rm {{ NGINX }}
                Restart=always

                [Install]
                WantedBy=multi-user.target

            - name: "{{ LETSENCRYPT }}.service"
              command: "start"
              content: |
                [Unit]
                Description=Let's Encrypt
                Requires=docker.service
                After={{ NGINX }}.service
                Before=teamcity-server.service

                [Service]
                TimeoutStartSec=1200s
                ExecStart=/usr/bin/docker run \
                  -v /opt/domains/certs:/etc/nginx/certs:rw \
                  --volumes-from {{ NGINX }} \
                  -v /var/run/docker.sock:/var/run/docker.sock:ro \
                  --name {{ LETSENCRYPT }} \
                  {{ LETSENCRYPT_IMAGE }}
                ExecStop=-/usr/bin/docker stop {{ LETSENCRYPT }}
                ExecStopPost=-/usr/bin/docker rm {{ LETSENCRYPT }}
                Restart=always

                [Install]
                WantedBy=multi-user.target
{%- endif %}

            - name: "report-waiter-status.service"
              enable: true
              command: "start"
              content: |
                [Unit]
{%- if properties['enableHttps'] %}
                Requires=docker.service teamcity-server.service {{ NGINX }}.service {{ LETSENCRYPT }}.service
{%- else %}
                Requires=docker.service teamcity-server.service
{%- endif  %}
                Before=teamcity-agent.service
                ConditionPathExists=!/etc/teamcity/waiter

                [Service]
                Type=oneshot
                EnvironmentFile=/run/metadata/coreos
{%- if properties['enableHttps'] %}
                ExecStartPre=/bin/bash /etc/teamcity/checkCertificate.sh
{%- endif  %}
                ExecStartPre=/bin/bash -c "until $(curl --output /dev/null --silent --fail {{ SERVER_URL }}); do echo 'Waiting for success response from {{ SERVER_URL }}'; sleep 10; done;"
                ExecStart=/usr/bin/docker run --rm  -e "CLOUDSDK_CORE_DISABLE_PROMPTS=1" google/cloud-sdk:alpine gcloud beta runtime-config configs variables set success/{{ properties['waiter']['name'] }} success --config-name {{ properties['waiter']['config'] }}
                ExecStartPost=/usr/bin/docker rmi google/cloud-sdk:alpine
                ExecStartPost=/bin/touch /etc/teamcity/waiter

                [Install]
                WantedBy=multi-user.target
    disks:
      - deviceName: boot
        type: PERSISTENT
        autoDelete: true
        boot: true
        initializeParams:
          diskName: {{ BASE_NAME }}-disk
          sourceImage: {{ GlobalComputeUrl('teamcitytest-166414', 'images', 'flatcar-stable') }}
          diskSizeGb: 14
      - deviceName: {{ BASE_NAME }}-data
        type: PERSISTENT
        autoDelete: true
        source: $(ref.{{ BASE_NAME }}-data.selfLink)
    networkInterfaces:
      - accessConfigs:
        - name: external-nat
          type: ONE_TO_ONE_NAT
{%- if properties['ipAddress'] %}
          natIP: {{ properties['ipAddress'] }}
{%- else %}
          natIP: $(ref.{{ BASE_NAME }}-address.address)
{%- endif %}
        network: {{ GlobalComputeUrl(env['project'], 'networks', properties['network']) }}
{%- if properties['subnetwork'] %}
        subnetwork: {{ RegionalComputeUrl(env['project'], REGION, 'subnetworks', properties['subnetwork']) }}
{%- endif %}
    tags:
      items:
        - http-server
{%- if properties['enableHttps'] %}
        - https-server
{%- endif %}
        - ssh-server

outputs:
  - name: ip
    value: $(ref.{{ BASE_NAME }}.networkInterfaces[0].accessConfigs[0].natIP)
