Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
January 24, 2022 09:13 pm GMT

Install Erlang, Elixir, Phoenix, and Nerves automatically to machines on macOS and Ubuntu by Ansible and Asdf

Suppose you install Erlang, Elixir, Phoenix and Nerves to a machine on macOS or Ubuntu by Asdf. In that case, you may do it by your hand, following such articles like "Perfect Steps of Installing Erlang and Elixir to Apple Silicon Mac." But if you do it to two or more machines? You may want to make such jobs automated. Ansible is such an approach.

This article will explain how we automatically install Erlang, Elixir, Phoenix, and Nerves to machines on macOS and Ubuntu by Ansible and Asdf.

Japanese edition is here: https://qiita.com/zacky1972/items/38a9ebb53bbc406fabb7

Prerequisite

Suppose you have a host machine and one or more target machines. You should install Ansible on the host. Suppose the targets run on macOS or Ubuntu. And you should install Homebrew on them on macOS. Moreover, suppose you can log in to all targets by ssh with your public key and become an administrator with the same sudo password. Finally, suppose the hostnames of the targets are target1, target2, ..., target9.

inventory.yml

You should write the information of the targets and common variables to inventory/inventory.yml:

all:  hosts:    target[1:9]:  vars:    asdf: v0.8.1    erlang: latest    elixir: latest    phoenix: latest    nerves: latest

target[1:9] means target1, target2, ..., target9. You can rename it as you need. You can also specify each version for Asdf, Erlang, Elixir, Phoenix, and Nerves. In this case, the version of Asdf you will install is v0.8.1, and the versions of the others are the latest. You may specify older Erlang, Elixir, Phoenix, and Nerves versions.

Especially, you may install them to localhost as follows:

all:  hosts:    localhost:      ansible_host: "127.0.0.1"  vars:    asdf: v0.8.1    erlang: latest    elixir: latest    phoenix: latest    nerves: latest

If so, of course, you should enable to log in by ssh to localhost.

ansible.cfg

To suppress warnings, you may write ansible.cfg as follows:

[defaults]interpreter_python=/usr/bin/python3

Tasks

For reusability, you can write Ansible tasks as components.

Install Asdf for Ubuntu

tasks/0010_install_asdf_linux.yml:

---- block:  - name: Install dependencies of asdf    become: true    apt:      update_cache: yes      cache_valid_time: 86400 # 1day      name:        - curl        - git      state: latest  - name: Install asdf    git:      repo: https://github.com/asdf-vm/asdf.git      dest: "{{ ansible_user_dir }}/.asdf"      depth: 1      version: "{{ asdf | quote }}"    register: result  - name: asdf update    shell: "bash -lc 'cd {{ ansible_user_dir }}/.asdf && git pull'"    ignore_errors: yes    when: result is failed  - name: set env vars    lineinfile:      dest: "{{ shrc }}"      state: present      line: "{{ item.line }}"    with_items:    - line: ". $HOME/.asdf/completions/asdf.{{ sh }}"      regexp: '^ \. \$HOME/\.asdf/completions/asdf\.{{ sh }}'    - line: '. $HOME/.asdf/asdf.sh'      regexp: '^ \. \$HOME/\.asdf/asdf\.sh'  when: ansible_system == 'Linux' and (ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian')  vars:    - shrc: "{{ ansible_user_dir | quote }}/.{{ ansible_user_shell | basename | quote }}rc"    - sh: "{{ ansible_user_shell | basename | quote }}"

Install Asdf for macOS

tasks/0010_install_asdf_macos.yml:

---- block:  - name: install asdf by Homebrew    community.general.homebrew:      update_homebrew: true      name:        - asdf  - name: set env vars (bash)    lineinfile:      dest: "{{ shprofile }}"      state: present      line: "{{ item.line }}"    with_items:    - line: ".  $(brew --prefix asdf)/etc/bash_completion.d/asdf.bash"      regexp: '^ \. \$(brew --prefix asdf)/etc/bash_completion\.d/asdf\.bash'    - line: '. $(brew --prefix asdf)/libexec/asdf.sh'      regexp: '^ \. \$(brew --prefix asdf)/libexec/asdf\.sh'    when: sh == 'bash'  - name: set env vars (zsh)    lineinfile:      dest: "{{ shrc }}"      state: present      line: "{{ item.line }}"    with_items:    - line: ". $(brew --prefix)/share/zsh/site-functions"      regexp: '^ \. \$(brew --prefix)/share/zsh/site-functions'    - line: '. $(brew --prefix asdf)/libexec/asdf.sh'      regexp: '^ \. \$(brew --prefix asdf)/libexec/asdf\.sh'    when: sh == 'zsh'  when: ansible_system == 'Darwin'  vars:    - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile"    - shrc: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename }}rc"    - sh: "{{ ansible_user_shell | basename | quote }}"

