diff --git a/ansible.py b/ansible.py new file mode 100644 index 0000000..2bbefad --- /dev/null +++ b/ansible.py @@ -0,0 +1,74 @@ +""" +This module abstracts the use of ansible for managing cloud deployments. +""" + +import json +import yaml + +import libroll as lib +from config import Config + + +def generate_inventory(config: Config): + unique_hosts = set( + [ + config.l1_node_remote_ip, + config.l2_engine_remote_ip, + config.l2_sequencer_remote_ip, + config.l2_proposer_remote_ip, + config.l2_batcher_remote_ip, + ] + ) + + inventory = { + "l1": {"hosts": {"l1": {"ansible_host": config.l1_node_remote_ip}}}, + "l2_engine": { + "hosts": {"l2-engine": {"ansible_host": config.l2_engine_remote_ip}} + }, + "l2_sequencer": { + "hosts": {"l2-sequencer": {"ansible_host": config.l2_sequencer_remote_ip}} + }, + "l2_proposer": { + "hosts": {"l2-proposer": {"ansible_host": config.l2_proposer_remote_ip}} + }, + "l2_batcher": { + "hosts": {"l2-batcher": {"ansible_host": config.l2_batcher_remote_ip}} + }, + "l2": { + "hosts": { + "l2-engine": {}, + "l2-sequencer": {}, + "l2-proposer": {}, + "l2-batcher": {}, + } + }, + "unique_hosts": {"hosts": {}}, + } + + for host in unique_hosts: + inventory["unique_hosts"]["hosts"][host] = {"ansible_host": host} + + # Write the inventory dictionary to a YAML file + ansible_dir = config.paths.ansible_dir + with open(f"{ansible_dir}/inventory.yml", "w") as file: + yaml.dump(inventory, file, default_flow_style=False) + + +def run_playbook(config: Config, descr, log_file, playbook, extra_vars=None, tags=None): + ansible_dir = config.paths.ansible_dir + command = f"ansible-playbook -i inventory.yml playbooks/{playbook}" + + if extra_vars is not None: + command = f"{command} --extra-vars='{json.dumps(extra_vars, separators=(',', ':'))}'" + + if config.ansible_ssh_user is not None: + command = f"{command} --user {config.ansible_ssh_user}" + + if config.ansible_ssh_key is not None: + command = f"{command} --key-file {config.ansible_ssh_key}" + + if tags is not None: + command = f"{command} --tags {','.join(tags)}" + + print(f"Running ansible {playbook}. Logging to {log_file}") + lib.run(descr, command, cwd=ansible_dir, forward="fd", stdout=log_file) diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..2a12267 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,17 @@ +[defaults] +fact_caching = ansible.builtin.jsonfile +fact_caching_connection = .facts +cache_timeout = 1 +host_key_checking = False +forks = 50 +callback_enabled = profile_tasks +timeout=20 +stdout_callback = yaml +bin_ansible_callbacks = True + +[ssh_connection] +retries = 3 +pipelining = True +timeout = 5 +ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ServerAliveInterval=30 -o ConnectTimeout=15s +usetty = true diff --git a/ansible/playbooks/roles/rollop/defaults/main.yml b/ansible/playbooks/roles/rollop/defaults/main.yml new file mode 100644 index 0000000..cdfebe0 --- /dev/null +++ b/ansible/playbooks/roles/rollop/defaults/main.yml @@ -0,0 +1,7 @@ +--- +l1_geth_port: 8545 +l2_service_ports: + engine: 9545 + sequencer: 7545 + proposer: 5545 + batcher: 6545 diff --git a/ansible/playbooks/roles/rollop/tasks/l1.yml b/ansible/playbooks/roles/rollop/tasks/l1.yml new file mode 100644 index 0000000..810fb29 --- /dev/null +++ b/ansible/playbooks/roles/rollop/tasks/l1.yml @@ -0,0 +1,16 @@ +--- +- name: write l1 systemd file + ansible.builtin.template: + src: l1.service.j2 + dest: /etc/systemd/system/l1.service + mode: 0644 + tags: + - l1 + +- name: enable l1 service + ansible.builtin.systemd: + name: l1 + daemon-reload: true + enabled: true + tags: + - l1 diff --git a/ansible/playbooks/roles/rollop/tasks/l2.yml b/ansible/playbooks/roles/rollop/tasks/l2.yml new file mode 100644 index 0000000..9b48856 --- /dev/null +++ b/ansible/playbooks/roles/rollop/tasks/l2.yml @@ -0,0 +1,28 @@ +--- +- name: Set l2_service fact + ansible.builtin.set_fact: + l2_service: "{{ item }}" + loop: + - engine + - sequencer + - proposer + - batcher + when: "'l2_' + item in group_names" + tags: + - l2 + +- name: Write systemd file for l2 service + ansible.builtin.template: + src: l2.service.j2 + dest: "/etc/systemd/system/l2-{{ l2_service }}.service" + mode: 0644 + tags: + - l2 + +- name: Enable l2 service + ansible.builtin.systemd: + name: "l2-{{ l2_service }}" + daemon-reload: true + enabled: true + tags: + - l2 diff --git a/ansible/playbooks/roles/rollop/tasks/main.yml b/ansible/playbooks/roles/rollop/tasks/main.yml new file mode 100644 index 0000000..5bd8df9 --- /dev/null +++ b/ansible/playbooks/roles/rollop/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- name: setup roll-op + include_tasks: setup.yml + when: "'unique_hosts' in group_names" + tags: + - setup + +- name: configure l1 + include_tasks: l1.yml + when: "'l1' in group_names" + tags: + - l1 + +- name: configure l2 + include_tasks: l2.yml + when: "'l2' in group_names" + tags: + - l2 + +- name: (re)start l1 and l2 + include_tasks: restart.yml + tags: + - restart diff --git a/ansible/playbooks/roles/rollop/tasks/restart.yml b/ansible/playbooks/roles/rollop/tasks/restart.yml new file mode 100644 index 0000000..bf3fca9 --- /dev/null +++ b/ansible/playbooks/roles/rollop/tasks/restart.yml @@ -0,0 +1,55 @@ +--- +- name: restart l1 service + ansible.builtin.systemd: + name: l1 + state: restarted + when: "'l1' in group_names" + tags: + - l1 + - restart + +- name: Wait for geth port + ansible.builtin.wait_for: + port: "{{ l1_geth_port }}" + delay: 10 + when: "'l1' in group_names" + tags: + - l1 + - restart + +- name: Deploy l2 contracts + create genesis + ansible.builtin.shell: + chdir: /roll-op + cmd: ./rollop --no-ansi-esc --config /roll-op/config.toml deploy-l2 + when: "'l2_engine' in group_names" + tags: + - l2 + - restart + +- name: Restart l2 service + ansible.builtin.systemd: + name: "l2-{{ item }}" + state: restarted + loop: + - engine + - sequencer + - proposer + - batcher + when: "'l2_' + item in group_names" + tags: + - l2 + - restart + +- name: Wait for l2 service port + ansible.builtin.wait_for: + port: "{{ l2_service_ports[item] }}" + delay: 10 + loop: + - engine + - sequencer + - proposer + - batcher + when: "'l2_' + item in group_names" + tags: + - l2 + - restart diff --git a/ansible/playbooks/roles/rollop/tasks/setup.yml b/ansible/playbooks/roles/rollop/tasks/setup.yml new file mode 100644 index 0000000..17ddae2 --- /dev/null +++ b/ansible/playbooks/roles/rollop/tasks/setup.yml @@ -0,0 +1,49 @@ +--- +- name: update apt cache + ansible.builtin.apt: + update_cache: true + when: ansible_facts['distribution'] in ['Debian', 'Ubuntu'] + tags: + - setup + +- name: install system dependencies + ansible.builtin.apt: + pkg: + - acl + - apt-transport-https + - build-essential + - ca-certificates + - curl + - git + - jq + - python3-pip + - python3-setuptools + - software-properties-common + when: ansible_facts['distribution'] in ['Debian', 'Ubuntu'] + tags: + - setup + +- name: clone roll-op + ansible.builtin.git: + force: true + repo: https://github.com/0xFableOrg/roll-op.git + dest: /roll-op + version: feature/ansible + tags: + - setup + +- name: run setup + ansible.builtin.shell: + chdir: /roll-op + cmd: ./rollop --no-ansi-esc setup --yes + creates: /roll-op/optimism + tags: + - setup + +- name: copy config + ansible.builtin.copy: + src: "{{ playbook_dir }}/../../config.toml" + dest: /roll-op/config.toml + mode: 0644 + tags: + - setup diff --git a/ansible/playbooks/roles/rollop/templates/l1.service.j2 b/ansible/playbooks/roles/rollop/templates/l1.service.j2 new file mode 100644 index 0000000..31d03e9 --- /dev/null +++ b/ansible/playbooks/roles/rollop/templates/l1.service.j2 @@ -0,0 +1,13 @@ +[Unit] +Description=Roll-OP Layer 1 + +[Service] +Type=simple +Restart=always +WorkingDirectory=/roll-op +Nice=-20 +ExecStart=/roll-op/rollop --no-ansi-esc --config /roll-op/config.toml l1 +TimeoutSec=900 + +[Install] +WantedBy=default.target diff --git a/ansible/playbooks/roles/rollop/templates/l2.service.j2 b/ansible/playbooks/roles/rollop/templates/l2.service.j2 new file mode 100644 index 0000000..6e02dc5 --- /dev/null +++ b/ansible/playbooks/roles/rollop/templates/l2.service.j2 @@ -0,0 +1,13 @@ +[Unit] +Description=Roll-OP Layer 2 {{ l2_service }} + +[Service] +Type=simple +Restart=always +WorkingDirectory=/roll-op +Nice=-20 +ExecStart=/roll-op/rollop --no-ansi-esc --config /roll-op/config.toml l2-{{ l2_service }} +TimeoutSec=900 + +[Install] +WantedBy=default.target diff --git a/ansible/playbooks/rollop.yml b/ansible/playbooks/rollop.yml new file mode 100644 index 0000000..3bd1436 --- /dev/null +++ b/ansible/playbooks/rollop.yml @@ -0,0 +1,42 @@ +--- +- name: Setup rollop + hosts: unique_hosts + become: true + roles: + - role: rollop + become: true + +- name: Deploy l1 + hosts: l1 + become: true + roles: + - role: rollop + become: true + +- name: Deploy l2-engine + hosts: l2-engine + become: true + roles: + - role: rollop + become: true + +- name: Deploy l2-sequencer + hosts: l2-sequencer + become: true + roles: + - role: rollop + become: true + +- name: Deploy l2-proposer + hosts: l2-proposer + become: true + roles: + - role: rollop + become: true + +- name: Deploy l2-batcher + hosts: l2-batcher + become: true + roles: + - role: rollop + become: true