mirror of
https://github.com/truenas/scale-build.git
synced 2025-12-24 13:00:20 +00:00
Validate manifet when executing other targets
This commit is contained in:
6
.github/workflows/manifest.yml
vendored
6
.github/workflows/manifest.yml
vendored
@@ -13,9 +13,7 @@ jobs:
|
|||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v1
|
||||||
with:
|
with:
|
||||||
python-version: 3.9
|
python-version: 3.9
|
||||||
- name: Install dependencies
|
- name: Validating manifest
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements.txt
|
make validate_manifest PYTHON=`which python`
|
||||||
- name: Validating manifest
|
|
||||||
run: ./scripts/validate_manifest.py validate --path=./conf/build.manifest
|
|
||||||
|
|||||||
14
Makefile
14
Makefile
@@ -16,13 +16,17 @@ endif
|
|||||||
|
|
||||||
all: checkout packages update iso
|
all: checkout packages update iso
|
||||||
|
|
||||||
clean: check
|
clean: validate
|
||||||
. ./venv-${COMMIT_HASH}/bin/activate && scale_build clean
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build clean
|
||||||
checkout: check
|
checkout: validate
|
||||||
. ./venv-${COMMIT_HASH}/bin/activate && scale_build checkout
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build checkout
|
||||||
iso: check
|
iso: validate
|
||||||
. ./venv-${COMMIT_HASH}/bin/activate && scale_build iso
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build iso
|
||||||
packages: check
|
packages: validate
|
||||||
. ./venv-${COMMIT_HASH}/bin/activate && scale_build packages
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build packages
|
||||||
update: check
|
update: validate
|
||||||
. ./venv-${COMMIT_HASH}/bin/activate && scale_build update
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build update
|
||||||
|
validate_manifest: check
|
||||||
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build validate --no-validate-system_state
|
||||||
|
validate: check
|
||||||
|
. ./venv-${COMMIT_HASH}/bin/activate && scale_build validate
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ chardet==4.0.0
|
|||||||
coloredlogs==15.0
|
coloredlogs==15.0
|
||||||
humanfriendly==9.1
|
humanfriendly==9.1
|
||||||
idna==2.10
|
idna==2.10
|
||||||
|
jsonschema==3.2.0
|
||||||
pexpect==4.8.0
|
pexpect==4.8.0
|
||||||
psutil==5.8.0
|
psutil==5.8.0
|
||||||
ptyprocess==0.7.0
|
ptyprocess==0.7.0
|
||||||
@@ -10,4 +11,3 @@ PyYAML==5.4.1
|
|||||||
requests==2.25.1
|
requests==2.25.1
|
||||||
toposort==1.6
|
toposort==1.6
|
||||||
urllib3==1.26.4
|
urllib3==1.26.4
|
||||||
jsonschema==3.2.0
|
|
||||||
|
|||||||
@@ -11,11 +11,6 @@ class MissingManifest(CallError):
|
|||||||
super().__init__('Unable to locate manifest file')
|
super().__init__('Unable to locate manifest file')
|
||||||
|
|
||||||
|
|
||||||
class InvalidManifest(CallError):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__('Invalid manifest file found')
|
|
||||||
|
|
||||||
|
|
||||||
class MissingPackagesException(CallError):
|
class MissingPackagesException(CallError):
|
||||||
def __init__(self, packages):
|
def __init__(self, packages):
|
||||||
super().__init__(f'Failed preflight check. Please install {", ".join(packages)!r} packages.')
|
super().__init__(f'Failed preflight check. Please install {", ".join(packages)!r} packages.')
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from .package import build_packages
|
|||||||
from .preflight import preflight_check
|
from .preflight import preflight_check
|
||||||
from .update_image import build_update_image
|
from .update_image import build_update_image
|
||||||
from .utils.manifest import get_manifest
|
from .utils.manifest import get_manifest
|
||||||
|
from .validate import validate
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -49,6 +50,11 @@ def main():
|
|||||||
subparsers.add_parser('packages', help='Build TrueNAS Scale packages')
|
subparsers.add_parser('packages', help='Build TrueNAS Scale packages')
|
||||||
subparsers.add_parser('update', help='Create TrueNAS Scale update image')
|
subparsers.add_parser('update', help='Create TrueNAS Scale update image')
|
||||||
subparsers.add_parser('iso', help='Create TrueNAS Scale iso installation file')
|
subparsers.add_parser('iso', help='Create TrueNAS Scale iso installation file')
|
||||||
|
validate_parser = subparsers.add_parser('validate', help='Validate TrueNAS Scale build manifest and system state')
|
||||||
|
for action in ('manifest', 'system_state'):
|
||||||
|
validate_parser.add_argument(f'--validate-{action}', dest=action, action='store_true')
|
||||||
|
validate_parser.add_argument(f'--no-validate-{action}', dest=action, action='store_false')
|
||||||
|
validate_parser.set_defaults(**{action: True})
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.action == 'checkout':
|
if args.action == 'checkout':
|
||||||
@@ -63,5 +69,7 @@ def main():
|
|||||||
build_iso()
|
build_iso()
|
||||||
elif args.action == 'clean':
|
elif args.action == 'clean':
|
||||||
complete_cleanup()
|
complete_cleanup()
|
||||||
|
elif args.action == 'validate':
|
||||||
|
validate(args.system_state, args.manifest)
|
||||||
else:
|
else:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from toposort import toposort
|
|||||||
from .bootstrap.bootstrapdir import PackageBootstrapDirectory
|
from .bootstrap.bootstrapdir import PackageBootstrapDirectory
|
||||||
from .clean import clean_bootstrap_logs
|
from .clean import clean_bootstrap_logs
|
||||||
from .config import PARALLEL_BUILD, PKG_DEBUG
|
from .config import PARALLEL_BUILD, PKG_DEBUG
|
||||||
|
from .exceptions import CallError
|
||||||
from .packages.order import get_initialized_packages, get_to_build_packages
|
from .packages.order import get_initialized_packages, get_to_build_packages
|
||||||
from .utils.logger import get_logger
|
from .utils.logger import get_logger
|
||||||
from .utils.paths import LOG_DIR, PKG_DIR, PKG_LOG_DIR
|
from .utils.paths import LOG_DIR, PKG_DIR, PKG_LOG_DIR
|
||||||
@@ -163,5 +164,7 @@ def _build_packages_impl():
|
|||||||
for p in failed.values():
|
for p in failed.values():
|
||||||
p['package'].delete_overlayfs()
|
p['package'].delete_overlayfs()
|
||||||
|
|
||||||
|
raise CallError(f'{", ".join(failed)!r} Packages failed to build')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info('Success! Done building packages')
|
logger.info('Success! Done building packages')
|
||||||
|
|||||||
@@ -1,31 +1,12 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
|
|
||||||
from .exceptions import CallError, MissingPackagesException
|
|
||||||
from .utils.manifest import get_manifest
|
|
||||||
from .utils.system import has_low_ram
|
from .utils.system import has_low_ram
|
||||||
from .utils.paths import CACHE_DIR, HASH_DIR, LOG_DIR, PKG_DIR, PKG_LOG_DIR, SOURCES_DIR, TMP_DIR, TMPFS
|
from .utils.paths import CACHE_DIR, HASH_DIR, LOG_DIR, PKG_DIR, PKG_LOG_DIR, SOURCES_DIR, TMP_DIR, TMPFS
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
WANTED_PACKAGES = {
|
|
||||||
'make',
|
|
||||||
'debootstrap',
|
|
||||||
'git',
|
|
||||||
'mksquashfs',
|
|
||||||
'unzip',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def is_root():
|
|
||||||
return os.geteuid() == 0
|
|
||||||
|
|
||||||
|
|
||||||
def retrieve_missing_packages():
|
|
||||||
return {pkg for pkg in WANTED_PACKAGES if not shutil.which(pkg)}
|
|
||||||
|
|
||||||
|
|
||||||
def setup_dirs():
|
def setup_dirs():
|
||||||
for d in (CACHE_DIR, TMP_DIR, HASH_DIR, LOG_DIR, PKG_DIR, PKG_LOG_DIR, SOURCES_DIR, TMPFS):
|
for d in (CACHE_DIR, TMP_DIR, HASH_DIR, LOG_DIR, PKG_DIR, PKG_LOG_DIR, SOURCES_DIR, TMPFS):
|
||||||
@@ -33,16 +14,7 @@ def setup_dirs():
|
|||||||
|
|
||||||
|
|
||||||
def preflight_check():
|
def preflight_check():
|
||||||
if not is_root():
|
|
||||||
raise CallError('Must be run as root (or using sudo)!')
|
|
||||||
|
|
||||||
missing_packages = retrieve_missing_packages()
|
|
||||||
if missing_packages:
|
|
||||||
raise MissingPackagesException(missing_packages)
|
|
||||||
|
|
||||||
if has_low_ram():
|
if has_low_ram():
|
||||||
logging.warning('WARNING: Running with less than 16GB of memory. Build may fail...')
|
logging.warning('WARNING: Running with less than 16GB of memory. Build may fail...')
|
||||||
|
|
||||||
setup_dirs()
|
setup_dirs()
|
||||||
# TODO: Validate contents of manifest like empty string is not provided for source name/repo etc
|
|
||||||
get_manifest()
|
|
||||||
|
|||||||
@@ -1,26 +1,136 @@
|
|||||||
|
import functools
|
||||||
|
import jsonschema
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from scale_build.config import TRAIN
|
from scale_build.config import TRAIN
|
||||||
from scale_build.exceptions import MissingManifest, InvalidManifest
|
from scale_build.exceptions import CallError, MissingManifest
|
||||||
from scale_build.utils.paths import MANIFEST
|
from scale_build.utils.paths import MANIFEST
|
||||||
|
|
||||||
|
|
||||||
manifest = None
|
MANIFEST_SCHEMA = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'code_name': {'type': 'string'},
|
||||||
|
'debian_release': {'type': 'string'},
|
||||||
|
'apt-repos': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'url': {'type': 'string'},
|
||||||
|
'distribution': {'type': 'string'},
|
||||||
|
'components': {'type': 'string'},
|
||||||
|
'additional': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'url': {'type': 'string'},
|
||||||
|
'distribution': {'type': 'string'},
|
||||||
|
'component': {'type': 'string'},
|
||||||
|
'key': {'type': 'string'},
|
||||||
|
},
|
||||||
|
'required': ['url', 'distribution', 'component', 'key'],
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['url', 'distribution', 'components', 'additional'],
|
||||||
|
},
|
||||||
|
'base-packages': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'base-prune': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'build-epoch': {'type': 'integer'},
|
||||||
|
'apt_preferences': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Package': {'type': 'string'},
|
||||||
|
'Pin': {'type': 'string'},
|
||||||
|
'Pin-Priority': {'type': 'integer'},
|
||||||
|
},
|
||||||
|
'required': ['Package', 'Pin', 'Pin-Priority'],
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
'additional-packages': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'package': {'type': 'string'},
|
||||||
|
'comment': {'type': 'string'},
|
||||||
|
},
|
||||||
|
'required': ['package', 'comment'],
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
'iso-packages': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'name': {'type': 'string'},
|
||||||
|
'repo': {'type': 'string'},
|
||||||
|
'branch': {'type': 'string'},
|
||||||
|
'batch_priority': {'type': 'integer'},
|
||||||
|
'predepscmd': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'buildcmd': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'prebuildcmd': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'deps_path': {'type': 'string'},
|
||||||
|
'kernel_module': {'type': 'boolean'},
|
||||||
|
'generate_version': {'type': 'boolean'},
|
||||||
|
'explicit_deps': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': [{'type': 'string'}],
|
||||||
|
},
|
||||||
|
'subdir': {'type': 'string'},
|
||||||
|
'deoptions': {'type': 'string'},
|
||||||
|
'jobs': {'type': 'integer'},
|
||||||
|
},
|
||||||
|
'required': ['name', 'branch', 'repo'],
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': [
|
||||||
|
'code_name',
|
||||||
|
'debian_release',
|
||||||
|
'apt-repos',
|
||||||
|
'base-packages',
|
||||||
|
'base-prune',
|
||||||
|
'build-epoch',
|
||||||
|
'apt_preferences',
|
||||||
|
'additional-packages',
|
||||||
|
'iso-packages',
|
||||||
|
'sources'
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@functools.cache
|
||||||
def get_manifest():
|
def get_manifest():
|
||||||
global manifest
|
try:
|
||||||
if not manifest:
|
with open(MANIFEST, 'r') as f:
|
||||||
try:
|
manifest = yaml.safe_load(f.read())
|
||||||
with open(MANIFEST, 'r') as f:
|
return manifest
|
||||||
manifest = yaml.safe_load(f.read())
|
except FileNotFoundError:
|
||||||
return manifest
|
raise MissingManifest()
|
||||||
except FileNotFoundError:
|
except yaml.YAMLError:
|
||||||
raise MissingManifest()
|
raise CallError('Provided manifest has invalid format')
|
||||||
except yaml.YAMLError:
|
|
||||||
raise InvalidManifest()
|
|
||||||
else:
|
|
||||||
return manifest
|
|
||||||
|
|
||||||
|
|
||||||
def get_release_code_name():
|
def get_release_code_name():
|
||||||
@@ -29,3 +139,10 @@ def get_release_code_name():
|
|||||||
|
|
||||||
def get_truenas_train():
|
def get_truenas_train():
|
||||||
return TRAIN or f'TrueNAS-SCALE-{get_release_code_name()}-Nightlies'
|
return TRAIN or f'TrueNAS-SCALE-{get_release_code_name()}-Nightlies'
|
||||||
|
|
||||||
|
|
||||||
|
def validate_manifest():
|
||||||
|
try:
|
||||||
|
jsonschema.validate(get_manifest(), MANIFEST_SCHEMA)
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
raise CallError(f'Provided manifest is invalid: {e}')
|
||||||
|
|||||||
39
scale_build/validate.py
Normal file
39
scale_build/validate.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from .exceptions import CallError, MissingPackagesException
|
||||||
|
from .utils.manifest import validate_manifest
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
WANTED_PACKAGES = {
|
||||||
|
'make',
|
||||||
|
'debootstrap',
|
||||||
|
'git',
|
||||||
|
'mksquashfs',
|
||||||
|
'unzip',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def retrieve_missing_packages():
|
||||||
|
return {pkg for pkg in WANTED_PACKAGES if not shutil.which(pkg)}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_system_state():
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
raise CallError('Must be run as root (or using sudo)!')
|
||||||
|
|
||||||
|
missing_packages = retrieve_missing_packages()
|
||||||
|
if missing_packages:
|
||||||
|
raise MissingPackagesException(missing_packages)
|
||||||
|
|
||||||
|
|
||||||
|
def validate(system_state_flag=True, manifest_flag=True):
|
||||||
|
if system_state_flag:
|
||||||
|
validate_system_state()
|
||||||
|
logger.debug('System state Validated')
|
||||||
|
if manifest_flag:
|
||||||
|
validate_manifest()
|
||||||
|
logger.debug('Manifest Validated')
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import argparse
|
|
||||||
import jsonschema
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
|
|
||||||
def validate(manifest_path):
|
|
||||||
|
|
||||||
error_str = None
|
|
||||||
try:
|
|
||||||
with open(manifest_path, 'r') as f:
|
|
||||||
manifest = yaml.safe_load(f.read())
|
|
||||||
except FileNotFoundError:
|
|
||||||
error_str = f'{manifest_path!r} does not exist'
|
|
||||||
except yaml.YAMLError:
|
|
||||||
error_str = f'Unable to read {manifest_path!r} contents. Can you please confirm format is valid ?'
|
|
||||||
|
|
||||||
if error_str:
|
|
||||||
print(f'[\033[91mFAILED\x1B[0m]\t{error_str}')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
schema = {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'code_name': {'type': 'string'},
|
|
||||||
'debian_release': {'type': 'string'},
|
|
||||||
'apt-repos': {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'url': {'type': 'string'},
|
|
||||||
'distribution': {'type': 'string'},
|
|
||||||
'components': {'type': 'string'},
|
|
||||||
'additional': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'url': {'type': 'string'},
|
|
||||||
'distribution': {'type': 'string'},
|
|
||||||
'component': {'type': 'string'},
|
|
||||||
'key': {'type': 'string'},
|
|
||||||
},
|
|
||||||
'required': ['url', 'distribution', 'component', 'key'],
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'required': ['url', 'distribution', 'components', 'additional'],
|
|
||||||
},
|
|
||||||
'base-packages': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'base-prune': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'build-epoch': {'type': 'integer'},
|
|
||||||
'apt_preferences': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'Package': {'type': 'string'},
|
|
||||||
'Pin': {'type': 'string'},
|
|
||||||
'Pin-Priority': {'type': 'integer'},
|
|
||||||
},
|
|
||||||
'required': ['Package', 'Pin', 'Pin-Priority'],
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
'additional-packages': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'package': {'type': 'string'},
|
|
||||||
'comment': {'type': 'string'},
|
|
||||||
},
|
|
||||||
'required': ['package', 'comment'],
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
'iso-packages': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'sources': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'name': {'type': 'string'},
|
|
||||||
'repo': {'type': 'string'},
|
|
||||||
'branch': {'type': 'string'},
|
|
||||||
'batch_priority': {'type': 'integer'},
|
|
||||||
'predepscmd': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'buildcmd': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'prebuildcmd': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'deps_path': {'type': 'string'},
|
|
||||||
'kernel_module': {'type': 'boolean'},
|
|
||||||
'generate_version': {'type': 'boolean'},
|
|
||||||
'explicit_deps': {
|
|
||||||
'type': 'array',
|
|
||||||
'items': [{'type': 'string'}],
|
|
||||||
},
|
|
||||||
'subdir': {'type': 'string'},
|
|
||||||
'deoptions': {'type': 'string'},
|
|
||||||
'jobs': {'type': 'integer'},
|
|
||||||
},
|
|
||||||
'required': ['name', 'branch', 'repo'],
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'required': [
|
|
||||||
'code_name',
|
|
||||||
'debian_release',
|
|
||||||
'apt-repos',
|
|
||||||
'base-packages',
|
|
||||||
'base-prune',
|
|
||||||
'build-epoch',
|
|
||||||
'apt_preferences',
|
|
||||||
'additional-packages',
|
|
||||||
'iso-packages',
|
|
||||||
'sources'
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
jsonschema.validate(manifest, schema)
|
|
||||||
except jsonschema.ValidationError as e:
|
|
||||||
print(f'[\033[91mFAILED\x1B[0m]\tFailed to validate manifest: {e}')
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
print('[\033[92mOK\x1B[0m]\tManifest validated')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
subparsers = parser.add_subparsers(help='sub-command help', dest='action')
|
|
||||||
|
|
||||||
parser_setup = subparsers.add_parser('validate', help='Validate TrueNAS Scale build manifest')
|
|
||||||
parser_setup.add_argument('--path', help='Specify path of build manifest')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
if args.action == 'validate':
|
|
||||||
validate(args.path)
|
|
||||||
else:
|
|
||||||
parser.print_help()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
Reference in New Issue
Block a user