Skip to content

Commit e08eb71

Browse files
committed
Release 1.4.0
1 parent a6b1617 commit e08eb71

File tree

19 files changed

+71
-50
lines changed

19 files changed

+71
-50
lines changed

.github/workflows/build-multi-pex.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
runs-on: ubuntu-latest
4040
strategy:
4141
matrix:
42-
python-version: ["3.9", "3.10", "3.11"]
42+
python-version: ["3.9", "3.10", "3.11", "3.13"]
4343

4444
steps:
4545

@@ -83,6 +83,7 @@ jobs:
8383
tar axvf elastic-blast-3.9/elastic-blast3.9.tar.gz
8484
tar axvf elastic-blast-3.10/elastic-blast3.10.tar.gz
8585
tar axvf elastic-blast-3.11/elastic-blast3.11.tar.gz
86+
tar axvf elastic-blast-3.13/elastic-blast3.13.tar.gz
8687
rm -fvr elastic-blast-*.tar.gz
8788
tar -czvf ~/elastic-blast.tar.gz elastic-blast elastic-blast*md5 elastic-blast3.*
8889
- name: 'Upload Artifact'

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
cff-version: "1.2.0"
22
message: "If you use this software, please cite it using these metadata."
33
title: ElasticBLAST
4-
version: "1.3.1"
5-
date-released: 2024-07-24
4+
version: "1.4.0"
5+
date-released: 2025-03-17
66
license: "NCBI Public Domain"
77
repository-code: "https://github.com/ncbi/elastic-blast/"
88
url: "https://blast.ncbi.nlm.nih.gov/doc/elastic-blast/"

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ elastic-blast: ${PYTHON_SRC} ${YAML_TEMPLATES} ${VENV} validate-cf-templates
4141
source ${VENV}/bin/activate && pex --python-shebang='/usr/bin/env python3' --disable-cache . -r requirements/base.txt --python=python${PYTHON_VERSION} -c $@ -o $@
4242
-./$@ --version
4343

44+
elastic-blast3.13: ${PYTHON_SRC} ${YAML_TEMPLATES} ${VENV} validate-cf-templates
45+
source ${VENV}/bin/activate && pex --disable-cache . -r requirements/base.txt --python=python3.13 -c elastic-blast -o $@
46+
-./$@ --version
47+
48+
elastic-blast3.11: ${PYTHON_SRC} ${YAML_TEMPLATES} ${VENV} validate-cf-templates
49+
source ${VENV}/bin/activate && pex --disable-cache . -r requirements/base.txt --python=python3.11 -c elastic-blast -o $@
50+
-./$@ --version
51+
4452
elastic-blast3.9: ${PYTHON_SRC} ${YAML_TEMPLATES} ${VENV} validate-cf-templates
4553
source ${VENV}/bin/activate && pex --disable-cache . -r requirements/base.txt --python=python3.9 -c elastic-blast -o $@
4654
-./$@ --version

docker-blast/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626

2727
SHELL=/bin/bash
2828
IMG?=ncbi/elb
29-
GCP_IMG?=gcr.io/ncbi-sandbox-blast/${IMG}
29+
GCP_PROJECT?=$(shell gcloud config get-value project 2>/dev/null)
30+
GCP_IMG?=gcr.io/${GCP_PROJECT}/${IMG}
3031
AWS_SERVER?=public.ecr.aws/i6v3i0i9
3132
AWS_IMG?=${AWS_SERVER}/elasticblast-elb
3233
AWS_REGION?=us-east-1

docker-janitor/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ SHELL=/bin/bash
2727
.PHONY: all pre-check check clean build publish gcp-build gcp-check gcp-clean
2828

2929
IMG?=ncbi/elasticblast-janitor
30-
VERSION?=0.3.2
30+
VERSION?=0.4.0
3131
ELB_VERSION?=$(shell git describe --tags --abbrev=0)
3232
GCP_PROJECT?=$(shell gcloud config get-value project 2>/dev/null)
3333
GCP_TEST_BUCKET?=gs://elasticblast-test/query-split-run-test

docker-job-submit/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
templates/
2+
src/
3+
bin/
4+
requirements/
5+
setup.cfg_cloud
6+
setup.py

docker-job-submit/Dockerfile-build-from-local-sources.aws

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ COPY submit_jobs.py /usr/bin/
3030

