Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customised docker image for running calculation out-of-box #981

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
26 changes: 26 additions & 0 deletions .docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#FROM ghcr.io/aiidateam/aiida-core-with-services:edge
FROM ghcr.io/aiidateam/aiida-core-with-services:pr-6170
unkcpz marked this conversation as resolved.
Show resolved Hide resolved

USER root

ARG QE_VERSION
ENV QE_VERSION ${QE_VERSION}

# Install aiida-quantumespresso from source code
COPY --from=src . /tmp/aiida-quantumespresso
RUN pip install /tmp/aiida-quantumespresso --no-cache-dir && \
rm -rf /tmp/aiida-quantumespresso

# Install quantum espresso from conda (the latest version)
RUN mamba install -y -c conda-forge qe=${QE_VERSION} && \
mamba clean --all -f -y && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${SYSTEM_USER}"

COPY scripts/60-pseudo-code-setup.sh /etc/init/run-before-daemon-start/

# Static example files
RUN mkdir -p /opt/examples
COPY _static/ /opt/examples

USER ${SYSTEM_UID}
28 changes: 28 additions & 0 deletions .docker/_static/Si.cif
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# generated using pymatgen
data_Si
_symmetry_space_group_name_H-M 'P 1'
_cell_length_a 3.86697465
_cell_length_b 3.86697465
_cell_length_c 3.86697465
_cell_angle_alpha 60.00000000
_cell_angle_beta 60.00000000
_cell_angle_gamma 60.00000000
_symmetry_Int_Tables_number 1
_chemical_formula_structural Si
_chemical_formula_sum Si2
_cell_volume 40.88829285
_cell_formula_units_Z 2
loop_
_symmetry_equiv_pos_site_id
_symmetry_equiv_pos_as_xyz
1 'x, y, z'
loop_
_atom_site_type_symbol
_atom_site_label
_atom_site_symmetry_multiplicity
_atom_site_fract_x
_atom_site_fract_y
_atom_site_fract_z
_atom_site_occupancy
Si Si0 1 0.75000000 0.75000000 0.75000000 1
Si Si1 1 0.50000000 0.50000000 0.50000000 1
38 changes: 38 additions & 0 deletions .docker/docker-bake.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# docker-bake.hcl
variable "ORGANIZATION" {
default = "aiidateam"
}

variable "REGISTRY" {
default = "docker.io/"
}

variable "PLATFORMS" {
default = ["linux/amd64"]
}

variable "QE_VERSION" {
default = "7.2"
}

function "tags" {
params = [image]
result = [
"${REGISTRY}${ORGANIZATION}/${image}:newly-baked"
]
}

group "default" {
targets = ["aiida-quantumespresso"]
}

target "aiida-quantumespresso" {
tags = tags("aiida-quantumespresso")
contexts = {
src = ".."
}
platforms = "${PLATFORMS}"
args = {
"QE_VERSION" = "${QE_VERSION}"
}
}
15 changes: 15 additions & 0 deletions .docker/docker-compose.aiida-quantumespresso.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
version: '3.4'

services:

aiida:
image: ${REGISTRY:-}${BASE_IMAGE:-aiidateam/aiida-quantumespresso}:${TAG:-latest}
environment:
TZ: Europe/Zurich
SETUP_DEFAULT_AIIDA_PROFILE: 'true'
#volumes:
# - aiida-home-folder:/home/aiida

volumes:
aiida-home-folder:
8 changes: 8 additions & 0 deletions .docker/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
docker
pre-commit
pytest
requests
tabulate
pytest-docker
docker-compose
pyyaml<=5.3.1
31 changes: 31 additions & 0 deletions .docker/scripts/60-pseudo-code-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash

# If lock file exists, then we have already run this script
if [ -f ${HOME}/.lock_pseudo_code_setup ]; then
exit 0
else
touch ${HOME}/.lock_pseudo_code_setup
fi

# Install pseudopotential libraries
aiida-pseudo install sssp --functional PBE -p efficiency
aiida-pseudo install sssp --functional PBE -p precision
aiida-pseudo install sssp --functional PBEsol -p efficiency
aiida-pseudo install sssp --functional PBEsol -p precision

# Loop over executables to set up
for code_name in pw ph; do
# Set up caching
verdi config set -a caching.enabled_for aiida.calculations:quantumespresso.${code_name}
# Set up code
verdi code create core.code.installed \
--non-interactive \
--label ${code_name}-${QE_VERSION} \
--description "${code_name}.x code on localhost" \
--default-calc-job-plugin quantumespresso.${code_name} \
--computer localhost --prepend-text 'eval "$(conda shell.posix hook)"\nconda activate base\nexport OMP_NUM_THREADS=1' \
--filepath-executable ${code_name}.x
done

