Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.demo.bodc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ FILECHECKER_IMAGE_TAG=develop
#availables tags at https://github.com/OneArgo/ArgoFormatChecker/tags + develop + latest

# External directories to mount to the container
FILECHECKER_SPEC_VOLUME=./file_checker_spec
FILECHECKER_INPUT_VOLUME=./demo/inputs/3901945
FILECHECKER_OUTPUT_VOLUME=./demo/outputs/3901945

Expand Down
1 change: 0 additions & 1 deletion .env.demo.coriolis
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ FILECHECKER_IMAGE_TAG=develop
#availables tags at https://github.com/OneArgo/ArgoFormatChecker/tags + develop + latest

# External directories to mount to the container
FILECHECKER_SPEC_VOLUME=./file_checker_spec
FILECHECKER_INPUT_VOLUME=./demo/inputs/2903996
FILECHECKER_OUTPUT_VOLUME=./demo/outputs/2903996

Expand Down
1 change: 0 additions & 1 deletion .env.docs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ FILECHECKER_IMAGE_TAG=develop
#availables tags at https://github.com/OneArgo/ArgoFormatChecker/tags + develop + latest

# External directories to mount to the container
FILECHECKER_SPEC_VOLUME=<path to the file_checker_spec directory>
FILECHECKER_INPUT_VOLUME=<path to input directory>
FILECHECKER_OUTPUT_VOLUME=<path to output directory>

Expand Down
41 changes: 38 additions & 3 deletions .github/workflows/component-container-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ on:
description: "Path of the docker image Tag"
default: "ghcr.io/${{ github.repository }}/app"
type: string
target:
description: "Target build stage for Docker multistage build"
required: false
type: string
file:
description: "Path to the Dockerfile."
required: false
type: string

