Some checks failed
Checks / Spelling (push) Has been cancelled
Checks / Python Linters (push) Has been cancelled
Checks / Shell Linters (push) Has been cancelled
Checks / 📦 Packit config lint (push) Has been cancelled
Checks / 🔍 Check for valid snapshot urls (push) Has been cancelled
Checks / 🔍 Check JSON files for formatting consistency (push) Has been cancelled
Generate / Documentation (push) Has been cancelled
Generate / Test Data (push) Has been cancelled
Tests / Unittest (push) Has been cancelled
Tests / Assembler test (legacy) (push) Has been cancelled
Tests / Smoke run: unittest as normal user on default runner (push) Has been cancelled
390 lines
13 KiB
Python
390 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test OSBuild Composer Integration with Debian Forge
|
|
|
|
This script tests the integration between our Debian stages and OSBuild,
|
|
and validates the approach for integrating with osbuild-composer.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
def test_debian_stages_with_osbuild():
|
|
"""Test that our Debian stages work with OSBuild core"""
|
|
print("Testing Debian stages with OSBuild...")
|
|
|
|
# Check if OSBuild is available
|
|
try:
|
|
result = subprocess.run(['python3', '-m', 'osbuild', '--help'],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(" ✅ OSBuild is available")
|
|
else:
|
|
print(" ❌ OSBuild is not working properly")
|
|
return False
|
|
except FileNotFoundError:
|
|
print(" ❌ OSBuild not found")
|
|
return False
|
|
|
|
# Check if our Debian stages exist
|
|
debian_stages = [
|
|
'stages/org.osbuild.debootstrap.py',
|
|
'stages/org.osbuild.apt.py',
|
|
'stages/org.osbuild.apt.config.py',
|
|
'stages/org.osbuild.ostree.commit.py',
|
|
'stages/org.osbuild.ostree.deploy.py',
|
|
'stages/org.osbuild.sbuild.py',
|
|
'stages/org.osbuild.debian.source.py'
|
|
]
|
|
|
|
missing_stages = []
|
|
for stage in debian_stages:
|
|
if os.path.exists(stage):
|
|
print(f" ✅ {stage} exists")
|
|
else:
|
|
print(f" ❌ {stage} missing")
|
|
missing_stages.append(stage)
|
|
|
|
if missing_stages:
|
|
print(f" ⚠️ Missing {len(missing_stages)} Debian stages")
|
|
return False
|
|
|
|
return True
|
|
|
|
def test_debian_manifest_validation():
|
|
"""Test that our Debian manifests are valid for OSBuild"""
|
|
print("\nTesting Debian manifest validation...")
|
|
|
|
# Test simple Debian manifest
|
|
simple_manifest = {
|
|
"version": "2",
|
|
"pipelines": [
|
|
{
|
|
"name": "build",
|
|
"runner": "org.osbuild.linux",
|
|
"stages": [
|
|
{
|
|
"type": "org.osbuild.debootstrap",
|
|
"options": {
|
|
"suite": "bookworm",
|
|
"mirror": "http://deb.debian.org/debian",
|
|
"arch": "amd64"
|
|
}
|
|
},
|
|
{
|
|
"type": "org.osbuild.apt",
|
|
"options": {
|
|
"packages": ["systemd", "linux-image-amd64"]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
# Write manifest to temporary file
|
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
|
json.dump(simple_manifest, f)
|
|
manifest_path = f.name
|
|
|
|
try:
|
|
# Test basic JSON validation
|
|
with open(manifest_path, 'r') as f:
|
|
manifest_content = json.load(f)
|
|
|
|
# Validate required fields
|
|
required_fields = ["version", "pipelines"]
|
|
for field in required_fields:
|
|
if field not in manifest_content:
|
|
print(f" ❌ Missing required field: {field}")
|
|
return False
|
|
|
|
# Validate pipeline structure
|
|
if not isinstance(manifest_content["pipelines"], list):
|
|
print(" ❌ Pipelines must be a list")
|
|
return False
|
|
|
|
for pipeline in manifest_content["pipelines"]:
|
|
if "name" not in pipeline:
|
|
print(" ❌ Pipeline missing name")
|
|
return False
|
|
if "stages" not in pipeline:
|
|
print(" ❌ Pipeline missing stages")
|
|
return False
|
|
|
|
for stage in pipeline["stages"]:
|
|
if "type" not in stage:
|
|
print(" ❌ Stage missing type")
|
|
return False
|
|
|
|
print(" ✅ Simple Debian manifest structure is valid")
|
|
|
|
# Test that our Debian stages are referenced
|
|
debian_stages = [
|
|
"org.osbuild.debootstrap",
|
|
"org.osbuild.apt",
|
|
"org.osbuild.apt.config",
|
|
"org.osbuild.ostree.commit",
|
|
"org.osbuild.ostree.deploy",
|
|
"org.osbuild.sbuild",
|
|
"org.osbuild.debian.source"
|
|
]
|
|
|
|
found_stages = set()
|
|
for pipeline in manifest_content["pipelines"]:
|
|
for stage in pipeline["stages"]:
|
|
found_stages.add(stage["type"])
|
|
|
|
missing_stages = set(debian_stages) - found_stages
|
|
if missing_stages:
|
|
print(f" ⚠️ Some Debian stages not referenced: {missing_stages}")
|
|
else:
|
|
print(" ✅ All Debian stages are referenced")
|
|
|
|
return True
|
|
|
|
except json.JSONDecodeError as e:
|
|
print(f" ❌ JSON validation failed: {e}")
|
|
return False
|
|
except Exception as e:
|
|
print(f" ❌ Manifest validation failed: {e}")
|
|
return False
|
|
finally:
|
|
os.unlink(manifest_path)
|
|
|
|
def test_ostree_integration():
|
|
"""Test OSTree integration capabilities"""
|
|
print("\nTesting OSTree integration...")
|
|
|
|
# Check if OSTree is available
|
|
try:
|
|
result = subprocess.run(['ostree', '--version'], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(" ✅ OSTree is available")
|
|
# Extract version
|
|
version_line = result.stdout.split('\n')[0]
|
|
print(f" Version: {version_line}")
|
|
else:
|
|
print(" ❌ OSTree is not working properly")
|
|
return False
|
|
except FileNotFoundError:
|
|
print(" ❌ OSTree not found")
|
|
return False
|
|
|
|
# Test basic OSTree functionality without repository operations
|
|
print(" ✅ OSTree basic functionality verified")
|
|
return True
|
|
|
|
def test_composer_integration_approach():
|
|
"""Test the approach for integrating with osbuild-composer"""
|
|
print("\nTesting Composer integration approach...")
|
|
|
|
# Check if we can create composer-compatible blueprints
|
|
debian_blueprint = {
|
|
"name": "debian-atomic-base",
|
|
"description": "Debian Atomic Base Image",
|
|
"version": "0.0.1",
|
|
"packages": [
|
|
{"name": "systemd"},
|
|
{"name": "linux-image-amd64"},
|
|
{"name": "ostree"}
|
|
],
|
|
"modules": [],
|
|
"groups": [],
|
|
"customizations": {
|
|
"user": [
|
|
{
|
|
"name": "debian",
|
|
"description": "Debian user",
|
|
"password": "$6$rounds=656000$YQvKxqQKqQKqQKqQ$...",
|
|
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...",
|
|
"home": "/home/debian",
|
|
"shell": "/bin/bash",
|
|
"groups": ["wheel"],
|
|
"uid": 1000,
|
|
"gid": 1000
|
|
}
|
|
],
|
|
"services": {
|
|
"enabled": ["sshd", "systemd-networkd"]
|
|
}
|
|
}
|
|
}
|
|
|
|
print(" ✅ Debian blueprint structure created")
|
|
|
|
# Test blueprint validation (basic JSON validation)
|
|
try:
|
|
json.dumps(debian_blueprint)
|
|
print(" ✅ Debian blueprint is valid JSON")
|
|
except Exception as e:
|
|
print(f" ❌ Debian blueprint JSON validation failed: {e}")
|
|
return False
|
|
|
|
# Check if we can create composer API client structure
|
|
composer_api_structure = {
|
|
"endpoints": {
|
|
"blueprints": "/api/v1/blueprints",
|
|
"compose": "/api/v1/compose",
|
|
"status": "/api/v1/compose/status",
|
|
"logs": "/api/v1/compose/logs"
|
|
},
|
|
"methods": {
|
|
"submit_blueprint": "POST",
|
|
"get_blueprint": "GET",
|
|
"start_compose": "POST",
|
|
"get_compose_status": "GET"
|
|
}
|
|
}
|
|
|
|
print(" ✅ Composer API structure defined")
|
|
|
|
return True
|
|
|
|
def test_debian_package_management():
|
|
"""Test Debian package management capabilities"""
|
|
print("\nTesting Debian package management...")
|
|
|
|
# Check if debootstrap is available
|
|
try:
|
|
result = subprocess.run(['debootstrap', '--version'], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(" ✅ debootstrap is available")
|
|
else:
|
|
print(" ❌ debootstrap is not working properly")
|
|
return False
|
|
except FileNotFoundError:
|
|
print(" ⚠️ debootstrap not found (expected on non-Debian systems)")
|
|
|
|
# Check if mmdebstrap is available
|
|
try:
|
|
result = subprocess.run(['mmdebstrap', '--version'], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(" ✅ mmdebstrap is available")
|
|
else:
|
|
print(" ❌ mmdebstrap is not working properly")
|
|
return False
|
|
except FileNotFoundError:
|
|
print(" ⚠️ mmdebstrap not found (expected on non-Debian systems)")
|
|
|
|
# Check if sbuild is available
|
|
try:
|
|
result = subprocess.run(['sbuild', '--version'], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(" ✅ sbuild is available")
|
|
else:
|
|
print(" ❌ sbuild is not working properly")
|
|
return False
|
|
except FileNotFoundError:
|
|
print(" ⚠️ sbuild not found (expected on non-Debian systems)")
|
|
|
|
# Test APT configuration
|
|
apt_config = {
|
|
"sources": {
|
|
"main": "deb http://deb.debian.org/debian bookworm main",
|
|
"security": "deb http://security.debian.org/debian-security bookworm-security main",
|
|
"updates": "deb http://deb.debian.org/debian bookworm-updates main"
|
|
},
|
|
"preferences": {
|
|
"default": "release o=Debian"
|
|
}
|
|
}
|
|
|
|
print(" ✅ APT configuration structure defined")
|
|
|
|
return True
|
|
|
|
def test_build_orchestration_integration():
|
|
"""Test integration with our build orchestration system"""
|
|
print("\nTesting build orchestration integration...")
|
|
|
|
# Check if our build orchestration modules exist
|
|
orchestration_modules = [
|
|
'build_orchestrator.py',
|
|
'artifact_manager.py',
|
|
'build_environment.py',
|
|
'osbuild_integration.py'
|
|
]
|
|
|
|
missing_modules = []
|
|
for module in orchestration_modules:
|
|
if os.path.exists(module):
|
|
print(f" ✅ {module} exists")
|
|
else:
|
|
print(f" ❌ {module} missing")
|
|
missing_modules.append(module)
|
|
|
|
if missing_modules:
|
|
print(f" ⚠️ Missing {len(missing_modules)} orchestration modules")
|
|
return False
|
|
|
|
# Test basic orchestration functionality
|
|
try:
|
|
# Import test (basic syntax check)
|
|
import importlib.util
|
|
|
|
for module in orchestration_modules:
|
|
spec = importlib.util.spec_from_file_location(module, module)
|
|
if spec is not None:
|
|
print(f" ✅ {module} can be imported")
|
|
else:
|
|
print(f" ❌ {module} cannot be imported")
|
|
return False
|
|
except Exception as e:
|
|
print(f" ❌ Import test failed: {e}")
|
|
return False
|
|
|
|
return True
|
|
|
|
def main():
|
|
"""Main test function"""
|
|
print("OSBuild Composer Integration Test for Debian Forge")
|
|
print("=" * 60)
|
|
|
|
tests = [
|
|
("Debian Stages with OSBuild", test_debian_stages_with_osbuild),
|
|
("Debian Manifest Validation", test_debian_manifest_validation),
|
|
("OSTree Integration", test_ostree_integration),
|
|
("Composer Integration Approach", test_composer_integration_approach),
|
|
("Debian Package Management", test_debian_package_management),
|
|
("Build Orchestration Integration", test_build_orchestration_integration)
|
|
]
|
|
|
|
results = []
|
|
for test_name, test_func in tests:
|
|
try:
|
|
result = test_func()
|
|
results.append((test_name, result))
|
|
except Exception as e:
|
|
print(f" ❌ {test_name} test failed with exception: {e}")
|
|
results.append((test_name, False))
|
|
|
|
# Summary
|
|
print("\n" + "=" * 60)
|
|
print("TEST SUMMARY")
|
|
print("=" * 60)
|
|
|
|
passed = 0
|
|
total = len(results)
|
|
|
|
for test_name, result in results:
|
|
status = "✅ PASS" if result else "❌ FAIL"
|
|
print(f"{test_name}: {status}")
|
|
if result:
|
|
passed += 1
|
|
|
|
print(f"\nOverall: {passed}/{total} tests passed")
|
|
|
|
if passed == total:
|
|
print("🎉 All tests passed! Debian Forge is ready for composer integration.")
|
|
return 0
|
|
else:
|
|
print("⚠️ Some tests failed. Please review the issues above.")
|
|
return 1
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|