3131
RUN chmod +x /usr/bin/submit_jobs.py && \
3232
apk -U upgrade && \
33-
apk add --no-cache bash python3 py3-pip py3-wheel && \
34-
pip3 install --no-cache-dir --upgrade --break-system-packages pip && \
33+
apk add --no-cache bash python3 py3-pip py3-wheel curl unzip && \
34+
pip3 install --no-cache-dir --upgrade pip && \
3535
mkdir -p /var/elastic-blast && \
3636
rm -rf /var/cache/apk/*
3737

@@ -43,6 +43,8 @@ COPY setup.cfg_cloud /var/elastic-blast/setup.cfg
4343

4444
WORKDIR /var/elastic-blast
4545

46-
RUN pip3 install . -r requirements/base.txt --break-system-packages
46+
RUN python3 -m venv /var/elastic-blast/.venv && \
47+
source /var/elastic-blast/.venv && \
48+
pip3 install . -r requirements/base.txt --no-cache-dir
4749

4850
CMD ["/usr/bin/submit_jobs.py", "--help"]

docker-job-submit/Dockerfile.aws

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ COPY submit_jobs.py /usr/bin/
2727
RUN chmod +x /usr/bin/submit_jobs.py && \
2828
apk -U upgrade && \
2929
apk add --no-cache bash python3 py3-pip py3-wheel curl unzip && \
30-
pip3 install --no-cache-dir --upgrade --break-system-packages pip && \
31-
pip3 install --no-cache-dir -r requirements.txt --break-system-packages && rm -rf /var/cache/apk/* requirements.txt
30+
pip3 install --no-cache-dir --upgrade pip && \
31+
python3 -m venv /.venv && source /.venv/bin/activate && \
32+
pip3 install --no-cache-dir -r requirements.txt && rm -rf /var/cache/apk/* requirements.txt
3233

3334
LABEL Description="NCBI ElasticBLAST Cloud Job Submission Module"
3435
LABEL Version=${version}

docker-job-submit/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ SHELL=/bin/bash
2828
.PHONY: all pre-check check clean build publish gcp-build gcp-check gcp-clean
2929

3030
IMG?=ncbi/elasticblast-job-submit
31-
VERSION?=4.0.3
31+
VERSION?=4.1.0
3232
ELB_VERSION?=$(shell git describe --tags --abbrev=0)
3333
GCP_PROJECT?=$(shell gcloud config get-value project 2>/dev/null)
3434
GCP_TEST_BUCKET?=gs://elasticblast-test/cloud-job-submission
@@ -64,6 +64,7 @@ check:
6464
gcp-build:
6565
rsync -a ../src/elastic_blast/templates ${PWD}/
6666
gcloud builds submit --config cloudbuild.yaml --substitutions _VERSION=${VERSION},_IMG=${IMG}
67+
rm -fr templates
6768

6869
.PHONY: aws-build
6970
aws-build:

docker-job-submit/cloud-job-submit.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ while true; do
7373
sleep 30
7474
done
7575

76-
s=`${KUBECTL} get jobs -l app=setup -o jsonpath='{.items[*].status.conditions[*].type}'`
76+
s=`${KUBECTL} get jobs -l app=setup -o jsonpath="{.items[*].status.conditions[?(@.type=='Complete')].type}"`
7777
if [[ "$s" != Complete*( Complete) ]]; then
78-
echo "Setup job(s) failed:" `${KUBECTL} get jobs -l app=setup -o jsonpath='{.items[?(@.status.failed)].metadata.name}'`
78+
echo "Setup job(s) failed:" `${KUBECTL} get jobs -l app=setup -o json`
7979
copy_job_logs_to_results_bucket setup "${K8S_JOB_GET_BLASTDB}"
8080
copy_job_logs_to_results_bucket setup "${K8S_JOB_IMPORT_QUERY_BATCHES}"
8181
exit 1

docker-qs/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ various repositories.
1111
If you have `docker` available, run `make build` to build the image, and `make
1212
check` to test it locally.
1313

14-
You will need credentials for NCBI-AWS-ELASTICBLAST-OPERATIONS to push to AWS ECR, see *To get NCBI AWS credentials in NCBI-AWS-ELASTICBLAST-OPERATIONS* in [README-ncbi.md](../README-ncbi.md).

requirements/base.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
wheel==0.43.0
2-
setuptools==70.0.0
1+
wheel==0.41.2
2+
setuptools==68.2.0
33
importlib-resources==6.1.1
44
importlib-metadata==7.0.0
5-
pex==2.9.0
6-
boto3==1.34.141
7-
botocore==1.34.141
5+
pex==2.33.4
6+
boto3==1.37.12
7+
botocore==1.37.12
88
awslimitchecker==12.0.0
9-
tenacity==8.5.0
9+
tenacity==9.0.0
1010
dataclasses-json==0.6.7

requirements/test.txt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
-r base.txt
22

3-
pytest==8.2.2
4-
pytest-cov==5.0.0
3+
pytest==8.3.5
4+
pytest-cov==6.0.0
55
pytest-mock==3.14.0
6-
teamcity-messages==1.32
7-
mypy==1.10.1
8-
pylint==2.7.4
6+
teamcity-messages==1.33
7+
mypy==1.15.0
8+
pylint==3.3.5
99
tox==4.4.12
10-
virtualenv==20.24.5
11-
yamllint==1.35.1
10+
yamllint==1.36.0
1211
moto==4.2.14
1312
docker==7.1.0
14-
cfn-lint==1.5.1
13+
cfn-lint==1.30.0

src/elastic_blast/base.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import re
3030
from dataclasses import dataclass, field, Field, fields, _MISSING_TYPE
3131
from enum import Enum, auto
32-
from typing import Dict, List, Union, Optional, NamedTuple
32+
from typing import Dict, List, Union, Optional, NamedTuple, get_origin, get_args
3333

3434
@dataclass(frozen=True)
3535
class InstanceProperties:
@@ -317,10 +317,8 @@ def get_non_union_type(field: Field):
317317
If fieds.type is a Union, then the first type that is not None,
318318
otherwise field.type"""
319319
ftype = field.type
320-
# FIXME: in python3.8 this can be done via typing.get_origin()
321-
if getattr(ftype, '__origin__', None) is not None and \
322-
ftype.__origin__ == Union:
323-
ftype = [t for t in ftype.__args__ if t != type(None)][0]
320+
if get_origin(ftype) is not None and get_origin(ftype) == Union:
321+
ftype = [t for t in get_args(ftype) if t != type(None)][0]
324322
return ftype
325323

326324

src/elastic_blast/constants.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class ElbExecutionMode(Enum):
156156
ELB_LOCAL_SSD_BLAST_JOB_TEMPLATE = 'resource:templates/blast-batch-job-local-ssd.yaml.template'
157157
GCS_DFLT_BUCKET = 'gs://blast-db'
158158

159-
GCP_APIS = ['compute', 'serviceusage', 'container', 'storage-api', 'storage-component']
159+
GCP_APIS = ['compute', 'serviceusage', 'artifactregistry', 'container', 'storage-api', 'storage-component']
160160
# https://cloud.google.com/kubernetes-engine/docs/how-to/creating-managing-labels#requirements
161161
GCP_MAX_NUM_LABELS = 64
162162
# https://cloud.google.com/kubernetes-engine/docs/how-to/creating-managing-labels#requirements
@@ -212,8 +212,8 @@ def __str__(self):
212212

213213
ELB_DOCKER_VERSION = '1.3.2' # ElasticBLAST 1.3.0 uses BLAST+ 2.16.0
214214
ELB_QS_DOCKER_VERSION = '0.1.4'
215-
ELB_JANITOR_DOCKER_VERSION = '0.3.2'
216-
ELB_JOB_SUBMIT_DOCKER_VERSION = '4.0.3'
215+
ELB_JANITOR_DOCKER_VERSION = '0.4.0'
216+
ELB_JOB_SUBMIT_DOCKER_VERSION = '4.1.0'
217217

218218
ELB_DOCKER_IMAGE_GCP = f'gcr.io/ncbi-sandbox-blast/ncbi/elb:{ELB_DOCKER_VERSION}'
219219
ELB_DOCKER_IMAGE_AWS = f'public.ecr.aws/ncbi-elasticblast/elasticblast-elb:{ELB_DOCKER_VERSION}'

src/elastic_blast/gcp.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,19 +245,17 @@ def _check_status(self, extended=False) -> Tuple[ElbStatus, Dict[str, int], Dict
245245
selector = 'app=blast'
246246
kubectl = f'kubectl --context={k8s_ctx}'
247247

248-
# if we need name of the job in the future add NAME:.metadata.name to custom-columns
249-
# get status of jobs (pending/running, succeeded, failed)
250-
cmd = f'{kubectl} get jobs -o custom-columns=STATUS:.status.conditions[0].type -l {selector}'.split()
248+
cmd = f'{kubectl} get jobs -l {selector} -o custom-columns=STATUS:.status.conditions[*].type'.split()
251249
if self.dry_run:
252250
logging.debug(cmd)
253251
else:
254252
proc = safe_exec(cmd)
255253
for line in proc.stdout.decode().split('\n'):
256254
if not line or line.startswith('STATUS'):
257255
continue
258-
if line.startswith('Complete'):
256+
if 'Complete' in line:
259257
counts['succeeded'] += 1
260-
elif line.startswith('Failed'):
258+
elif 'Failed' in line:
261259
counts['failed'] += 1
262260
else:
263261
counts['pending'] += 1
@@ -303,7 +301,8 @@ def _job_status_by_app(self, app):
303301
selector = f'app={app}'
304302
k8s_ctx = self._get_gke_credentials()
305303
kubectl = f'kubectl --context={k8s_ctx}'
306-
cmd = f'{kubectl} get jobs -o custom-columns=STATUS:.status.conditions[0].type -l {selector}'.split()
304+
cmd = f'{kubectl} get jobs -l {selector} -o custom-columns=STATUS:.status.conditions[*].type'
305+
cmd = cmd.split()
307306
if self.dry_run:
308307
logging.debug(cmd)
309308
else:
@@ -315,9 +314,9 @@ def _job_status_by_app(self, app):
315314
for line in proc.stdout.decode().split('\n'):
316315
if not line or line.startswith('STATUS'):
317316
continue
318-
if line.startswith('Complete'):
317+
if 'Complete' in line:
319318
succeeded += 1
320-
elif line.startswith('Failed'):
319+
elif 'Failed' in line:
321320
failed += 1
322321
else:
323322
pending += 1

src/elastic_blast/kubernetes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,10 @@ def _job_succeeded(k8s_ctx: str, k8s_job_file: pathlib.Path, dry_run: bool = Fal
344344

345345
final_status = ''
346346
if 'conditions' in json_output['status'] and len(json_output['status']['conditions']) > 0:
347-
final_status = json_output['status']['conditions'][0]['type']
347+
final_status = 'Failed' # assume failure
348+
for condition in json_output['status']['conditions']:
349+
if 'type' in condition and condition['type'] in ('Complete', 'Failed'):
350+
final_status = condition['type']
348351

349352
if final_status == 'Complete' and 'succeeded' in json_output['status']:
350353
retval = json_output['status']['succeeded']

src/elastic_blast/util.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from .constants import DEPENDENCY_ERROR, AWS_MAX_TAG_LENGTH, GCP_MAX_LABEL_LENGTH
4242
from .constants import AWS_MAX_JOBNAME_LENGTH, CSP, ELB_GCS_PREFIX
4343
from .constants import ELB_DFLT_LOGLEVEL, ELB_DFLT_LOGFILE
44-
from .constants import INPUT_ERROR
44+
from .constants import INPUT_ERROR, UNKNOWN_ERROR
4545
from .constants import ELB_S3_PREFIX
4646
from .base import DBSource
4747

@@ -244,11 +244,14 @@ def safe_exec(cmd: Union[List[str], str], env: Optional[Dict[str, str]] = None)
244244
msg = f'The command "{" ".join(e.cmd)}" returned with exit code {e.returncode}\n{e.stderr.decode()}\n{e.stdout.decode()}'
245245
if e.output is not None:
246246
'\n'.join([msg, f'{e.output.decode()}'])
247-
raise SafeExecError(e.returncode, msg)
247+
error_code = UNKNOWN_ERROR if e.returncode is None else e.returncode
248+
raise SafeExecError(error_code, msg)
248249
except PermissionError as e:
249-
raise SafeExecError(e.errno, str(e))
250+
error_code = UNKNOWN_ERROR if e.errno is None else e.errno
251+
raise SafeExecError(error_code, str(e))
250252
except FileNotFoundError as e:
251-
raise SafeExecError(e.errno, e.strerror)
253+
error_code = UNKNOWN_ERROR if e.errno is None else e.errno
254+
raise SafeExecError(error_code, str(e))
252255
return p
253256

254257

tests/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ def mocked_safe_exec(cmd: Union[List[str], str], env: Optional[Dict[str, str]] =
366366
elif cmd[0] == 'kubectl' and 'get pods -o custom-columns=STATUS' in ' '.join(cmd):
367367
return MockedCompletedProcess('\n'.join(['STATUS'] + ['Running' for i in K8S_JOB_STATUS if i == 'Running']))
368368

369-
elif cmd[0] == 'kubectl' and 'get jobs -o custom-columns=STATUS' in ' '.join(cmd):
369+
elif cmd[0] == 'kubectl' and 'get jobs' in ' '.join(cmd):
370370
switcher = {'Failed': 'Failed',
371371
'Succeeded': 'Complete',
372372
'Running': '<none>',

0 commit comments

Comments
 (0)