jobs:
container-image-build:
Expand All @@ -35,11 +43,20 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build (pull request)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'pull_request'}}
if: ${{ github.event_name == 'pull_request' && (inputs.target == '' || inputs.target == null) }}
with:
context: "{{defaultContext}}:${{ inputs.context }}"
tags: "${{ steps.format.outputs.lowercase }}:develop"
push: false
- name: Build with target (pull request)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'pull_request' && inputs.target != '' && inputs.target != null }}
with:
context: "{{defaultContext}}:${{ inputs.context }}"
target: ${{ inputs.target }}
file: ${{ inputs.file }}
tags: "${{ steps.format.outputs.lowercase }}:develop"
push: false
- name: Build and push (develop)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
Expand All @@ -49,15 +66,33 @@ jobs:
push: true
- name: Build and push (main)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && (inputs.target == '' || inputs.target == null) }}
with:
context: "{{defaultContext}}:${{ inputs.context }}"
tags: "${{ steps.format.outputs.lowercase }}:latest"
push: true
- name: Build and push with target (main)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && inputs.target != '' && inputs.target != null }}
with:
context: "{{defaultContext}}:${{ inputs.context }}"
target: ${{ inputs.target }}
file: ${{ inputs.file }}
tags: "${{ steps.format.outputs.lowercase }}:latest"
push: true
- name: Build and push (release)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'release' }}
if: ${{ github.event_name == 'release' && (inputs.target == '' || inputs.target == null) }}
with:
context: "{{defaultContext}}:${{ inputs.context }}"
tags: "${{ steps.format.outputs.lowercase }}:${{ github.ref_name }}"
push: true
- name: Build and push with target (release)
uses: docker/build-push-action@v6
if: ${{ github.event_name == 'release' && inputs.target != '' && inputs.target != null }}
with:
context: "{{defaultContext}}:${{ inputs.context }}"
target: ${{ inputs.target }}
file: ${{ inputs.file }}
tags: "${{ steps.format.outputs.lowercase }}:${{ github.ref_name }}"
push: true
6 changes: 5 additions & 1 deletion .github/workflows/workflow-java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ on:
- develop
paths:
- file_checker_exec/**
- file_checker_spec/**
- Dockerfile
pull_request:
# Run for any pull requests
paths:
- file_checker_exec/**
- file_checker_spec/**
- Dockerfile
release:
types: [created]

Expand All @@ -20,5 +24,5 @@ jobs:
container-image-build:
uses: ./.github/workflows/component-container-image.yml
with:
context: file_checker_exec
context: .
image-path: ghcr.io/OneArgo/ArgoFormatChecker/app
33 changes: 33 additions & 0 deletions .github/workflows/workflow-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Image build

on:
push:
branches:
# Run on our main branch
- main
- develop
paths:
- file_checker_python/**
pull_request:
# Run for any pull requests
paths:
- file_checker_python/**
release:
types: [created]


jobs:
container-image-build-wrapper:
uses: ./.github/workflows/component-container-image.yml
with:
context: .
file: "python.Dockerfile"
target: file-checker-python
image-path: ghcr.io/OneArgo/ArgoFormatChecker/python-wrapper
container-image-build-api:
uses: ./.github/workflows/component-container-image.yml
with:
context: .
file: "python.Dockerfile"
target: file-checker-api
image-path: ghcr.io/OneArgo/ArgoFormatChecker/python-api
2 changes: 0 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
include:
- component: $CI_SERVER_FQDN/dev-ops/templates/automatisation/ci-cd/pipeline-java-container-image@~latest
inputs:
container_image_build_context: "./file_checker_exec"
container_image_docker_file_path: "./file_checker_exec/Dockerfile"
java_builder_artifacts_path: "**/target/*.{war,jar}"
java_builder_build_command: "clean package -f file_checker_exec/pom.xml"
java_builder_maven_quality_enable: "false"
Expand Down
12 changes: 8 additions & 4 deletions file_checker_exec/Dockerfile → Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ LABEL org.opencontainers.image.vendor="OneArgo"

WORKDIR /build

COPY ./.mvn ./.mvn
COPY ./mvnw ./mvnw
COPY ./pom.xml ./pom.xml
COPY ./src ./src
COPY ./file_checker_exec/.mvn ./.mvn
COPY ./file_checker_exec/mvnw ./mvnw
COPY ./file_checker_exec/pom.xml ./pom.xml
COPY ./file_checker_exec/src ./src


# Ensure mvnw has execution permissions
RUN chmod +x ./mvnw \
Expand All @@ -36,6 +37,9 @@ RUN set -e \

# Copy the built jar file to the runtime stage
COPY --from=builder --chown=root:gcontainer --chmod=750 /build/target/file_checker*.jar app.jar
# Copy the specs :
COPY file_checker_spec /app/file_checker_spec

# Specify the default command for running the app
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

Expand Down
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ $FILES_NAMES is a list of file's name from the INPUT_DIR. It is optional : witho

### Run the application using Docker

```bash
docker run --rm -v [ABSOLUTE_PATH_TO_DATA_FOLDER]:/app/data -v [ABSOLUTE_PATH_TO_OUTPUT_DIR]:/app/results ghcr.io/oneargo/argoformatchecker/app:{TAG} [$OPTIONS] $DAC_NAME ./file_checker_spec ./results ./data [$FILES_NAMES]
```

Or if you want to use your own specification files :

```bash
docker run --rm -v [ABSOLUTE_PATH_TO_SPEC]:/app/file_checker_spec -v [ABSOLUTE_PATH_TO_DATA_FOLDER]:/app/data -v [ABSOLUTE_PATH_TO_OUTPUT_DIR]:/app/results ghcr.io/oneargo/argoformatchecker/app:{TAG} [$OPTIONS] $DAC_NAME ./file_checker_spec ./results ./data [$FILES_NAMES]
```

You need to mount external directories to the container :

[ABSOLUTE_PATH_TO_SPEC] : the file_checker_spec directory path.
[ABSOLUTE_PATH_TO_SPEC] : OPTIONAL - The file_checker_spec directory path (if you don't want to use the specs included in the docker container).

[ABSOLUTE_PATH_TO_DATA_FOLDER] : Path to directory containing the argo necdf files to be checked. The fileChecker will not seek files in subfolders

Expand All @@ -43,7 +49,7 @@ You need to mount external directories to the container :
Example :

```bash
docker run --rm -v D:\test_file_checker\file_checker_spec:/app/file_checker_spec -v D:\test_file_checker\datatest:/app/data -v D:\test_file_checker\results:/app/results ghcr.io/oneargo/argoformatchecker/app:develop -no-name-check coriolis ./file_checker_spec ./results ./data
docker run --rm -v D:\test_file_checker\datatest:/app/data -v D:\test_file_checker\results:/app/results ghcr.io/oneargo/argoformatchecker/app:develop -no-name-check coriolis ./file_checker_spec ./results ./data
```

### Run the application using Docker Compose
Expand Down Expand Up @@ -73,7 +79,6 @@ FILECHECKER_IMAGE=ghcr.io/oneargo/argoformatchecker/app
FILECHECKER_IMAGE_TAG=develop

# External directories to mount to the container
FILECHECKER_SPEC_VOLUME='D:\test_compose\file_checker_spec'
FILECHECKER_INPUT_VOLUME='D:\test_compose\data'
FILECHECKER_OUTPUT_VOLUME='D:\test_compose\results'

Expand Down Expand Up @@ -107,12 +112,20 @@ or for Windows :

output files will be generated in `./demo/outputs`.

### Run File checker using Python and an API

In folder /file-checker-python you will find a python wrapper and an API to facilitate the use of Argo FileChecker. See python.README for more informations.

### Test data

To further test the Argo File Checker, you will find argo data here : https://www.argodatamgt.org/DataAccess.html

The Argo File Checker is not yet designed to checking *prof.nc and *Sprof.nc. It checks only TRAJ, META, TECH and PROFILES files.

## Run File checker using Python and an API

In folder /argo-file-checker-python you will find a python wrapper and an API to facilitate the use of Argo FileChecker.

## TOOLS

### Maven Wrapper
Expand Down
3 changes: 1 addition & 2 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ services:
user: "${DOCKER_UID:-0}:${DOCKER_GID:-0}"
group_add:
- 1001
volumes:
- ${FILECHECKER_SPEC_VOLUME}:/app/file_checker_spec:ro
volumes:
- ${FILECHECKER_INPUT_VOLUME}:/app/data:ro
- ${FILECHECKER_OUTPUT_VOLUME}:/app/results:rw
command: ${FILECHECKER_OPTIONS} ${DAC_NAME} ./file_checker_spec ./results ./data ${FILES_NAMES}
File renamed without changes.
2 changes: 1 addition & 1 deletion file_checker_exec/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>fr.ifremer</groupId>
<artifactId>file_checker_exec</artifactId>
<version>2.9.3</version>
<version>2.9.4</version>

<name>Argo NetCDF file format checker</name>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,10 +514,12 @@ private boolean checkSpecialTechParamVarAttributeValue(Variable dataVar, String
if (attrName.equals("long_name") && authorizedLongName != null
&& !authorizedLongName.contains(dataAttrValue)) {

validationResult.addError("attribute: " + varName + ":" + attrName + ": Definitions differ "
+ "\n\tSpecification = See argo-tech_names-spec list, definition column"
+ "\n\tData File = '" + dataAttrValue + "'");
String specValueInErrorReport = authorizedLongName.size() == 1 ? "'" + authorizedLongName.get(0) + "'"
: "Multiple possibilities; see argo-tech_names-spec list, definition column";

validationResult.addError(
String.format("attribute: %s:%s: Definitions differ\n\tSpecification = %s\n\tData File = '%s'",
varName, attrName, specValueInErrorReport, dataAttrValue));
}

}
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .app import app
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import os
import shutil
from fastapi import FastAPI, UploadFile
from pathlib import Path
from tempfile import TemporaryDirectory

from argofilechecker_python_wrapper import FileChecker, ValidationResult

ROOT_PATH = os.getenv("API_ROOT_PATH", "")
UPLOAD_FILES_DIR = Path(os.getenv("UPLOAD_FILES_DIR", Path.cwd()))

app = FastAPI(root_path=ROOT_PATH)


@app.get("/")
def app_status() -> dict[str, str]:
"""
Health check endpoint to confirm that the app is running.
:return: status message
"""
return {"status": "OK"}


@app.post("/check-files")
def check_file_list(files: list[UploadFile], dac: str) -> list[ValidationResult]:
"""
Main endpoint to upload files to be checked.
:param files:
List of files uploaded as multipart/form-data
:param dac:
Relevant DAC for the files, e.g. coriolis, bodc, aoml, etc. Must be the same DAC for all files

:return:
list[ValidationResult]
"""
if not files:
raise ValueError("No files to check.")
if not UPLOAD_FILES_DIR.exists():
raise FileNotFoundError(f"Upload directory does not exist: {UPLOAD_FILES_DIR}")
if not UPLOAD_FILES_DIR.is_dir():
raise NotADirectoryError(f"Upload directory path is not a directory: {UPLOAD_FILES_DIR}")

with TemporaryDirectory(dir=UPLOAD_FILES_DIR) as request_tmp_dir:
request_file_dir = Path(request_tmp_dir)
for upload_file in files:
try:
with request_file_dir.joinpath(upload_file.filename).open("wb") as buffer:
shutil.copyfileobj(upload_file.file, buffer)
finally:
upload_file.file.close()
file_checker = FileChecker()
results = file_checker.check_files(request_file_dir.glob("*"), dac)
if not results:
raise RuntimeError("An error occurred while handling uploaded files.")
return results
Loading
Loading