Install prerequisite libraries for Erlang on Ubuntu

tasks/0011_install_erlang_prerequisite_linux.yml:

---- block:  - name: install prerequisite libraries for erlang     become: true    apt:      update_cache: yes      cache_valid_time: 86400 # 1day      state: latest      name:      - build-essential      - autoconf      - m4      - libncurses5-dev      - libwxgtk3.0-gtk3-dev      - libgl1-mesa-dev      - libglu1-mesa-dev      - libpng-dev      - libssh-dev      - unixodbc-dev      - xsltproc      - fop      - libxml2-utils      - libncurses-dev      - openjdk-11-jdk  when: ansible_system == 'Linux' and (ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian')

Install prerequisite libraries for Erlang on macOS

tasks/0011_install_erlang_prerequisite_macos.yml:

---- block:  - name: install prerequisite libraries for erlang     community.general.homebrew:      update_homebrew: true      name:        - autoconf        - [email protected]        - openssl@3        - wxwidgets        - libxslt        - fop        - openjdk  when: ansible_system == 'Darwin'

Install prerequisite libraries for Nerves on Ubuntu

tasks/0013_install_nerves_prerequisite_linux.yml:

---- block:  - name: install prerequisite libraries for nerves    become: true    apt:      update_cache: yes      cache_valid_time: 86400 # 1day      state: latest      name:      - automake      - autoconf      - git      - squashfs-tools      - ssh-askpass      - pkg-config      - curl      - libssl-dev      - libncurses5-dev      - bc      - m4      - unzip      - cmake      - python  when: ansible_system == 'Linux' and (ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian')

Install prerequisite libraries for Nerves on macOS

tasks/0013_install_nerves_prerequisite_macos.yml:

---- block:  - name: install prerequisite libraries for nerves     community.general.homebrew:      update_homebrew: true      name:        - fwup         - squashfs        - coreutils        - xz        - pkg-config  when: ansible_system == 'Darwin'

Install Erlang plugin

tasks/0021_install_erlang_plugin.yml:

---- block:  - name: sh env    ansible.builtin.shell:    args:      cmd: "{{ shenv_cmd }}"      chdir: '{{ ansible_user_dir }}/'    register: shenv  - name: asdf plugin add erlang    ansible.builtin.shell: |      {{ source }}       asdf plugin add erlang    args:      executable: '{{ ansible_user_shell }}'    register: result    failed_when: result.rc != 0 and result.stderr | regex_search('(Plugin named .* already added)') == ''     vars:       source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" vars: - asdfsh: "{{ ansible_user_dir | quote }}/.asdf/asdf.sh" - profile: "{{ ansible_user_dir | quote }}/.profile" - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" - shrc: "{{ ansible_user_dir | quote }}/.{{ ansible_user_shell | basename | quote }}rc" - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi"

Install Elixir plugin

tasks/0022_install_elixir_plugin.yml:

---- block:  - name: sh env    ansible.builtin.shell:    args:      cmd: "{{ shenv_cmd }}"      chdir: '{{ ansible_user_dir }}/'    register: shenv  - name: asdf plugin add elixir    ansible.builtin.shell: |      {{ source }}       asdf plugin add elixir    args:      executable: '{{ ansible_user_shell }}'    register: result    failed_when: result.rc != 0 and result.stderr | regex_search('(Plugin named .* already added)') == ''     vars:       source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" vars: - asdfsh: "{{ ansible_user_dir | quote }}/.asdf/asdf.sh" - profile: "{{ ansible_user_dir }}/.profile" - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" - shrc: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename }}rc" - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi"

Install Erlang

tasks/0101_install_erlang.yml:

---- block:  - name: sh env    ansible.builtin.shell:    args:      cmd: "{{ shenv_cmd }}"      chdir: '{{ ansible_user_dir }}/'    register: shenv  - name: asdf install erlang (for Linux)    ansible.builtin.shell: |      {{ source }}       asdf install erlang {{ erlang | quote }}    args:      executable: '{{ ansible_user_shell }}'    register: result    when: ansible_system == 'Linux'    vars:       source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: show result debug: var: result - name: asdf install erlang (macOS OTP version 24.1.x or earlier) ansible.builtin.shell: | {{ source }} {{ install_erlang_ssl_1_1 }} args: executable: '{{ ansible_user_shell }}' register: result when: (erlang != 'latest' and erlang is version_compare('24.2', '<')) and ansible_system == 'Darwin' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: show result debug: var: result when: (erlang != 'latest' and erlang is version_compare('24.2', '<')) and ansible_system == 'Darwin' - name: asdf install erlang (macOS OTP 24.2 or later) ansible.builtin.shell: | {{ source }} {{ install_erlang_ssl_3 }} args: executable: '{{ ansible_user_shell }}' register: result when: (erlang == 'latest' or (erlang is version_compare('24.2', '>='))) and ansible_system == 'Darwin' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: show result debug: var: result when: (erlang == 'latest' or (erlang is version_compare('24.2', '>='))) and ansible_system == 'Darwin' - name: asdf global erlang ansible.builtin.shell: | {{ source }} asdf global erlang {{ erlang | quote }} args: executable: '{{ ansible_user_shell }}' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" vars: - asdfsh: "{{ ansible_user_dir | quote }}/.asdf/asdf.sh" - profile: "{{ ansible_user_dir }}/.profile" - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" - shrc: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename }}rc" - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi" - install_erlang_ssl_1_1: "KERL_CONFIGURE_OPTIONS=\"--with-ssl=$(brew --prefix [email protected]) --with-odbc=$(brew --prefix unixodbc)\" CC=\"/usr/bin/gcc -I$(brew --prefix unixodbc)/include\" LDFLAGS=-L$(brew --prefix unixodbc)/lib asdf install erlang {{ erlang | quote }}" - install_erlang_ssl_3: "KERL_CONFIGURE_OPTIONS=\"--with-ssl=$(brew --prefix openssl@3) --with-odbc=$(brew --prefix unixodbc)\" CC=\"/usr/bin/gcc -I$(brew --prefix unixodbc)/include\" LDFLAGS=-L$(brew --prefix unixodbc)/lib asdf install erlang {{ erlang | quote }}"

Install Elixir

tasks/0102_install_elixir.yml:

---- block:  - name: sh env    ansible.builtin.shell:    args:      cmd: "{{ shenv_cmd }}"      chdir: '{{ ansible_user_dir }}/'    register: shenv  - name: asdf install elixir    ansible.builtin.shell: |      {{ source }}      asdf install elixir {{ elixir | quote }}    args:      executable: '{{ ansible_user_shell }}'    register: result    vars:       source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: show result debug: var: result - name: asdf install elixir ansible.builtin.shell: | {{ source }} asdf global elixir {{ elixir | quote }} args: executable: '{{ ansible_user_shell }}' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" vars: - asdfsh: "{{ ansible_user_dir | quote }}/.asdf/asdf.sh" - profile: "{{ ansible_user_dir }}/.profile" - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" - shrc: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename }}rc" - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi"

Install Phoenix

tasks/0201_install_phoenix.yml:

---- block:  - name: sh env    ansible.builtin.shell:    args:      cmd: "{{ shenv_cmd }}"      chdir: '{{ ansible_user_dir }}/'    register: shenv  - name: install prerequisite    ansible.builtin.shell: |      {{ source }}      mix local.rebar --force      mix local.hex --force    args:      executable: '{{ ansible_user_shell }}'    register: result    vars:       source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: install Phoenix (latest) ansible.builtin.shell: | {{ source }} mix archive.install hex phx_new --force args: executable: '{{ ansible_user_shell }}' register: result when: phoenix == 'latest' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: install Phoenix (not latest) ansible.builtin.shell: | {{ source }} mix archive.install hex phx_new {{ phoenix }} --force args: executable: '{{ ansible_user_shell }}' register: result when: phoenix != 'latest' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" vars: - asdfsh: "{{ ansible_user_dir | quote }}/.asdf/asdf.sh" - profile: "{{ ansible_user_dir }}/.profile" - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" - shrc: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename }}rc" - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi"

Install Nerves

tasks/0301_install_nerves.yml:

