-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from truenas/library-hashes
Generate hashes of different library versions and validate them
- Loading branch information
Showing
13 changed files
with
231 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import pathlib | ||
|
||
from jsonschema import validate as json_schema_validate, ValidationError as JsonValidationError | ||
|
||
from apps_validation.exceptions import ValidationErrors | ||
from catalog_reader.library import get_library_hashes, get_hashes_of_base_lib_versions, RE_VERSION | ||
from catalog_reader.names import get_library_path, get_library_hashes_path | ||
|
||
from .json_schema_utils import BASE_LIBRARIES_JSON_SCHEMA | ||
|
||
|
||
def validate_base_libraries(catalog_path: str, verrors: ValidationErrors) -> None: | ||
library_path = get_library_path(catalog_path) | ||
library_path_obj = pathlib.Path(library_path) | ||
if not library_path_obj.exists(): | ||
return | ||
|
||
found_libs = False | ||
for entry in filter(lambda e: e.is_dir(), library_path_obj.iterdir()): | ||
if RE_VERSION.match(entry.name): | ||
found_libs = True | ||
else: | ||
verrors.add( | ||
f'library.{entry.name}', 'Library version folder should conform to semantic versioning i.e 1.0.0' | ||
) | ||
|
||
if found_libs and not pathlib.Path(get_library_hashes_path(library_path)).exists(): | ||
verrors.add('library', 'Library hashes file is missing') | ||
|
||
verrors.check() | ||
|
||
get_local_hashes_contents = get_library_hashes(library_path) | ||
try: | ||
json_schema_validate(get_local_hashes_contents, BASE_LIBRARIES_JSON_SCHEMA) | ||
except JsonValidationError as e: | ||
verrors.add('library', f'Invalid format specified for library hashes: {e}') | ||
|
||
verrors.check() | ||
|
||
try: | ||
hashes = get_hashes_of_base_lib_versions(catalog_path) | ||
except Exception as e: | ||
verrors.add('library', f'Error while generating hashes for library versions: {e}') | ||
else: | ||
if hashes != get_local_hashes_contents: | ||
verrors.add( | ||
'library', | ||
'Generated hashes for library versions do not match with the existing ' | ||
'hashes file and need to be updated' | ||
) | ||
|
||
verrors.check() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import subprocess | ||
|
||
|
||
def get_hash_of_directory(directory: str) -> str: | ||
""" | ||
This returns sha256sum of the directory | ||
""" | ||
cp = subprocess.run( | ||
f'find {directory} -type f -exec sha256sum {{}} + | sort | awk \'{{print $1}}\' | sha256sum', | ||
capture_output=True, check=True, shell=True, | ||
) | ||
return cp.stdout.decode().split()[0] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import contextlib | ||
import os | ||
import pathlib | ||
import re | ||
import yaml | ||
|
||
from .hash_utils import get_hash_of_directory | ||
from .names import get_library_path, get_library_hashes_path | ||
|
||
|
||
RE_VERSION = re.compile(r'^\d+.\d+\.\d+$') | ||
|
||
|
||
def get_library_hashes(library_path: str) -> dict: | ||
""" | ||
This reads from library hashes file and returns the hashes | ||
""" | ||
with contextlib.suppress(FileNotFoundError, yaml.YAMLError): | ||
with open(get_library_hashes_path(library_path), 'r') as f: | ||
return yaml.safe_load(f.read()) | ||
|
||
|
||
def get_hashes_of_base_lib_versions(catalog_path: str) -> dict: | ||
library_path = get_library_path(catalog_path) | ||
library_dir = pathlib.Path(library_path) | ||
hashes = {} | ||
for lib_entry in library_dir.iterdir(): | ||
if not lib_entry.is_dir() or not RE_VERSION.match(lib_entry.name): | ||
continue | ||
|
||
hashes[lib_entry.name] = get_hash_of_directory(os.path.join(library_path, lib_entry.name)) | ||
|
||
return hashes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#!/usr/bin/env python | ||
import argparse | ||
import os | ||
import pathlib | ||
import ruamel.yaml | ||
import shutil | ||
import yaml | ||
|
||
from apps_validation.exceptions import CatalogDoesNotExist, ValidationErrors | ||
from catalog_reader.dev_directory import get_ci_development_directory | ||
from catalog_reader.library import get_hashes_of_base_lib_versions | ||
from catalog_reader.names import get_library_path, get_library_hashes_path, get_base_library_dir_name_from_version | ||
|
||
|
||
YAML = ruamel.yaml.YAML() | ||
YAML.indent(mapping=2, sequence=4, offset=2) | ||
|
||
|
||
def update_catalog_hashes(catalog_path: str) -> None: | ||
if not os.path.exists(catalog_path): | ||
raise CatalogDoesNotExist(catalog_path) | ||
|
||
verrors = ValidationErrors() | ||
library_dir = pathlib.Path(get_library_path(catalog_path)) | ||
if not library_dir.exists(): | ||
verrors.add('library', 'Library directory is missing') | ||
|
||
verrors.check() | ||
|
||
hashes = get_hashes_of_base_lib_versions(catalog_path) | ||
hashes_file_path = get_library_hashes_path(get_library_path(catalog_path)) | ||
with open(hashes_file_path, 'w') as f: | ||
yaml.safe_dump(hashes, f) | ||
|
||
print(f'[\033[92mOK\x1B[0m]\tGenerated hashes for library versions at {hashes_file_path!r}') | ||
|
||
dev_directory = pathlib.Path(get_ci_development_directory(catalog_path)) | ||
if not dev_directory.is_dir(): | ||
return | ||
elif not hashes: | ||
print('[\033[92mOK\x1B[0m]\tNo hashes found for library versions, skipping updating apps hashes') | ||
return | ||
|
||
for train_dir in dev_directory.iterdir(): | ||
if not train_dir.is_dir(): | ||
continue | ||
|
||
for app_dir in train_dir.iterdir(): | ||
if not app_dir.is_dir(): | ||
continue | ||
|
||
app_metadata_file = app_dir / 'app.yaml' | ||
if not app_metadata_file.is_file(): | ||
continue | ||
|
||
with open(str(app_metadata_file), 'r') as f: | ||
app_config = YAML.load(f) | ||
|
||
if (lib_version := app_config.get('lib_version')) and lib_version not in hashes: | ||
print( | ||
f'[\033[93mWARN\x1B[0m]\tLibrary version {lib_version!r} not found in hashes, ' | ||
f'skipping updating {app_dir.name!r} in {train_dir.name} train' | ||
) | ||
continue | ||
|
||
base_lib_name = get_base_library_dir_name_from_version(lib_version) | ||
app_lib_dir = app_dir / 'templates/library' | ||
app_lib_dir.mkdir(exist_ok=True, parents=True) | ||
app_base_lib_dir = app_lib_dir / base_lib_name | ||
shutil.rmtree(app_base_lib_dir.as_posix(), ignore_errors=True) | ||
|
||
catalog_base_lib_dir_path = os.path.join(library_dir.as_posix(), lib_version) | ||
shutil.copytree(catalog_base_lib_dir_path, app_base_lib_dir.as_posix()) | ||
|
||
app_config['lib_version_hash'] = hashes[lib_version] | ||
with open(str(app_metadata_file), 'w') as f: | ||
YAML.dump(app_config, f) | ||
|
||
print(f'[\033[92mOK\x1B[0m]\tUpdated library hash for {app_dir.name!r} in {train_dir.name}') | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('--path', help='Specify path of TrueNAS catalog') | ||
|
||
args = parser.parse_args() | ||
if not args.path: | ||
parser.print_help() | ||
else: | ||
update_catalog_hashes(args.path) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,5 @@ jinja2 | |
jsonschema==4.10.3 | ||
markdown | ||
pyyaml | ||
ruamel.yaml | ||
semantic_version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters