<commit_before>---
# Additional playbook that runs on a group first host only and gather facts from all hosts
# This is required to allow deploying on fraction of group hosts
# For example rolling updates and deploying only to single hosts of a group
#
# For example below command will deploy only to ae-dev2-epoch-n0 host in tag_env_dev2 group
# ansible-playbook --limit="ae-dev2-epoch-n0" --extra-vars "hosts_group=tag_env_dev2" deploy.yml

- name: Facts setup
  hosts: all
  remote_user: epoch
  # Executor facts will be gathered anyway in the task below
  gather_facts: no
  tasks:
    - name: Gather facts from all hosts in {{ hosts_group }} group
      setup:
      run_once: yes
      delegate_to: "{{ item }}"
      delegate_facts: yes
      with_items: "{{ groups[hosts_group] }}"
    - name: Fetch node sync public key
      command: "{{ ansible_env.HOME }}/node/bin/epoch peer_key"
      ignore_errors: yes
      register: key_command
    - name: Register sync public key as fact
      set_fact:
        sync_public_key: "{{ key_command.stdout }}"
      when: key_command.rc == 0

- name: Deploy epoch package
  hosts: all
  remote_user: epoch
  # Facts are already collected in the previous playbook
  gather_facts: no
  max_fail_percentage: 25
  serial: "25%"

  vars:
    project_root: "{{ ansible_env.HOME }}/node"
    genesis_accounts_path: "{{ project_root }}/data/aecore/.genesis/accounts.json"
    is_remote_package: false
    public_ip: "{{ ansible_ssh_host|default(ansible_host)|default(inventory_hostname) }}"

    # Label used for datadog tagging and ENV file planting
    env: unknown
    # Group of the hosts used to configure node peers
    hosts_group: unknown
    config:
      sync:
        port: 3015
      http:
        external:
          port: 3013
        internal:
          listen_address: "{{ api_internal_listen_address|default('127.0.0.1') }}"
          port: 3113
        debug: "{{ http_debug|default(false) }}"
      websocket:
        internal:
          listen_address: "{{ ws_internal_listen_address|default('127.0.0.1') }}"
          port: 3114
      chain:
        persist: true
        db_path: "./db44"
      keypair:
        dir: "keys"
        password: "{{ vault_keys_password|default('<PASSWORD>') }}"
      logging:
        level: "{{ log_level|default('error') }}"
      mining:
        expected_mine_rate: "{{ expected_mine_rate|default(300000) }}"
        cuckoo:
          miner:
            executable: "{{ miner_executable|default('mean28s-generic') }}"
            extra_args: "{{ miner_extra_args|default('-t 5') }}"
            node_bits: "{{ miner_node_bits|default(28) }}"
    api_base_uri: http://{{ public_ip }}:{{ config.http.external.port }}/v2

  tasks:
    - block:
      - name: Fail on missing package variable
        fail:
          msg: '"package" variable must be defined'
        when: package is not defined
        tags: [package]

      - name: "Make sure {{ project_root }} exists"
        file:
            path: "{{ project_root }}"
            state: directory
            # allow group read for integration purposes  (e.g. logs)
            mode: 0750

      - name: Check if epoch binary exists
        stat:
          path: "{{ project_root }}/bin/epoch"
        register: epoch
        tags: [daemon]

      - name: Ping epoch daemon
        command: "{{ project_root }}/bin/epoch ping"
        failed_when: no
        register: ping
        when: epoch.stat.exists == True
        tags: [daemon]

      - name: Stop epoch daemon
        command: "{{ project_root }}/bin/epoch stop"
        when: epoch.stat.exists == True and ping.stdout == "pong"
        tags: [daemon]

      - name: Register remote package
        set_fact:
          is_remote_package: true
        when: "'http' in package"
        tags: [package]

      - name: Extract epoch package into {{ project_root }}
        unarchive:
          remote_src: "{{ is_remote_package | bool }}"
          keep_newer: true
          src: "{{ package }}"
          dest: "{{ project_root }}"
        when: package is defined
        tags: [package]

      - name: Plant ENV file
        copy:
          content: "{{ env }}\n"
          dest: "{{ project_root }}/ENV"
        tags: [package]

      - name: "Make sure chain path ( {{ config.chain.db_path }} ) exists"
        file:
          path: "{{ project_root }}/{{ config.chain.db_path }}"
          state: directory
        tags: [config]

      - name: "Make sure keys dir ( {{ config.keypair.dir }} ) exists"
        file:
          path: "{{ project_root }}/{{ config.keypair.dir }}"
          state: directory
          mode: 0700
        tags: [config]

      - name: "Copy node keys to {{ project_root }}/{{ config.keypair.dir }}"
        copy:
          src: "{{ item }}"
          dest: "{{ project_root }}/{{ config.keypair.dir }}"
          mode: 0600
        with_items: "{{ keypair }}"
        when: keypair is defined
        tags: [config]

      - name: Update epoch configuration
        template:
          src: templates/epoch.yaml.j2
          dest: "{{ project_root }}/epoch.yaml"
          mode: '0600'
        tags: [config]

      - name: Update accounts configuration
        copy:
          content: "{{ genesis_accounts | to_nice_json }}"
          dest: "{{ genesis_accounts_path }}"
        when: genesis_accounts is defined
        tags: [config]

      - name: "Copy node peer keys to {{ project_root }}/{{ config.keypair.dir }}"
        copy:
          src: "{{ item }}"
          dest: "{{ project_root }}/{{ config.keypair.dir }}"
          mode: 0600
        with_items: "{{ peer_keypairs }}"
        when: peer_keypairs is defined
        tags: [config]

      - name: Start epoch daemon
        command: "{{ project_root }}/bin/epoch start"
        tags: [daemon]

      - name: Wait epoch node API to boot
        wait_for:
          port: "{{ config.http.external.port }}"
          host: "{{ public_ip }}"
          timeout: 300
        connection: local
        tags: [health-check]

      - name: API health check
        uri:
          url: "{{ api_base_uri }}/top"
          timeout: 30
        connection: local
        tags: [health-check]

      - name: Read app version
        command: "cat {{ project_root }}/VERSION"
        register: version_output
        tags: [datadog-event]

      - name: Read app revision
        command: "cat {{ project_root }}/REVISION"
        register: revision_output
        tags: [datadog-event]

      - name: Send Datadog event
        datadog_event:
          host: "{{ inventory_hostname }}"
          alert_type: success
          title: Deploy
          text: |
            %%%
            Revision: [{{ revision_output.stdout }}](https://github.com/aeternity/epoch/commit/{{ revision_output.stdout }})
            Package: {{ package }}
            %%%
          api_key: "{{ vault_datadog_api_key }}"
          app_key: "{{ vault_datadog_app_key }}"
          tags:
            - "env:{{ env }}"
            - "version:{{ version_output.stdout }}"
        connection: local
        tags: [datadog-event]
      rescue:
        - name: Send Datadog event
          datadog_event:
            host: "{{ inventory_hostname }}"
            alert_type: error
            title: Deploy
            text: "Package: {{ package }}"
            api_key: "{{ vault_datadog_api_key }}"
            app_key: "{{ vault_datadog_app_key }}"
            tags:
              - "env:{{ env }}"
          connection: local
          tags: [datadog-event]
        - fail:
            msg: "Failed deploy"
            when: true
<commit_msg>Bump DB version in environments for recent hard fork height change<commit_after>---
# Additional playbook that runs on a group first host only and gather facts from all hosts
# This is required to allow deploying on fraction of group hosts
# For example rolling updates and deploying only to single hosts of a group
#
# For example below command will deploy only to ae-dev2-epoch-n0 host in tag_env_dev2 group
# ansible-playbook --limit="ae-dev2-epoch-n0" --extra-vars "hosts_group=tag_env_dev2" deploy.yml

- name: Facts setup
  hosts: all
  remote_user: epoch
  # Executor facts will be gathered anyway in the task below
  gather_facts: no
  tasks:
    - name: Gather facts from all hosts in {{ hosts_group }} group
      setup:
      run_once: yes
      delegate_to: "{{ item }}"
      delegate_facts: yes
      with_items: "{{ groups[hosts_group] }}"
    - name: Fetch node sync public key
      command: "{{ ansible_env.HOME }}/node/bin/epoch peer_key"
      ignore_errors: yes
      register: key_command
    - name: Register sync public key as fact
      set_fact:
        sync_public_key: "{{ key_command.stdout }}"
      when: key_command.rc == 0

- name: Deploy epoch package
  hosts: all
  remote_user: epoch
  # Facts are already collected in the previous playbook
  gather_facts: no
  max_fail_percentage: 25
  serial: "25%"

  vars:
    project_root: "{{ ansible_env.HOME }}/node"
    genesis_accounts_path: "{{ project_root }}/data/aecore/.genesis/accounts.json"
    is_remote_package: false
    public_ip: "{{ ansible_ssh_host|default(ansible_host)|default(inventory_hostname) }}"

    # Label used for datadog tagging and ENV file planting
    env: unknown
    # Group of the hosts used to configure node peers
    hosts_group: unknown
    config:
      sync:
        port: 3015
      http:
        external:
          port: 3013
        internal:
          listen_address: "{{ api_internal_listen_address|default('127.0.0.1') }}"
          port: 3113
        debug: "{{ http_debug|default(false) }}"
      websocket:
        internal:
          listen_address: "{{ ws_internal_listen_address|default('127.0.0.1') }}"
          port: 3114
      chain:
        persist: true
        db_path: "./db45"
      keypair:
        dir: "keys"
        password: "{{ vault_keys_password|default('secret') }}"
      logging:
        level: "{{ log_level|default('error') }}"
      mining:
        expected_mine_rate: "{{ expected_mine_rate|default(300000) }}"
        cuckoo:
          miner:
            executable: "{{ miner_executable|default('mean28s-generic') }}"
            extra_args: "{{ miner_extra_args|default('-t 5') }}"
            node_bits: "{{ miner_node_bits|default(28) }}"
    api_base_uri: http://{{ public_ip }}:{{ config.http.external.port }}/v2

  tasks:
    - block:
      - name: Fail on missing package variable
        fail:
          msg: '"package" variable must be defined'
        when: package is not defined
        tags: [package]

      - name: "Make sure {{ project_root }} exists"
        file:
            path: "{{ project_root }}"
            state: directory
            # allow group read for integration purposes  (e.g. logs)
            mode: 0750

      - name: Check if epoch binary exists
        stat:
          path: "{{ project_root }}/bin/epoch"
        register: epoch
        tags: [daemon]

      - name: Ping epoch daemon
        command: "{{ project_root }}/bin/epoch ping"
        failed_when: no
        register: ping
        when: epoch.stat.exists == True
        tags: [daemon]

      - name: Stop epoch daemon
        command: "{{ project_root }}/bin/epoch stop"
        when: epoch.stat.exists == True and ping.stdout == "pong"
        tags: [daemon]

      - name: Register remote package
        set_fact:
          is_remote_package: true
        when: "'http' in package"
        tags: [package]

      - name: Extract epoch package into {{ project_root }}
        unarchive:
          remote_src: "{{ is_remote_package | bool }}"
          keep_newer: true
          src: "{{ package }}"
          dest: "{{ project_root }}"
        when: package is defined
        tags: [package]

      - name: Plant ENV file
        copy:
          content: "{{ env }}\n"
          dest: "{{ project_root }}/ENV"
        tags: [package]

      - name: "Make sure chain path ( {{ config.chain.db_path }} ) exists"
        file:
          path: "{{ project_root }}/{{ config.chain.db_path }}"
          state: directory
        tags: [config]

      - name: "Make sure keys dir ( {{ config.keypair.dir }} ) exists"
        file:
          path: "{{ project_root }}/{{ config.keypair.dir }}"
          state: directory
          mode: 0700
        tags: [config]

      - name: "Copy node keys to {{ project_root }}/{{ config.keypair.dir }}"
        copy:
          src: "{{ item }}"
          dest: "{{ project_root }}/{{ config.keypair.dir }}"
          mode: 0600
        with_items: "{{ keypair }}"
        when: keypair is defined
        tags: [config]

      - name: Update epoch configuration
        template:
          src: templates/epoch.yaml.j2
          dest: "{{ project_root }}/epoch.yaml"
          mode: '0600'
        tags: [config]

      - name: Update accounts configuration
        copy:
          content: "{{ genesis_accounts | to_nice_json }}"
          dest: "{{ genesis_accounts_path }}"
        when: genesis_accounts is defined
        tags: [config]

      - name: "Copy node peer keys to {{ project_root }}/{{ config.keypair.dir }}"
        copy:
          src: "{{ item }}"
          dest: "{{ project_root }}/{{ config.keypair.dir }}"
          mode: 0600
        with_items: "{{ peer_keypairs }}"
        when: peer_keypairs is defined
        tags: [config]

      - name: Start epoch daemon
        command: "{{ project_root }}/bin/epoch start"
        tags: [daemon]

      - name: Wait epoch node API to boot
        wait_for:
          port: "{{ config.http.external.port }}"
          host: "{{ public_ip }}"
          timeout: 300
        connection: local
        tags: [health-check]

      - name: API health check
        uri:
          url: "{{ api_base_uri }}/top"
          timeout: 30
        connection: local
        tags: [health-check]

      - name: Read app version
        command: "cat {{ project_root }}/VERSION"
        register: version_output
        tags: [datadog-event]

      - name: Read app revision
        command: "cat {{ project_root }}/REVISION"
        register: revision_output
        tags: [datadog-event]

      - name: Send Datadog event
        datadog_event:
          host: "{{ inventory_hostname }}"
          alert_type: success
          title: Deploy
          text: |
            %%%
            Revision: [{{ revision_output.stdout }}](https://github.com/aeternity/epoch/commit/{{ revision_output.stdout }})
            Package: {{ package }}
            %%%
          api_key: "{{ vault_datadog_api_key }}"
          app_key: "{{ vault_datadog_app_key }}"
          tags:
            - "env:{{ env }}"
            - "version:{{ version_output.stdout }}"
        connection: local
        tags: [datadog-event]
      rescue:
        - name: Send Datadog event
          datadog_event:
            host: "{{ inventory_hostname }}"
            alert_type: error
            title: Deploy
            text: "Package: {{ package }}"
            api_key: "{{ vault_datadog_api_key }}"
            app_key: "{{ vault_datadog_app_key }}"
            tags:
              - "env:{{ env }}"
          connection: local
          tags: [datadog-event]
        - fail:
            msg: "Failed deploy"
            when: true

{'fraction_non_alphanumeric': 0.11759313821776993, 'fraction_numerical': 0.010345053362142342, 'mean_word_length': 1.9710173118070415, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2108440', 'n_tokens_mistral': 4688, 'n_tokens_neox': 4529, 'n_words': 1220}