# Import example structures
verdi data core.structure import ase /opt/examples/Si.cif
60 changes: 60 additions & 0 deletions .docker/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# pylint: disable=missing-docstring, redefined-outer-name
import json
import re

import pytest


@pytest.fixture(scope='session')
def docker_compose_file(pytestconfig): # pylint: disable=unused-argument
return f'docker-compose.aiida-quantumespresso.yml'


@pytest.fixture(scope='session')
def docker_compose(docker_services):
# pylint: disable=protected-access
return docker_services._docker_compose


def is_container_ready(dodkec_compose):
output = dodkec_compose.execute('exec -T aiida verdi status').decode().strip()
unkcpz marked this conversation as resolved.
Show resolved Hide resolved
return 'Connected to RabbitMQ' in output and 'Daemon is running' in output


@pytest.fixture(scope='session', autouse=True)
def _docker_service_wait(docker_services):
"""Container startup wait."""
docker_compose = docker_services._docker_compose

docker_services.wait_until_responsive(timeout=120.0, pause=0.1, check=lambda: is_container_ready(docker_compose))


@pytest.fixture
def container_user():
return 'aiida'


@pytest.fixture
def aiida_exec(docker_compose):

def execute(command, user=None, **kwargs):
if user:
command = f'exec -T --user={user} aiida {command}'
else:
command = f'exec -T aiida {command}'
return docker_compose.execute(command, **kwargs)

return execute


@pytest.fixture
def qe_version(aiida_exec):
info = json.loads(aiida_exec('mamba list -n base --json --full-name qe').decode())[0]
return info['version']


@pytest.fixture
def sssp_version(aiida_exec):
output = aiida_exec('aiida-pseudo list').decode().strip()
return re.search(r'SSSP/(\d+\.\d+)/PBE/efficiency', output).group(1)
33 changes: 33 additions & 0 deletions .docker/tests/test_aiida.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# pylint: disable=missing-docstring


def test_verdi_status(aiida_exec, container_user):
output = aiida_exec('verdi status', user=container_user).decode().strip()
assert 'Connected to RabbitMQ' in output
assert 'Daemon is running' in output

# check that we have suppressed the warnings
assert 'Warning' not in output


def test_computer_setup_success(aiida_exec, container_user):
output = aiida_exec('verdi computer test localhost', user=container_user).decode().strip()

assert 'Success' in output
assert 'Failed' not in output


def test_run_real_pw_computation(aiida_exec, container_user, qe_version, sssp_version):
import re

output = aiida_exec('verdi data core.structure import ase /opt/examples/Si.cif',
user=container_user).decode().strip()

# Find pk
pk = re.search(r'PK = (\d+)', output).group(1)

cmd = f'aiida-quantumespresso calculation launch pw -X pw-{qe_version}@localhost -F SSSP/{sssp_version}/PBE/efficiency -S {pk} -k 1 1 1'
output = aiida_exec(cmd, user=container_user).decode().strip()

assert 'terminated with state: finished [0]' in output
81 changes: 81 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
name: Build, test and push Docker Images

on:
pull_request:
paths-ignore:
- "docs/**"
- "tests/**"
push:
branches:
- main
tags:
- "v*"
paths-ignore:
- "docs/**"
- "tests/**"
workflow_dispatch:

# https://docs.github.com/en/actions/using-jobs/using-concurrency
concurrency:
# only cancel in-progress jobs or runs for the current workflow - matches against branch & tags
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
amd64-build:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: .docker

steps:
- name: Checkout Repo ⚡️
uses: actions/checkout@v3
- name: Set Up Python 🐍
uses: actions/setup-python@v4
with:
python-version: 3.x

- name: Install Dev Dependencies 📦
run: |
pip install --upgrade pip
pip install --upgrade -r requirements.txt

- name: Build image
run: docker buildx bake -f docker-bake.hcl --set *.platform=linux/amd64 --load
env:
# Full logs for CI build
BUILDKIT_PROGRESS: plain

- name: Run tests ✅
run: TAG=newly-baked python -m pytest -s tests

- name: Docker meta 📝
id: meta
uses: docker/metadata-action@v4
with:
images: |
name=ghcr.io/aiidateam/aiida-quantumespresso
tags: |
type=edge,enable={{is_default_branch}}
type=sha,enable=${{ github.ref_type != 'tag' }}
type=ref,event=pr
type=match,pattern=v(\d+\.\d+.\d+),group=1
type=raw,value={{tag}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}

- name: Login to Container Registry 🔑
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set tags for image and push 🏷️📤💾
run: |
declare -a arr=(${{ steps.meta.outputs.tags }})
for tag in "${arr[@]}"; do
docker tag aiidateam/aiida-quantumespresso:newly-baked ${tag}
docker push ${tag}
done
Loading