---- block:  - name: sh env    ansible.builtin.shell:    args:      cmd: "{{ shenv_cmd }}"      chdir: '{{ ansible_user_dir }}/'    register: shenv  - name: install Nerves (latest)    ansible.builtin.shell: |      {{ source }}      mix local.rebar --force      mix local.hex --force      mix archive.install hex nerves_bootstrap --force    args:      executable: '{{ ansible_user_shell }}'    register: result    when: nerves == 'latest'    vars:       source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" - name: install Nerves (not latest) ansible.builtin.shell: | {{ source }} mix local.rebar --force mix local.hex --force mix archive.install hex nerves_bootstrap {{ nerves }} --force args: executable: '{{ ansible_user_shell }}' register: result when: nerves != 'latest' vars: source: "{{ shenv.stdout_lines | map('regex_replace', '(^)', '. ') | join('
') }}" vars: - asdfsh: "{{ ansible_user_dir | quote }}/.asdf/asdf.sh" - profile: "{{ ansible_user_dir }}/.profile" - shprofile: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename | regex_replace('$', '_') | regex_replace('zsh_', 'z') }}profile" - shrc: "{{ ansible_user_dir }}/.{{ ansible_user_shell | basename }}rc" - shenv_cmd: "if [ -e {{ asdfsh }} ]; then echo '{{ asdfsh }}'; fi; if [ -e {{ shprofile }} ]; then echo '{{ shprofile }}'; fi; if [ -e {{ profile }} ]; then echo '{{ profile }}'; fi; if [ -e {{ shrc }} ]; then echo '{{ shrc }}'; fi"

Playbooks

Then, you can assemble a playbook from the tasks. This section shows some samples.

Install Asdf

playbook/0010_install_asdf.yml:

- name: install asdf  hosts: all  tasks:    - include_tasks: ../tasks/0010_install_asdf_linux.yml      when: ansible_system == 'Linux' and (ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian')    - include_tasks: ../tasks/0010_install_asdf_macos.yml      when: ansible_system == 'Darwin'

Install prerequisites of Erlang

playbook/0011_install_erlang_prerequisite.yml:

- name: install prerequisites of erlang  hosts: all  tasks:    - include_tasks: ../tasks/0011_install_erlang_prerequisite_linux.yml      when: ansible_system == 'Linux' and (ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian')    - include_tasks: ../tasks/0011_install_erlang_prerequisite_macos.yml      when: ansible_system == 'Darwin'

Install prerequisites of Nerves

playbook/0013_install_nerves_prerequisite.yml:

- name: install prerequisites of nerves  hosts: all  tasks:    - include_tasks: ../tasks/0013_install_nerves_prerequisite_linux.yml      when: ansible_system == 'Linux' and (ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian')    - include_tasks: ../tasks/0013_install_nerves_prerequisite_macos.yml      when: ansible_system == 'Darwin'

Install plugins

playbook/0020_install_plugins.yml:

- name: install erlang/elixir plugins for asdf  hosts: all  tasks:    - include_tasks: ../tasks/0021_install_erlang_plugin.yml    - include_tasks: ../tasks/0022_install_elixir_plugin.yml

Install Erlang and Elixir

playbook/0100_install_erlang_elixir.yml:

- name: install erlang/elixir with asdf  hosts: all  tasks:    - include_tasks: ../tasks/0101_install_erlang.yml    - include_tasks: ../tasks/0102_install_elixir.yml

Install Phoenix

playbook/0200_install_phoenix.yml:

- name: install phoenix with asdf  hosts: all  tasks:    - include_tasks: ../tasks/0201_install_phoenix.yml

Install Nerves

playbook/0300_install_nerves.yml

- name: install nerves with asdf  hosts: all  tasks:    - include_tasks: ../tasks/0301_install_nerves.yml

Usage

You can run the playbook as follows:

ansible-playbook -f (number of targets) -i (inventory file) (playbook file)

For example, you can install Erlang and Elixir to target1, target2, ..., target9 as follows:

ansible-playbook -f 9 -i inventory/inventory.yml playbook/0100_install_erlang_elixir.yml

If you need to become the administrator when running the playbook, you should run it as follows:

ansible-playbook -f (number of targets) -i (inventory file) (playbook file) --ask-become-pass

For example, you can install Asdf to target1, target2, ..., target9 when the targets include one or more Ubuntu machines as follows:

ansible-playbook -f 9 -i inventory/inventory.yml playbook/0010_install_asdf.yml --ask-become-pass

Original Link: https://dev.to/zacky1972/install-erlang-elixir-phoenix-and-nerves-automatically-to-machines-on-macos-and-ubuntu-by-ansible-and-asdf-2olc

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To