diff --git a/README.md b/README.md index c4bf040..adb21f6 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ For most users, a small Ubuntu VM inside OpenStack is the simplest and most repr Recommended head VM characteristics: ``` -Operating System: Ubuntu LTS (20.04 or newer) +Operating System: Ubuntu LTS (24.04 or newer) CPU/RAM: minimal (e.g. 1–2 vCPUs, 2–4 GB RAM) Access: SSH enabled via key pair ``` @@ -55,7 +55,7 @@ The following steps describe how to create a head VM using the generic OpenStack ### Select the Source Image (Operating System) 1. In the source tab, Select Boot Source: Image -2. Choose a supported Ubuntu image (eg. Ubuntu 22.04) +2. Choose a supported Ubuntu image (eg. Ubuntu 24.04) 3. If the BioShell image has been previously built you should be able to select BioShell at this step. ### Choose an Instance Flavor @@ -199,9 +199,9 @@ packer init . ### Step 2: Prepare Packer build configuration -Before running the build, review and update `openstack-bioshell.pkr.hcl` to ensure the values match your OpenStack environment. If using a prepared config skip to step 3. +Before running the build, review and update `[platform_name].pkrvars.hcl` to ensure the values match your OpenStack environment. If using a prepared config skip to step 3. -**Note: Example working configurations for [Nectar](build/examples/openstack-bioshell-nectar.pkr.hcl) and [Nirin](build/examples/openstack-bioshell-nirin.pkr.hcl) are included and were last successfully tested on 2 February 2026. The Nirin configuration requires you to add your project [network](#network-cloud-dependant).** +**Note: Example working configurations for [Nectar](build/packer-vars/nectar.pkrvars.hcl) and [Nirin](build/packer-vars/nirin.pkrvars.hcl) are included and were last successfully tested on 2 February 2026. The Nirin configuration requires you to add your project [network](#network-cloud-dependant).** At a minimum, check the following fields in the `source "openstack"` block: #### Source Image (Base OS) @@ -214,7 +214,7 @@ Example output: +--------------------------------------+-------------------------------+--------+ | ID | Name | Status | +--------------------------------------+-------------------------------+--------+ -| | Ubuntu 20.04 | active | +| | Ubuntu 24.04 | active | +--------------------------------------+-------------------------------+--------+ ``` Copy the ID of the image you want to use and set it as: @@ -284,29 +284,26 @@ If your cloud has a default network, this field may be omitted. #### CVMFS Configuration -The [`build-bioshell.yml`](build/build-bioshell.yml) playbook configures CVMFS for the image. +The [`ansible cvmfs role`](build/ansible/roles/cvmfs/tasks/main.yml) configures CVMFS for the image. - By default, the CVMFS HTTP proxy is set to **DIRECT** to make the build more portable across environments. -- If a infrastructure specific proxy is available (eg. `http://cvmfs-proxy-1.nci.org.au:3128;http://cvmfs-proxy-2.nci.org.au:3128` on Nirin), update the `CVMFS_HTTP_PROXY` line in the playbook. +- If a infrastructure specific proxy is available (eg. `http://cvmfs-proxy-1.nci.org.au:3128;http://cvmfs-proxy-2.nci.org.au:3128` on Nirin), add new file `[platform_name].yml` to [`ansible vars`](build/ansible/vars/) with `cvmfs_proxy: [proxy]`. -The relevant task in the playbook: - -```yaml -- name: Write default.local - copy: - dest: /etc/cvmfs/default.local - content: | - CVMFS_REPOSITORIES=data.biocommons.aarnet.edu.au,data.galaxyproject.org,singularity.galaxyproject.org - CVMFS_HTTP_PROXY='DIRECT' - CVMFS_QUOTA_LIMIT=4096 - CVMFS_USE_GEOAPI=yes -``` ### Step 3: Build BioShell Once the configuration has been updated, run the build: +For Nirin and Nectar users: +``` +./scripts/nirin.sh // nirin users +./scripts/nectar.sh. // nectar users ``` -packer build openstack-bioshell.pkr.hcl +For other platform users: ``` +packer build \ + -var-file="./packer-vars/[platform_name].pkrvars.hcl" \ + ./openstack-bioshell.pkr.hcl +``` + ### Step 4: Verify Image After the build process is complete, verify the newly created image by running: ``` @@ -364,7 +361,6 @@ This image uses CernVM-FS (CVMFS) to provide access to shared bioinformatics sof Access CVMFS repositories: ``` -ls /cvmfs/data.biocommons.aarnet.edu.au ls /cvmfs/data.galaxyproject.org ls /cvmfs/singularity.galaxyproject.org diff --git a/build/ansible/build-bioshell.yml b/build/ansible/build-bioshell.yml new file mode 100644 index 0000000..ce7561d --- /dev/null +++ b/build/ansible/build-bioshell.yml @@ -0,0 +1,16 @@ +--- +- name: Build BioShell base image + hosts: all + become: true + + vars_files: + - "vars/tool-versions.yml" + - "vars/{{ platform }}.yml" + + roles: + - common + - singularity + - nextflow + - rstudio + - cvmfs + - shelley-bio \ No newline at end of file diff --git a/build/ansible/roles/common/tasks/main.yml b/build/ansible/roles/common/tasks/main.yml new file mode 100644 index 0000000..f435581 --- /dev/null +++ b/build/ansible/roles/common/tasks/main.yml @@ -0,0 +1,201 @@ +--- +- name: Wait for apt lock + shell: | + while fuser /var/lib/apt/lists/lock >/dev/null 2>&1 || \ + fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || \ + fuser /var/lib/dpkg/lock >/dev/null 2>&1; do + sleep 5 + done + changed_when: false + +- name: Update apt cache + apt: + update_cache: yes + register: apt_update + retries: 3 + delay: 10 + until: apt_update is succeeded + +- name: Install base packages + apt: + name: + - lmod + - build-essential + - libssl-dev + - uuid-dev + - libgpgme11-dev + - squashfs-tools + - git + - wget + - autoconf + - automake + - cryptsetup + - fuse2fs + - fuse + - libfuse-dev + - libglib2.0-dev + - libtool + - pkg-config + - runc + - squashfs-tools-ng + - uidmap + - zlib1g-dev + - libseccomp-dev + - nano + - jupyter + - snakemake + - r-base + - python3 + - python3-pip + - python3-venv + - ansible + - tree + state: present + +- name: Install R build dependencies + apt: + name: + - build-essential + - cmake + - gdal-bin + - libcurl4-openssl-dev + - libxml2-dev + - libfontconfig1-dev + - libfreetype6-dev + - libharfbuzz-dev + - libfribidi-dev + - libudunits2-dev + - libglpk-dev + - libblas-dev + - liblapack-dev + - libopenblas-dev + - libtiff5-dev + - libjpeg-dev + - libpng-dev + - libcairo2-dev + +- name: Install Spack + block: + - name: Clone Spack repository + shell: | + git clone -c feature.manyFiles=true --depth=2 https://github.com/spack/spack.git /usr/local/spack + +- name: Ensure module directories exist + file: + path: "{{ item }}" + state: directory + loop: + - "{{ module_base_opt }}" + - "{{ module_base_apps }}" + +- name: Create /apps symlinks and paths + shell: | + mkdir -p /apps/R/{{ r_version }}/bin /apps/Modules/modulefiles/R + ln -sf /usr/bin/R /apps/R/{{ r_version }}/bin/R + + mkdir -p /apps/jupyter/{{ jupyter_version }}/bin /apps/Modules/modulefiles/jupyter + ln -sf /usr/bin/jupyter /apps/jupyter/{{ jupyter_version }}/bin/jupyter + + mkdir -p /apps/snakemake/{{ snakemake_version }}/bin /apps/Modules/modulefiles/snakemake + ln -sf /usr/bin/snakemake /apps/snakemake/{{ snakemake_version }}/bin/snakemake + + mkdir -p /apps/ansible/{{ ansible_version.string }}/bin /apps/Modules/modulefiles/ansible + ln -sf /usr/bin/ansible /apps/ansible/{{ ansible_version.string }}/bin/ansible + + args: + executable: /bin/bash + +- name: Update PATH in /etc/environment + lineinfile: + path: /etc/environment + regexp: '^PATH=' + line: 'PATH="{{ updated_path }}"' + state: present + vars: + current_path: "{{ ansible_env.PATH }}" + updated_path: "{{ current_path | replace('/usr/local/games', '') | trim | replace('::', ':') | regex_replace('^:|:$', '') }}:/usr/local/spack/bin" + +- name: Comment out existing module paths + lineinfile: + path: /etc/lmod/modulespath + regexp: '^(.*(/etc/lmod/modules|/usr/share/lmod/lmod/modulefiles).*)' + line: '# \1' + backrefs: yes + state: present + +- name: Add new module paths + lineinfile: + path: /etc/lmod/modulespath + line: "{{ item }}" + state: present + loop: + - "{{ module_base_apps }}" + - "{{ module_base_opt }}" + +- name: Create jupyter modulefile + copy: + dest: "/apps/Modules/modulefiles/jupyter/{{ jupyter_version }}" + content: | + #%Module1.0 + + prepend-path PATH "/apps/jupyter/{{ jupyter_version }}/bin" + +- name: Create snakemake modulefile + copy: + dest: "/apps/Modules/modulefiles/snakemake/{{ snakemake_version }}" + content: | + #%Module1.0 + + prepend-path PATH "/apps/snakemake/{{ snakemake_version }}/bin" + +- name: Create R modulefile + copy: + dest: "/apps/Modules/modulefiles/R/{{ r_version }}" + content: | + #%Module1.0 + + prepend-path PATH "/apps/R/{{ r_version }}/bin" + +- name: Create ansible modulefile + copy: + dest: "/apps/Modules/modulefiles/ansible/{{ ansible_version.string }}" + content: | + #%Module1.0 + + prepend-path PATH "/apps/ansible/{{ ansible_version.string }}/bin" + +- name: Ensure motd.d directory exists + file: + path: /etc/motd.d + state: directory + mode: '0755' + +- name: Add BioShell welcome message with turtle + copy: + dest: /etc/motd.d/bioshell + owner: root + group: root + mode: '0644' + content: | + ################################################################## + # # + # Welcome to BioShell! # + # # + # A range of commonly used bioinformatics software is available # + # via CVMFS. # + # # + # To make the software folders visible, run: # + # cvmfs_config probe # + # # + # If you need help finding and installing software, # + # ask Shelley-Bio # + # _ .----. # + # (_ \/ \_, # + # `uu----uu' # + # Basic commands: # + # shelley-bio find # + # shelley-bio search "" # + # shelley-bio versions # + # shelley-bio build # + # shelley-bio interactive # + ################################################################## diff --git a/build/ansible/roles/cvmfs/tasks/main.yml b/build/ansible/roles/cvmfs/tasks/main.yml new file mode 100644 index 0000000..693d1b3 --- /dev/null +++ b/build/ansible/roles/cvmfs/tasks/main.yml @@ -0,0 +1,94 @@ +--- +- name: Download CVMFS release package + get_url: + url: https://ecsft.cern.ch/dist/cvmfs/cvmfs-release/cvmfs-release-latest_all.deb + dest: /tmp/cvmfs-release-latest_all.deb + +- name: Install CVMFS release package + apt: + deb: /tmp/cvmfs-release-latest_all.deb + +- name: Remove CVMFS release package + file: + path: /tmp/cvmfs-release-latest_all.deb + state: absent + +- name: Update apt cache + apt: + update_cache: yes + +- name: Install CVMFS + apt: + name: cvmfs + state: present + +- name: Disable unwanted CVMFS default config files + command: "mv {{ item }} {{ item }}-DISABLED" + args: + removes: "{{ item }}" + loop: + - /etc/cvmfs/config.d/cvmfs-config.cern.ch.conf + - /etc/cvmfs/default.d/50-cern-debian.conf + - /etc/cvmfs/domain.d/cern.ch.conf + - /etc/cvmfs/domain.d/egi.eu.conf + - /etc/cvmfs/domain.d/opensciencegrid.org.conf + +- name: Write default.local + copy: + dest: /etc/cvmfs/default.local + content: | + CVMFS_REPOSITORIES={{ cvmfs_repositories }} + CVMFS_HTTP_PROXY='{{ cvmfs_proxy }}' + CVMFS_QUOTA_LIMIT={{ cvmfs_quota_limit }} + CVMFS_USE_GEOAPI=yes + +- name: set up cvmfs and set autofs + shell: | + cvmfs_config setup + sed -i 's%#+dir:/etc/auto.master.d%+dir:/etc/auto.master.d%' /etc/auto.master + systemctl restart autofs + +- name: Write galaxyproject.org.conf + copy: + dest: /etc/cvmfs/domain.d/galaxyproject.org.conf + content: | + CVMFS_SERVER_URL="http://cvmfs1-tacc0.galaxyproject.org/cvmfs/@fqrn@;http://cvmfs1-iu0.galaxyproject.org/cvmfs/@fqrn@;http://cvmfs1-psu0.galaxyproject.org/cvmfs/@fqrn@;http://galaxy.jrc.ec.europa.eu:8008/cvmfs/@fqrn@;http://cvmfs1-mel0.gvl.org.au/cvmfs/@fqrn@" + CVMFS_KEYS_DIR="/etc/cvmfs/keys/galaxyproject.org" + +- name: Ensure the /etc/cvmfs/keys/galaxyproject.org exists + file: + path: /etc/cvmfs/keys/galaxyproject.org + state: directory + + +- name: Write data.galaxyproject.org key + copy: + dest: /etc/cvmfs/keys/galaxyproject.org/data.galaxyproject.org.pub + content: | + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5LHQuKWzcX5iBbCGsXGt + 6CRi9+a9cKZG4UlX/lJukEJ+3dSxVDWJs88PSdLk+E25494oU56hB8YeVq+W8AQE + 3LWx2K2ruRjEAI2o8sRgs/IbafjZ7cBuERzqj3Tn5qUIBFoKUMWMSIiWTQe2Sfnj + GzfDoswr5TTk7aH/FIXUjLnLGGCOzPtUC244IhHARzu86bWYxQJUw0/kZl5wVGcH + maSgr39h1xPst0Vx1keJ95AH0wqxPbCcyBGtF1L6HQlLidmoIDqcCQpLsGJJEoOs + NVNhhcb66OJHah5ppI1N3cZehdaKyr1XcF9eedwLFTvuiwTn6qMmttT/tHX7rcxT + owIDAQAB + -----END PUBLIC KEY----- + +- name: Write singularity.galaxyproject.org.pub key + copy: + dest: /etc/cvmfs/keys/galaxyproject.org/singularity.galaxyproject.org.pub + content: | + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJZTWTY3/dBfspFKifv8 + TWuuT2Zzoo1cAskKpKu5gsUAyDFbZfYBEy91qbLPC3TuUm2zdPNsjCQbbq1Liufk + uNPZJ8Ubn5PR6kndwrdD13NVHZpXVml1+ooTSF5CL3x/KUkYiyRz94sAr9trVoSx + THW2buV7ADUYivX7ofCvBu5T6YngbPZNIxDB4mh7cEal/UDtxV683A/5RL4wIYvt + S5SVemmu6Yb8GkGwLGmMVLYXutuaHdMFyKzWm+qFlG5JRz4okUWERvtJ2QAJPOzL + mAG1ceyBFowj/r3iJTa+Jcif2uAmZxg+cHkZG5KzATykF82UH1ojUzREMMDcPJi2 + dQIDAQAB + -----END PUBLIC KEY----- + +- name: setup cvmfs + shell: | + cvmfs_config setup diff --git a/build/ansible/roles/nextflow/tasks/main.yml b/build/ansible/roles/nextflow/tasks/main.yml new file mode 100644 index 0000000..103ce93 --- /dev/null +++ b/build/ansible/roles/nextflow/tasks/main.yml @@ -0,0 +1,118 @@ +--- +- name: Install Java {{ java_version }} + apt: + name: openjdk-{{ java_version }}-jdk + state: present + when: ansible_os_family == "Debian" + +- name: Set Java {{ java_version }} as default + alternatives: + name: java + path: /usr/lib/jvm/java-{{ java_version }}-openjdk-amd64/bin/java + when: ansible_os_family == "Debian" + +- name: Create Nextflow directories + file: + path: "{{ item }}" + state: directory + loop: + - "/apps/nextflow/{{ nextflow_version }}/bin" + - "/apps/Modules/modulefiles/nextflow" + +- name: Download Nextflow + get_url: + url: https://get.nextflow.io + dest: "/apps/nextflow/{{ nextflow_version }}/bin/nextflow" + mode: '0755' + +- name: Create Nextflow framework and capsule directories + file: + path: "{{ item }}" + state: directory + mode: '0755' + loop: + - "/apps/nextflow/{{ nextflow_version }}/framework" + - "/apps/nextflow/{{ nextflow_version }}/capsule" + +- name: Pre-download Nextflow core jar into framework and capsule + shell: | + export NXF_VER={{ nextflow_version }} + export NXF_AUTOINSTALL=false + export NXF_DIST=/apps/nextflow/{{ nextflow_version }}/framework + export CAPSULE_CACHE_DIR=/apps/nextflow/{{ nextflow_version }}/capsule + export PATH=/apps/nextflow/{{ nextflow_version }}/bin:${PATH} + nextflow -version + args: + executable: /bin/bash + register: nxf_prefetch + changed_when: false + +- name: Show Nextflow version output + debug: + var: nxf_prefetch.stdout_lines + +- name: Check jar file was downloaded + stat: + path: "/apps/nextflow/{{ nextflow_version }}/framework/{{ nextflow_version }}/nextflow-{{ nextflow_version }}-one.jar" + register: nxf_jar + failed_when: not nxf_jar.stat.exists + +- name: Set jar file permissions + file: + path: "/apps/nextflow/{{ nextflow_version }}/framework/{{ nextflow_version }}/nextflow-{{ nextflow_version }}-one.jar" + mode: '0664' + +- name: Create Nextflow modulefile + copy: + dest: "/apps/Modules/modulefiles/nextflow/{{ nextflow_version }}" + content: | + #%Module1.0 + + module-whatis "Nextflow {{ nextflow_version }}" + prepend-path PATH "/apps/nextflow/{{ nextflow_version }}/bin" + setenv NXF_DIST /apps/nextflow/{{ nextflow_version }}/framework + setenv CAPSULE_CACHE_DIR /apps/nextflow/{{ nextflow_version }}/capsule + +- name: Create nf-core install directory + file: + path: /apps/nf-core/{{ nfcore_version }} + state: directory + recurse: yes + +- name: Install Python venv dependency + apt: + name: python3-venv + state: present + update_cache: yes + +- name: Create nf-core venv + command: python3 -m venv /apps/nf-core/{{ nfcore_version }} + args: + creates: /apps/nf-core/{{ nfcore_version }}/bin/activate + +- name: Install nf-core + command: /apps/nf-core/{{ nfcore_version }}/bin/pip install nf-core=={{ nfcore_version }} + +- name: Create symlink for nfcore alias (optional) + file: + src: /apps/nf-core/{{ nfcore_version }}/bin/nf-core + dest: /apps/nf-core/{{ nfcore_version }}/bin/nfcore + state: link + +- name: Create nf-core modulefile directory + file: + path: /apps/Modules/modulefiles/nf-core + state: directory + +- name: Create nf-core modulefile + copy: + dest: /apps/Modules/modulefiles/nf-core/{{ nfcore_version }} + content: | + #%Module1.0 + module-whatis "nf-core {{ nfcore_version }}" + prepend-path PATH "/apps/nf-core/{{ nfcore_version }}/bin" + + if { [ module-info mode load ] } { + module load nextflow + } + \ No newline at end of file diff --git a/build/ansible/roles/rstudio/tasks/main.yml b/build/ansible/roles/rstudio/tasks/main.yml new file mode 100644 index 0000000..a849d0c --- /dev/null +++ b/build/ansible/roles/rstudio/tasks/main.yml @@ -0,0 +1,76 @@ +--- +- name: Install RStudio Server dependencies + apt: + name: + - gdebi-core + - libclang-dev + state: present + +- name: Download RStudio Server {{ rstudio_version_full }} + get_url: + url: "https://download2.rstudio.org/server/jammy/amd64/rstudio-server-{{ rstudio_version_full }}-amd64.deb" + dest: /tmp/rstudio-server.deb + +- name: Install RStudio Server + apt: + deb: /tmp/rstudio-server.deb + +- name: Clean up installer + file: + path: /tmp/rstudio-server.deb + state: absent + +- name: Disable RStudio Server autostart + systemd: + name: rstudio-server + enabled: no + state: stopped + +- name: Create /apps paths and symlink system binaries + shell: | + mkdir -p /apps/RStudio/{{ rstudio_version }}/bin /apps/Modules/modulefiles/rstudio + ln -sf /usr/sbin/rstudio-server /apps/RStudio/{{ rstudio_version }}/bin/rstudio-server + args: + executable: /bin/bash + +- name: Create RStudio modulefile + become: yes + copy: + dest: "/apps/Modules/modulefiles/rstudio/{{ rstudio_version }}" + owner: root + group: root + mode: '0644' + content: | + #%Module1.0 + module-whatis "RStudio Server {{ rstudio_version }}" + prepend-path PATH "/usr/lib/rstudio-server/bin:/usr/lib/rstudio-server/bin" + + + set ip [exec /bin/bash -c " + curl -fsS --max-time 0.5 http://169.254.169.254/latest/meta-data/public-ipv4 2>/dev/null || true + "] + + if { $ip eq "" } { + set ip [exec /bin/bash -c "hostname -I 2>/dev/null | awk '{print \$1}'"] + } + + puts stderr "" + puts stderr "RStudio Server" + puts stderr "----------------------------------" + puts stderr "Login Details:" + puts stderr "" + puts stderr " Username: $env(USER)" + puts stderr " Password: Your Linux account password" + puts stderr "" + puts stderr "If you have not set a password yet, run:" + puts stderr "" + puts stderr " sudo passwd $env(USER)" + puts stderr "" + puts stderr "To start RStudio Server:" + puts stderr "" + puts stderr " sudo rstudio-server start" + puts stderr "" + puts stderr "Then open in your browser:" + puts stderr "" + puts stderr " http://$ip:8787" + puts stderr "" \ No newline at end of file diff --git a/build/ansible/roles/shelley-bio/tasks/main.yml b/build/ansible/roles/shelley-bio/tasks/main.yml new file mode 100644 index 0000000..2db23d4 --- /dev/null +++ b/build/ansible/roles/shelley-bio/tasks/main.yml @@ -0,0 +1,99 @@ +--- +- name: Ensure Python 3 and pip are installed + apt: + name: + - python3 + - python3-pip + - python3-venv + state: present + update_cache: yes + +- name: Ensure Git is installed + apt: + name: git + state: present + + +- name: Create installation directory + file: + path: /opt/shelley-bio + state: directory + owner: root + group: root + mode: '0755' + recurse: yes + +- name: Clone Shelley Bio repository + git: + repo: https://github.com/Sydney-Informatics-Hub/shelley-bio.git + dest: /opt/shelley-bio + version: main + force: yes + depth: 1 + +- name: Create Shelley Bio virtual environment + command: python3 -m venv /opt/shelley-bio-env + args: + creates: /opt/shelley-bio-env/bin/activate + +- name: Upgrade pip setuptools and wheel in venv + pip: + name: + - pip + - setuptools + - wheel + state: latest + virtualenv: /opt/shelley-bio-env + +- name: Install Shelley Bio dependencies into venv + pip: + requirements: /opt/shelley-bio/requirements.txt + state: present + virtualenv: /opt/shelley-bio-env + +- name: Install Shelley Bio package into venv + pip: + name: /opt/shelley-bio + editable: yes + state: present + virtualenv: /opt/shelley-bio-env + +- name: Fix shelley-bio entry point to use asyncio.run + copy: + dest: /opt/shelley-bio-env/bin/shelley-bio + owner: root + group: root + mode: '0755' + content: | + #!/opt/shelley-bio-env/bin/python3 + import sys + import asyncio + from shelley_bio.client.cli import main + if __name__ == "__main__": + sys.argv[0] = sys.argv[0].removesuffix(".exe") + sys.exit(asyncio.run(main())) + +- name: Add shelley-bio venv to system PATH + lineinfile: + path: /etc/environment + regexp: '^PATH=' + line: 'PATH="{{ updated_path }}"' + state: present + vars: + current_path: "{{ ansible_env.PATH }}" + updated_path: "/opt/shelley-bio-env/bin:{{ current_path }}" + +- name: Remove redundant wrapper script + file: + path: /usr/local/bin/shelley-bio + state: absent + +- name: Create system-wide launcher script + copy: + dest: /usr/local/bin/shelley-bio + owner: root + group: root + mode: '0755' + content: | + #!/usr/bin/env bash + exec /opt/shelley-bio-env/bin/python3 -m shelley_bio.client.cli "$@" diff --git a/build/ansible/roles/singularity/tasks/main.yml b/build/ansible/roles/singularity/tasks/main.yml new file mode 100644 index 0000000..5c7ad48 --- /dev/null +++ b/build/ansible/roles/singularity/tasks/main.yml @@ -0,0 +1,152 @@ +--- +- name: Check if /apps/go exists + stat: + path: /apps/go + register: go_apps_dir + +- name: Check if /usr/local/go exists + stat: + path: /usr/local/go + register: go_local_dir + +- name: Report status of /apps/go + debug: + msg: "/apps/go exists: {{ go_apps_dir.stat.exists }}" + +- name: Report status of /usr/local/go + debug: + msg: "/usr/local/go exists: {{ go_local_dir.stat.exists }}" + +- name: Take action based on Go installation paths + debug: + msg: > + Go is installed in: + {% if go_apps_dir.stat.exists %} + - /apps/go + {% endif %} + {% if go_local_dir.stat.exists %} + - /usr/local/go + {% endif %} + {% if not (go_apps_dir.stat.exists or go_local_dir.stat.exists) %} + - Neither path exists. + {% endif %} + +- name: Install Go + block: + - name: Download Go binary + get_url: + url: "https://dl.google.com/go/go{{ go_version }}.{{ os }}-{{ arch }}.tar.gz" + dest: /tmp/go{{ go_version }}.{{ os }}-{{ arch }}.tar.gz + + - name: Extract Go binary to /apps/ + unarchive: + src: /tmp/go{{ go_version }}.{{ os }}-{{ arch }}.tar.gz + dest: /apps/ + remote_src: yes + +- name: Install Singularity build dependencies + apt: + name: + - libsubid-dev + state: present + +- name: Create directories for Singularity + shell: | + export GOPATH=${HOME}/go && \ + mkdir -p $GOPATH/src/github.com/sylabs && \ + cd $GOPATH/src/github.com/sylabs && \ + wget https://github.com/sylabs/singularity/releases/download/v{{ singularity_version }}/singularity-ce-{{ singularity_version }}.tar.gz && \ + tar -xzf singularity-ce-{{ singularity_version }}.tar.gz && \ + cd ./singularity-ce-{{ singularity_version }} + +- name: Compile the SingularityCE source code + shell: | + export GOPATH=${HOME}/go + export PATH=/apps/go/bin:${PATH}:${GOPATH}/bin + cd $GOPATH/src/github.com/sylabs/singularity-ce-{{ singularity_version }} && \ + ./mconfig --prefix=/opt/singularity/{{ singularity_version }} && \ + make -C ./builddir && \ + make -C ./builddir install + args: + executable: /bin/bash + +- name: Clean up Singularity source code + file: + path: /tmp/singularity + state: absent + +- name: Clean up go source code + file: + path: /apps/go + state: absent + +- name: Create modulefile for Singularity + copy: + dest: /opt/Modules/modulefiles/singularity + content: | + #%Module1.0 + + proc ModulesHelp { } { + puts stderr "\tThis module makes available commands to run Singularity\n" + } + + module-whatis "Sets up the Singularity system in your environment" + prepend-path PATH "{{ singularity_prefix }}/{{ singularity_version }}/bin" + +- name: Install shpc + shell: | + mkdir -p /opt/shpc/bin + cd /opt/shpc + git clone -b {{ shpc_version }} https://github.com/singularityhub/singularity-hpc.git + cd singularity-hpc + pip install -e .[all] + ln -s /opt/shpc/bin/shpc /usr/local/bin/shpc + cp /opt/shpc/singularity-hpc/shpc/settings.yml /opt/shpc/singularity-hpc/shpc/settings-default.yml + cp /opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua /opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity-original.lua + args: + executable: /bin/bash + +- name: Configure shpc settings + lineinfile: + path: /opt/shpc/singularity-hpc/shpc/settings.yml + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + state: present + loop: + - { regexp: '^module_base:.*', line: 'module_base: $HOME/shpc/modules' } + - { regexp: '^container_base:.*', line: 'container_base: $HOME/shpc/containers' } + - { regexp: '^wrapper_base:.*', line: 'wrapper_base: $HOME/shpc/wrappers' } + - { regexp: '^views_base:.*', line: 'views_base: $HOME/shpc/views' } + +- name: Check if singularity.lua exists + stat: + path: "/opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua" + register: lua_file + +- name: Create singularity.lua if it does not exist + copy: + dest: "/opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua" + content: | + -- Default content for singularity.lua + local moduleDir = subprocess("realpath " .. myFileName()):match("(.*[/])") or "." + when: not lua_file.stat.exists + +- name: Replace line starting with 'local moduleDir' + lineinfile: + path: "/opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua" + regexp: '^local moduleDir.*' + line: 'local moduleDir = myFileName():match("(.*[/])") or "."' + state: present + +- name: Create shpc modulefile + copy: + dest: "/opt/Modules/modulefiles/shpc" + content: | + #%Module1.0 + + module-whatis "Singularity HPC" + prepend-path PATH "/opt/shpc/bin" + if { [ module-info mode load ] } { + module load singularity + } + \ No newline at end of file diff --git a/build/ansible/roles/validate_cvmfs/tasks/main.yml b/build/ansible/roles/validate_cvmfs/tasks/main.yml new file mode 100644 index 0000000..40c9260 --- /dev/null +++ b/build/ansible/roles/validate_cvmfs/tasks/main.yml @@ -0,0 +1,26 @@ +--- +- name: Check cvmfs is installed + command: which cvmfs2 + register: cvmfs2_check + changed_when: false + failed_when: cvmfs2_check.rc != 0 + +- name: Check config file exists + stat: + path: /etc/cvmfs/default.local + register: cvmfs_config + failed_when: not cvmfs_config.stat.exists + +- name: Probe repositories + command: cvmfs_config probe {{ item }} + register: probe_result + failed_when: false + loop: + - data.galaxyproject.org + - singularity.galaxyproject.org + +- name: Verify cvmfs proxy setting + command: grep "CVMFS_HTTP_PROXY" /etc/cvmfs/default.local + register: proxy_check + changed_when: false + failed_when: proxy_check.rc != 0 \ No newline at end of file diff --git a/build/ansible/roles/validate_jupyter/tasks/main.yml b/build/ansible/roles/validate_jupyter/tasks/main.yml new file mode 100644 index 0000000..e31bfec --- /dev/null +++ b/build/ansible/roles/validate_jupyter/tasks/main.yml @@ -0,0 +1,33 @@ +--- +- name: Check Jupyter binary exists + stat: + path: "/apps/jupyter/{{ jupyter_version }}/bin/jupyter" + register: jupyter_bin + +- name: Assert Jupyter binary exists + assert: + that: + - jupyter_bin.stat is defined + - jupyter_bin.stat.exists + fail_msg: "Jupyter binary not found at /apps/jupyter/{{ jupyter_version }}/bin/jupyter" + +- name: Check Jupyter version + command: jupyter --version + changed_when: false + register: jupyter_version_output + +- name: Show Jupyter version + debug: + var: jupyter_version_output.stdout_lines + +- name: Check Jupyter modulefile exists + stat: + path: "/apps/Modules/modulefiles/jupyter/{{ jupyter_version }}" + register: jupyter_module + +- name: Assert Jupyter modulefile exists + assert: + that: + - jupyter_module.stat is defined + - jupyter_module.stat.exists + fail_msg: "Jupyter modulefile not found at /apps/Modules/modulefiles/jupyter/{{ jupyter_version }}" \ No newline at end of file diff --git a/build/ansible/roles/validate_nextflow/tasks/main.yml b/build/ansible/roles/validate_nextflow/tasks/main.yml new file mode 100644 index 0000000..50f0a8a --- /dev/null +++ b/build/ansible/roles/validate_nextflow/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- name: Check Nextflow binary exists + stat: + path: "/apps/nextflow/{{ nextflow_version }}/bin/nextflow" + register: nf_bin + failed_when: not nf_bin.stat.exists + +- name: Check Nextflow is executable + command: "/apps/nextflow/{{ nextflow_version }}/bin/nextflow -version" + changed_when: false + environment: + NXF_VER: "{{ nextflow_version }}" + NXF_AUTOINSTALL: "false" + NXF_DIST: "/tmp/nxf-test" + CAPSULE_CACHE_DIR: "/tmp/nxf-capsule" + +- name: Check nf-core is installed + command: "/apps/nf-core/{{ nfcore_version }}/bin/nf-core --version" + changed_when: false + +- name: Check Nextflow modulefile exists + stat: + path: "/apps/Modules/modulefiles/nextflow/{{ nextflow_version }}" + register: nf_module + failed_when: not nf_module.stat.exists \ No newline at end of file diff --git a/build/ansible/roles/validate_rstudio/tasks/main.yml b/build/ansible/roles/validate_rstudio/tasks/main.yml new file mode 100644 index 0000000..3cec312 --- /dev/null +++ b/build/ansible/roles/validate_rstudio/tasks/main.yml @@ -0,0 +1,35 @@ +--- +- name: Check RStudio Server binary exists + stat: + path: /usr/sbin/rstudio-server + register: rstudio_bin + +- name: Assert RStudio binary exists + assert: + that: + - rstudio_bin.stat is defined + - rstudio_bin.stat.exists + fail_msg: "RStudio binary not found at /usr/sbin/rstudio-server" + +- name: Check RStudio Server version + command: rstudio-server version + changed_when: false + register: rstudio_version_output + +- name: Verify expected version + assert: + that: + - "rstudio_version in rstudio_version_output.stdout" + fail_msg: "RStudio version mismatch — expected {{ rstudio_version }}, got {{ rstudio_version_output.stdout }}" + +- name: Check RStudio modulefile exists + stat: + path: "/apps/Modules/modulefiles/rstudio/{{ rstudio_version }}" + register: rstudio_module + +- name: Assert RStudio modulefile exists + assert: + that: + - rstudio_module.stat is defined + - rstudio_module.stat.exists + fail_msg: "RStudio modulefile not found at /apps/Modules/modulefiles/rstudio/{{ rstudio_version }}" \ No newline at end of file diff --git a/build/ansible/roles/validate_shelley-bio/tasks/main.yml b/build/ansible/roles/validate_shelley-bio/tasks/main.yml new file mode 100644 index 0000000..c8c2acd --- /dev/null +++ b/build/ansible/roles/validate_shelley-bio/tasks/main.yml @@ -0,0 +1,37 @@ +--- +- name: Check launcher script exists + stat: + path: /usr/local/bin/shelley-bio + register: shelley_bin + failed_when: not shelley_bin.stat.exists + +- name: Check launcher is executable + stat: + path: /usr/local/bin/shelley-bio + register: shelley_exec + failed_when: not shelley_exec.stat.executable + +- name: Run shelley-bio CLI test + command: shelley-bio search "quality control" + changed_when: false + register: shelley_test + failed_when: false + +- name: Report CLI test result + debug: + msg: "{{ 'OK' if shelley_test.rc == 0 else 'FAILED — may need network access to run' }}" + +- name: Check MOTD exists + stat: + path: /etc/motd.d/bioshell + register: motd_file + +- name: Assert MOTD exists + assert: + that: + - motd_file.stat is defined + - motd_file.stat.exists + +- name: Check MOTD contains BioShell marker + command: grep -q "BioShell" /etc/motd.d/bioshell + changed_when: false \ No newline at end of file diff --git a/build/ansible/test-bioshell.yml b/build/ansible/test-bioshell.yml new file mode 100644 index 0000000..9bdc600 --- /dev/null +++ b/build/ansible/test-bioshell.yml @@ -0,0 +1,14 @@ +--- +- name: Validate BioShell base image + hosts: all + become: true + + vars_files: + - "vars/tool-versions.yml" + + roles: + - validate_cvmfs + - validate_nextflow + - validate_jupyter + - validate_rstudio + - validate_shelley-bio \ No newline at end of file diff --git a/build/ansible/vars/nectar.yml b/build/ansible/vars/nectar.yml new file mode 100644 index 0000000..e59af7d --- /dev/null +++ b/build/ansible/vars/nectar.yml @@ -0,0 +1 @@ +cvmfs_proxy: "DIRECT" \ No newline at end of file diff --git a/build/ansible/vars/nirin.yml b/build/ansible/vars/nirin.yml new file mode 100644 index 0000000..f45c135 --- /dev/null +++ b/build/ansible/vars/nirin.yml @@ -0,0 +1 @@ +cvmfs_proxy: "130.56.247.90:3128;130.56.247.132:3128" \ No newline at end of file diff --git a/build/ansible/vars/tool-versions.yml b/build/ansible/vars/tool-versions.yml new file mode 100644 index 0000000..0b9d449 --- /dev/null +++ b/build/ansible/vars/tool-versions.yml @@ -0,0 +1,34 @@ +# ============================================================ +# Tool versions — update here, everything else follows +# ============================================================ +singularity_version: "4.4.1" +singularity_prefix: "/opt/singularity" + +shpc_version: "0.1.33" + +go_version: "1.26.1" +os: "linux" +arch: "amd64" + + +java_version: "21" +nextflow_version: "25.10.4" +nfcore_version: "3.5.2" + +rstudio_version_full: "2023.12.1-402" +rstudio_version: "2023.12.1" + +# Each platform file overrides this proxy variable +cvmfs_quota_limit: 4096 +cvmfs_proxy: "DIRECT" +cvmfs_repositories: "data.galaxyproject.org,singularity.galaxyproject.org" +cvmfs_biocommons_url: "http://bcws.test.aarnet.edu.au/cvmfs/@fqrn@" + +# Module paths +module_base_apps: "/apps/Modules/modulefiles" +module_base_opt: "/opt/Modules/modulefiles" + +# Common tools +snakemake_version: "6.15.1" +r_version: "4.1.2" +jupyter_version: "2024.10" \ No newline at end of file diff --git a/build/build-bioshell.yml b/build/build-bioshell.yml deleted file mode 100644 index 195bd04..0000000 --- a/build/build-bioshell.yml +++ /dev/null @@ -1,747 +0,0 @@ ---- -- name: Build BioShell - hosts: all - become: true - - tasks: - - name: Wait for apt lock to be released - become: true - shell: | - while fuser /var/lib/apt/lists/lock >/dev/null 2>&1 || \ - fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || \ - fuser /var/lib/dpkg/lock >/dev/null 2>&1; do - sleep 5 - done - changed_when: false - - - name: Update apt repository - apt: - update_cache: yes - register: apt_update - retries: 3 - delay: 10 - until: apt_update is succeeded - - - name: Ensure necessary packages are installed - apt: - name: - - lmod - - build-essential - - libssl-dev - - uuid-dev - - libgpgme11-dev - - squashfs-tools - - git - - wget - - autoconf - - automake - - cryptsetup - - fuse2fs - - fuse - - libfuse-dev - - libglib2.0-dev - - libtool - - pkg-config - - runc - - squashfs-tools-ng - - uidmap - - zlib1g-dev - - libseccomp-dev - - nano - - jupyter - - snakemake - - r-base - - python3 - - python3-pip - - python3-venv - - ansible - - tree - state: present - - - name: Install build dependencies for R packages - apt: - name: - - build-essential - - cmake - - gdal-bin - - libcurl4-openssl-dev - - libxml2-dev - - libfontconfig1-dev - - libfreetype6-dev - - libharfbuzz-dev - - libfribidi-dev - - libudunits2-dev - - libglpk-dev - - libblas-dev - - liblapack-dev - - libopenblas-dev - - libtiff5-dev - - libjpeg-dev - - libpng-dev - - libcairo2-dev - state: present - update_cache: yes - - - name: Ensure the /opt/Modules/modulefiles directory exists - file: - path: /opt/Modules/modulefiles - state: directory - - - name: Ensure the /apps/Modules/modulefiles directory exists - file: - path: /apps/Modules/modulefiles - state: directory - - # Install RStudio - - name: Install RStudio Server dependencies - apt: - name: - - gdebi-core - - libclang-dev - state: present - - - name: Set RStudio Server version - set_fact: - rstudio_version: "2023.12.1-402" - - - name: Download RStudio Server - get_url: - url: "https://download2.rstudio.org/server/jammy/amd64/rstudio-server-{{ rstudio_version }}-amd64.deb" - dest: "/tmp/rstudio-server.deb" - - - name: Install RStudio Server - apt: - deb: /tmp/rstudio-server.deb - - - name: Clean up RStudio Server installer - file: - path: /tmp/rstudio-server.deb - state: absent - - - name: Enable and start RStudio Server - systemd: - name: rstudio-server - enabled: no - state: stopped - - # Install Singularity - - name: Check if /apps/go exists - stat: - path: /apps/go - register: go_apps_dir - - - name: Check if /usr/local/go exists - stat: - path: /usr/local/go - register: go_local_dir - - - name: Report status of /apps/go - debug: - msg: "/apps/go exists: {{ go_apps_dir.stat.exists }}" - - - name: Report status of /usr/local/go - debug: - msg: "/usr/local/go exists: {{ go_local_dir.stat.exists }}" - - - name: Take action based on Go installation paths - debug: - msg: > - Go is installed in: - {% if go_apps_dir.stat.exists %} - - /apps/go - {% endif %} - {% if go_local_dir.stat.exists %} - - /usr/local/go - {% endif %} - {% if not (go_apps_dir.stat.exists or go_local_dir.stat.exists) %} - - Neither path exists. - {% endif %} - - - name: Install Go - block: - - name: Set Go version and architecture - set_fact: - go_version: "1.22.7" - os: "linux" - arch: "amd64" - - - name: Download Go binary - get_url: - url: "https://dl.google.com/go/go{{ go_version }}.{{ os }}-{{ arch }}.tar.gz" - dest: /tmp/go{{ go_version }}.{{ os }}-{{ arch }}.tar.gz - - - name: Extract Go binary to /apps/ - unarchive: - src: /tmp/go{{ go_version }}.{{ os }}-{{ arch }}.tar.gz - dest: /apps/ - remote_src: yes - - - name: Create directories for Singularity - shell: | - export VERSION=4.2.1 && \ - export GOPATH=${HOME}/go && \ - mkdir -p $GOPATH/src/github.com/sylabs && \ - cd $GOPATH/src/github.com/sylabs && \ - wget https://github.com/sylabs/singularity/releases/download/v${VERSION}/singularity-ce-${VERSION}.tar.gz && \ - tar -xzf singularity-ce-${VERSION}.tar.gz && \ - cd ./singularity-ce-${VERSION} - - - name: Compile the SingularityCE source code - shell: | - export VERSION=4.2.1 - export GOPATH=${HOME}/go - export PATH=/apps/go/bin:${PATH}:${GOPATH}/bin - cd $GOPATH/src/github.com/sylabs/singularity-ce-${VERSION} && \ - ./mconfig --prefix=/opt/singularity/4.2.1 && \ - make -C ./builddir && \ - make -C ./builddir install - args: - executable: /bin/bash - - - name: Clean up Singularity source code - file: - path: /tmp/singularity - state: absent - - - name: Clean up go source code - file: - path: /apps/go - state: absent - - - name: Create modulefile for Singularity - copy: - dest: /opt/Modules/modulefiles/singularity - content: | - #%Module1.0 - - proc ModulesHelp { } { - puts stderr "\tThis module makes available commands to run Singularity\n" - } - - module-whatis "Sets up the Singularity system in your environment" - prepend-path PATH "/opt/singularity/4.2.1/bin" - - # Install Spack - - name: Install Spack - block: - - name: Clone Spack repository - shell: | - git clone -c feature.manyFiles=true --depth=2 https://github.com/spack/spack.git /usr/local/spack - - # Intall Nextflow - - name: Install Java 21 (required for Nextflow) - apt: - name: openjdk-21-jdk - state: present - become: yes - when: ansible_os_family == "Debian" - - - name: Ensure Java 21 is default JVM - alternatives: - name: java - path: /usr/lib/jvm/java-21-openjdk-amd64/bin/java - become: yes - when: ansible_os_family == "Debian" - - - # Make Nextflowfolder - - name: Create Nextflow folder - shell: | - mkdir -p /apps/Modules/modulefiles/nextflow - mkdir -p /apps/nextflow/24.10.2/bin - args: - executable: /bin/bash - - - name: Download Nextflow - get_url: - url: https://get.nextflow.io - dest: /tmp/nextflow - mode: '0755' - - - name: Move Nextflow to /apps - copy: - src: /tmp/nextflow - dest: /apps/nextflow/24.10.2/bin - mode: '0755' - remote_src: yes - - - name: Verify Nextflow installation with user-writable paths - shell: | - export NXF_VER=24.10.2 - export NXF_AUTOINSTALL=false - export NXF_DIST=$HOME/nextflow/framework - export CAPSULE_CACHE_DIR=$HOME/nextflow/capsule - export PATH=/apps/nextflow/24.10.2/bin:${PATH} - mkdir -p "$NXF_DIST" "$CAPSULE_CACHE_DIR" - nextflow -version - register: nextflow_version - args: - executable: /bin/bash - - - name: Clean up temporary files - file: - path: /tmp/nextflow - state: absent - - - name: Create modulefile for Nextflow - copy: - dest: /apps/Modules/modulefiles/nextflow/24.10.2 - content: | - #%Module1.0 - - module-whatis "Nextflow" - prepend-path PATH "/apps/nextflow/24.10.2/bin" - setenv NXF_DIST /apps/nextflow/24.10.2/framework - setenv CAPSULE_CACHE_DIR /apps/nextflow/24.10.2/capsule - - # add nf-core modulefile - - name: Create nf-core install directory - file: - path: /apps/nf-core/3.5.2 - state: directory - recurse: yes - - - name: Install Python venv dependency - apt: - name: python3-venv - state: present - update_cache: yes - - - name: Create nf-core virtual environment - command: python3 -m venv /apps/nf-core/3.5.2 - args: - creates: /apps/nf-core/3.5.2/bin/activate - - - name: Install nf-core into venv - command: /apps/nf-core/3.5.2/bin/pip install nf-core==3.5.2 - - - name: Create symlink for nfcore alias (optional) - file: - src: /apps/nf-core/3.5.2/bin/nf-core - dest: /apps/nf-core/3.5.2/bin/nfcore - state: link - - # --------------------------- - # Create modulefile directory - # --------------------------- - - - name: Create nf-core modulefile directory - file: - path: /apps/Modules/modulefiles/nf-core - state: directory - - - name: Create nf-core modulefile - copy: - dest: /apps/Modules/modulefiles/nf-core/3.5.2 - content: | - #%Module1.0 - module-whatis "nf-core 3.5.2" - prepend-path PATH "/apps/nf-core/3.5.2/bin" - - if { [ module-info mode load ] } { - module load nextflow - } - - # Install shpc - - name: Install shpc - shell: | - mkdir -p /opt/shpc/bin - cd /opt/shpc - git clone -b 0.1.28 https://github.com/singularityhub/singularity-hpc.git - cd singularity-hpc - pip install -e .[all] - ln -s /opt/shpc/bin/shpc /usr/local/bin/shpc - cp /opt/shpc/singularity-hpc/shpc/settings.yml /opt/shpc/singularity-hpc/shpc/settings-default.yml - cp /opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua /opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity-original.lua - - - name: update module_base - lineinfile: - path: /opt/shpc/singularity-hpc/shpc/settings.yml - regexp: '^module_base: \$root_dir/modules' - line: 'module_base: $HOME/shpc/modules' - state: present - - - name: update container_base - lineinfile: - path: /opt/shpc/singularity-hpc/shpc/settings.yml - regexp: '^container_base: \$root_dir/containers' - line: 'container_base: $HOME/shpc/containers' - state: present - - - name: update wrapper_base - lineinfile: - path: /opt/shpc/singularity-hpc/shpc/settings.yml - regexp: '^wrapper_base: \$root_dir/modules' - line: 'wrapper_base: $HOME/shpc/wrappers' - state: present - - - name: update view_base - lineinfile: - path: /opt/shpc/singularity-hpc/shpc/settings.yml - regexp: '^views_base: \$root_dir/views' - line: 'views_base: $HOME/shpc/views' - state: present - - - name: Check if singularity.lua exists - stat: - path: "/opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua" - register: lua_file - - - name: Create singularity.lua if it does not exist - copy: - dest: "/opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua" - content: | - -- Default content for singularity.lua - local moduleDir = subprocess("realpath " .. myFileName()):match("(.*[/])") or "." - when: not lua_file.stat.exists - - - name: Replace line starting with 'local moduleDir' - lineinfile: - path: "/opt/shpc/singularity-hpc/shpc/main/modules/templates/singularity.lua" - regexp: '^local moduleDir.*' - line: 'local moduleDir = myFileName():match("(.*[/])") or "."' - state: present - - - name: Create shpc modulefile - copy: - dest: "/opt/Modules/modulefiles/shpc" - content: | - #%Module1.0 - - module-whatis "Singularity HPC" - prepend-path PATH "/opt/shpc/bin" - if { [ module-info mode load ] } { - module load singularity - } - - - - name: Create /apps paths and symlink system binaries - shell: | - mkdir -p /apps/R/4.1.2/bin /apps/Modules/modulefiles/R - ln -sf /usr/bin/R /apps/R/4.1.2/bin/R - - mkdir -p /apps/jupyter/2024.10/bin /apps/Modules/modulefiles/jupyter - ln -sf /usr/bin/jupyter /apps/jupyter/2024.10/bin/jupyter - - mkdir -p /apps/snakemake/6.15.1/bin /apps/Modules/modulefiles/snakemake - ln -sf /usr/bin/snakemake /apps/snakemake/6.15.1/bin/snakemake - - mkdir -p /apps/ansible/2.10.8/bin /apps/Modules/modulefiles/ansible - ln -sf /usr/bin/ansible /apps/ansible/2.10.8/bin/ansible - - - mkdir -p /apps/RStudio/2023.12.1/bin /apps/Modules/modulefiles/rstudio - ln -sf /usr/sbin/rstudio-server /apps/RStudio/2023.12.1/bin/rstudio-server - args: - executable: /bin/bash - - - - name: Create R modulefile - copy: - dest: "/apps/Modules/modulefiles/R/4.1.2" - content: | - #%Module1.0 - - prepend-path PATH "/apps/R/4.1.2/bin" - - - name: Create jupyter modulefile - copy: - dest: "/apps/Modules/modulefiles/jupyter/2024.10" - content: | - #%Module1.0 - - prepend-path PATH "/apps/jupyter/2024.10/bin" - - - - name: Create snakemake modulefile - copy: - dest: "/apps/Modules/modulefiles/snakemake/6.15.1" - content: | - #%Module1.0 - - prepend-path PATH "/apps/snakemake/6.15.1/bin" - - - name: Create R modulefile - copy: - dest: "/apps/Modules/modulefiles/ansible/2.10.8" - content: | - #%Module1.0 - - prepend-path PATH "/apps/ansible/2.10.8/bin" - - - name: Create RStudio modulefile - become: yes - copy: - dest: "/apps/Modules/modulefiles/rstudio/2023.12.1" - owner: root - group: root - mode: '0644' - content: | - #%Module1.0 - module-whatis "RStudio Server 2023.12.1" - prepend-path PATH "/usr/lib/rstudio-server/bin:/usr/lib/rstudio-server/bin" - - - set ip [exec /bin/bash -c " - curl -fsS --max-time 0.5 http://169.254.169.254/latest/meta-data/public-ipv4 2>/dev/null || true - "] - - if { $ip eq "" } { - set ip [exec /bin/bash -c "hostname -I 2>/dev/null | awk '{print \$1}'"] - } - - puts stderr "" - puts stderr "RStudio Server" - puts stderr "----------------------------------" - puts stderr "Login Details:" - puts stderr "" - puts stderr " Username: $env(USER)" - puts stderr " Password: Your Linux account password" - puts stderr "" - puts stderr "If you have not set a password yet, run:" - puts stderr "" - puts stderr " sudo passwd $env(USER)" - puts stderr "" - puts stderr "To start RStudio Server:" - puts stderr "" - puts stderr " sudo rstudio-server start" - puts stderr "" - puts stderr "Then open in your browser:" - puts stderr "" - puts stderr " http://$ip:8787" - puts stderr "" - - - #Install cvmfs and configure with Galaxy, AARNET training, EESSI access - - name: Download CVMFS release package - get_url: - url: https://ecsft.cern.ch/dist/cvmfs/cvmfs-release/cvmfs-release-latest_all.deb - dest: /tmp/cvmfs-release-latest_all.deb - - - name: Install CVMFS release package - apt: - deb: /tmp/cvmfs-release-latest_all.deb - - - name: Remove CVMFS release package - file: - path: /tmp/cvmfs-release-latest_all.deb - state: absent - - - name: Update apt cache - apt: - update_cache: yes - - - name: Install CVMFS - apt: - name: cvmfs - state: present - - - name: Write default.local - copy: - dest: /etc/cvmfs/default.local - content: | - CVMFS_REPOSITORIES=data.biocommons.aarnet.edu.au,data.galaxyproject.org,singularity.galaxyproject.org - CVMFS_HTTP_PROXY='DIRECT' - CVMFS_QUOTA_LIMIT=4096 - CVMFS_USE_GEOAPI=yes - - - name: set up cvmfs and set autofs - shell: | - cvmfs_config setup - sed -i 's%#+dir:/etc/auto.master.d%+dir:/etc/auto.master.d%' /etc/auto.master - systemctl restart autofs - - - name: Write data.biocommons.aarnet.edu.au.conf - copy: - dest: /etc/cvmfs/config.d/data.biocommons.aarnet.edu.au.conf - content: | - CVMFS_SERVER_URL="http://bcws.test.aarnet.edu.au/cvmfs/@fqrn@" - CVMFS_PUBLIC_KEY="/etc/cvmfs/keys/data.biocommons.aarnet.edu.au/data.biocommons.aarnet.edu.au.pub" - - - name: Write galaxyproject.org.conf - copy: - dest: /etc/cvmfs/domain.d/galaxyproject.org.conf - content: | - CVMFS_SERVER_URL="http://cvmfs1-tacc0.galaxyproject.org/cvmfs/@fqrn@;http://cvmfs1-iu0.galaxyproject.org/cvmfs/@fqrn@;http://cvmfs1-psu0.galaxyproject.org/cvmfs/@fqrn@;http://galaxy.jrc.ec.europa.eu:8008/cvmfs/@fqrn@;http://cvmfs1-mel0.gvl.org.au/cvmfs/@fqrn@" - CVMFS_KEYS_DIR="/etc/cvmfs/keys/galaxyproject.org" - - - name: Ensure the /etc/cvmfs/keys/data.biocommons.aarnet.edu.au directory exists - file: - path: /etc/cvmfs/keys/data.biocommons.aarnet.edu.au - state: directory - - - name: data.biocommons.aarnet.edu.au key - copy: - dest: /etc/cvmfs/keys/data.biocommons.aarnet.edu.au/data.biocommons.aarnet.edu.au.pub - content: | - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3JEVgVhOjigVTX4OPVpj - EPIZEuhGzqhuvzu4ujovyEjrYoeXIfG+YSFIj9a3YxgPxRl1LVsBm59g+tqrUs25 - //xUFIQVomaw8gLRy9txflDe2SWVh4m40IIEGGQQoXyY/Iv26i8vtcVhAJnvL+lM - Iu25nG3MM8rcuuGrYnQQekeoSZLd5Tg4JHC+YEy9n1jUkxCBUTr5XFIXCEQkR2Nr - 9p6Hgol/NqUKZT76K3yWNfbRS/kXEB3ZOP6h0QDvVgwzfgTifoLge1cfJuiy/KtM - /UJr1k/cVp4l5ssL7Qqx582eGRJ/rn7K2BVNVF8XI+Fvgpp9DQPxu6U4S4WANKBE - OQIDAQAB - -----END PUBLIC KEY----- - - - name: Ensure the /etc/cvmfs/keys/galaxyproject.org exists - file: - path: /etc/cvmfs/keys/galaxyproject.org - state: directory - - - - name: Write data.galaxyproject.org key - copy: - dest: /etc/cvmfs/keys/galaxyproject.org/data.galaxyproject.org.pub - content: | - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5LHQuKWzcX5iBbCGsXGt - 6CRi9+a9cKZG4UlX/lJukEJ+3dSxVDWJs88PSdLk+E25494oU56hB8YeVq+W8AQE - 3LWx2K2ruRjEAI2o8sRgs/IbafjZ7cBuERzqj3Tn5qUIBFoKUMWMSIiWTQe2Sfnj - GzfDoswr5TTk7aH/FIXUjLnLGGCOzPtUC244IhHARzu86bWYxQJUw0/kZl5wVGcH - maSgr39h1xPst0Vx1keJ95AH0wqxPbCcyBGtF1L6HQlLidmoIDqcCQpLsGJJEoOs - NVNhhcb66OJHah5ppI1N3cZehdaKyr1XcF9eedwLFTvuiwTn6qMmttT/tHX7rcxT - owIDAQAB - -----END PUBLIC KEY----- - - - name: Write singularity.galaxyproject.org.pub key - copy: - dest: /etc/cvmfs/keys/galaxyproject.org/singularity.galaxyproject.org.pub - content: | - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJZTWTY3/dBfspFKifv8 - TWuuT2Zzoo1cAskKpKu5gsUAyDFbZfYBEy91qbLPC3TuUm2zdPNsjCQbbq1Liufk - uNPZJ8Ubn5PR6kndwrdD13NVHZpXVml1+ooTSF5CL3x/KUkYiyRz94sAr9trVoSx - THW2buV7ADUYivX7ofCvBu5T6YngbPZNIxDB4mh7cEal/UDtxV683A/5RL4wIYvt - S5SVemmu6Yb8GkGwLGmMVLYXutuaHdMFyKzWm+qFlG5JRz4okUWERvtJ2QAJPOzL - mAG1ceyBFowj/r3iJTa+Jcif2uAmZxg+cHkZG5KzATykF82UH1ojUzREMMDcPJi2 - dQIDAQAB - -----END PUBLIC KEY----- - - - name: setup cvmfs and probe resources - shell: | - cvmfs_config setup - cvmfs_config probe data.galaxyproject.org - cvmfs_config probe singularity.galaxyproject.org - - - name: Update PATH to remove /usr/local/games and add /usr/local/spack/bin - lineinfile: - path: /etc/environment - regexp: '^PATH=' - line: 'PATH="{{ updated_path }}"' - state: present - vars: - current_path: "{{ ansible_env.PATH }}" - updated_path: "{{ current_path | replace('/usr/local/games', '') | trim | replace('::', ':') | regex_replace('^:|:$', '') | regex_replace('^:', '') | regex_replace(':$', '') }}:/usr/local/spack/bin" - - - name: Comment out existing module paths - lineinfile: - path: /etc/lmod/modulespath - regexp: '^(.*(/etc/lmod/modules|/usr/share/lmod/lmod/modulefiles).*)' - line: '# \1' - backrefs: yes - state: present - - - name: Add new module paths - lineinfile: - path: /etc/lmod/modulespath - line: "{{ item }}" - state: present - loop: - - '/apps/Modules/modulefiles' - - '/opt/Modules/modulefiles' - - # ============================== - # Install Shelley Bio - # ============================== - - name: Ensure Python 3 and pip are installed - apt: - name: - - python3 - - python3-pip - state: present - update_cache: yes - - - name: Ensure Git is installed - apt: - name: git - state: present - - - name: Create installation directory for Shelley Bio - file: - path: /opt/shelley-bio - state: directory - owner: root - group: root - mode: '0755' - - - name: Clone Shelley Bio repository - git: - repo: https://github.com/Sydney-Informatics-Hub/shelley-bio.git - dest: /opt/shelley-bio - version: main - force: yes - depth: 1 - - - name: Install Shelley Bio dependencies globally - pip: - requirements: /opt/shelley-bio/requirements.txt - state: present - executable: pip3 - - - name: Install Shelley Bio package globally - pip: - name: /opt/shelley-bio - editable: yes - state: present - executable: pip3 - - - - name: Create system-wide launcher script - copy: - dest: /usr/local/bin/shelley-bio - owner: root - group: root - mode: '0755' - content: | - #!/usr/bin/env bash - exec python3 -m shelley_bio.client.cli "$@" - - - name: Test Shelley Bio CLI - command: shelley-bio search "quality control" - register: shelley_cli_test - ignore_errors: yes - - - name: Show Shelley Bio CLI test output - debug: - var: shelley_cli_test.stdout_lines - - - name: Add BioShell welcome message with turtle - copy: - dest: /etc/motd - owner: root - group: root - mode: '0644' - content: | - ################################################################## - # # - # Welcome to BioShell! # - # # - # A range of commonly used bioinformatics software is available # - # via CVMFS. # - # # - # To make the software folders visible, run: # - # cvmfs_config probe # - # # - # If you need help finding and installing software, # - # ask Shelley-Bio # - # _ .----. # - # (_ \/ \_, # - # `uu----uu' # - # Basic commands: # - # shelley-bio find # - # shelley-bio search "" # - # shelley-bio versions # - # shelley-bio build # - # shelley-bio interactive # - ################################################################## diff --git a/build/examples/openstack-bioshell-nectar.pkr.hcl b/build/examples/openstack-bioshell-nectar.pkr.hcl deleted file mode 100644 index 6a5cf59..0000000 --- a/build/examples/openstack-bioshell-nectar.pkr.hcl +++ /dev/null @@ -1,40 +0,0 @@ -packer { - required_plugins { - openstack = { - version = ">= 1.1.2" - source = "github.com/hashicorp/openstack" - } - - ansible = { - version = ">= 1.1.1" - source = "github.com/hashicorp/ansible" - } - } -} - -source "openstack" "ubuntu" { - image_name = "bioshell" - flavor = "r3.small" - source_image = "c0250c96-98a4-4bfa-b67c-51874808337f" - ssh_username = "ubuntu" - volume_size = 20 -} - -build { - sources = ["source.openstack.ubuntu"] - -provisioner "ansible" { - playbook_file = "./build-bioshell.yml" - - extra_arguments = [ - "--extra-vars", "ansible_user=ubuntu" - ] - - ansible_env_vars = [ - "ANSIBLE_HOST_KEY_CHECKING=False", - "ANSIBLE_SCP_IF_SSH=True" - ] - - use_proxy = false - } -} diff --git a/build/examples/openstack-bioshell-nirin.pkr.hcl b/build/examples/openstack-bioshell-nirin.pkr.hcl deleted file mode 100644 index 083f29f..0000000 --- a/build/examples/openstack-bioshell-nirin.pkr.hcl +++ /dev/null @@ -1,42 +0,0 @@ -packer { - required_plugins { - openstack = { - version = ">= 1.1.2" - source = "github.com/hashicorp/openstack" - } - - ansible = { - version = ">= 1.1.1" - source = "github.com/hashicorp/ansible" - } - } -} - -source "openstack" "ubuntu" { - image_name = "bioshell" - flavor = "c3.1c2m10d" - networks = [""] # update via: openstack network list - select network associated with your project - availability_zone = "CloudV3" - source_image = "68b8635c-9ae8-457a-afd6-b8609a36bf66" - ssh_username = "ubuntu" - volume_size = 20 -} - -build { - sources = ["source.openstack.ubuntu"] - -provisioner "ansible" { - playbook_file = "./build-bioshell.yml" - - extra_arguments = [ - "--extra-vars", "ansible_user=ubuntu" - ] - - ansible_env_vars = [ - "ANSIBLE_HOST_KEY_CHECKING=False", - "ANSIBLE_SCP_IF_SSH=True" - ] - - use_proxy = false - } -} diff --git a/build/openstack-bioshell.pkr.hcl b/build/openstack-bioshell.pkr.hcl index 0bf1526..6c8d6b1 100644 --- a/build/openstack-bioshell.pkr.hcl +++ b/build/openstack-bioshell.pkr.hcl @@ -2,7 +2,7 @@ packer { required_plugins { openstack = { version = ">= 1.1.2" - source = "github.com/hashicorp/openstack" + source = "github.com/hashicorp/openstack" } ansible = { @@ -12,31 +12,69 @@ packer { } } +variable "flavor" { + type = string +} + +variable "source_image" { + type = string +} + +variable "networks" { + type = list(string) + default = null +} + +variable "availability_zone" { + type = string + default = null +} + +variable "volume_size" { + type = number + default = 20 +} + +variable "platform" { + type = string +} + source "openstack" "ubuntu" { - image_name = "bioshell" - flavor = "" # update via: openstack flavor list - networks = [""] # update via: openstack network list - availability_zone = "" # update via: openstack availability zone list - source_image = "" # update via: openstack image list - ssh_username = "ubuntu" - volume_size = 20 + image_name = "bioshell" + flavor = var.flavor + source_image = var.source_image + ssh_username = "ubuntu" + volume_size = var.volume_size + networks = var.networks != null ? var.networks : null + availability_zone = var.availability_zone != null ? var.availability_zone : null } build { sources = ["source.openstack.ubuntu"] -provisioner "ansible" { - playbook_file = "./build-bioshell.yml" - - extra_arguments = [ - "--extra-vars", "ansible_user=ubuntu" - ] - - ansible_env_vars = [ - "ANSIBLE_HOST_KEY_CHECKING=False", - "ANSIBLE_SCP_IF_SSH=True" - ] - - use_proxy = false - } -} + # 1. Install everything + provisioner "ansible" { + playbook_file = "ansible/build-bioshell.yml" + extra_arguments = [ + "--extra-vars", "ansible_user=ubuntu platform=${var.platform}" + ] + ansible_env_vars = [ + "ANSIBLE_HOST_KEY_CHECKING=False", + "ANSIBLE_SCP_IF_SSH=True" + ] + use_proxy = false + } + + # 2. Validate — runs after install, before image is saved + provisioner "ansible" { + playbook_file = "ansible/test-bioshell.yml" + extra_arguments = [ + "--extra-vars", "ansible_user=ubuntu platform=${var.platform}" + ] + ansible_env_vars = [ + "ANSIBLE_HOST_KEY_CHECKING=False", + "ANSIBLE_SCP_IF_SSH=True" + ] + use_proxy = false + } +} \ No newline at end of file diff --git a/build/packer-vars/nectar.pkrvars.hcl b/build/packer-vars/nectar.pkrvars.hcl new file mode 100644 index 0000000..7ec2ccb --- /dev/null +++ b/build/packer-vars/nectar.pkrvars.hcl @@ -0,0 +1,3 @@ +flavor = "r3.small" +source_image = "c0250c96-98a4-4bfa-b67c-51874808337f" +platform = "nectar" \ No newline at end of file diff --git a/build/packer-vars/nirin.pkrvars.hcl b/build/packer-vars/nirin.pkrvars.hcl new file mode 100644 index 0000000..5daca6a --- /dev/null +++ b/build/packer-vars/nirin.pkrvars.hcl @@ -0,0 +1,5 @@ +flavor = "c3ep.2c4m20d" +source_image = "567d81cb-ff4c-42be-b11a-7f3ec884b211" +networks = [""] # update via: openstack network list - select network associated with your project +availability_zone = "CloudV3" +platform = "nirin" \ No newline at end of file diff --git a/build/scripts/nectar.sh b/build/scripts/nectar.sh new file mode 100755 index 0000000..1567fc1 --- /dev/null +++ b/build/scripts/nectar.sh @@ -0,0 +1,3 @@ +packer build \ + -var-file="./packer-vars/nectar.pkrvars.hcl" \ + ./openstack-bioshell.pkr.hcl \ No newline at end of file diff --git a/build/scripts/nirin.sh b/build/scripts/nirin.sh new file mode 100755 index 0000000..2c5b150 --- /dev/null +++ b/build/scripts/nirin.sh @@ -0,0 +1,3 @@ +packer build \ + -var-file="./packer-vars/nirin.pkrvars.hcl" \ + ./openstack-bioshell.pkr.hcl