332 lines
8.4 KiB
Text
332 lines
8.4 KiB
Text
# OCI Registry Service Integration
|
||
|
||
use ../config/loader.nu get-config
|
||
|
||
# Start registry service
|
||
export def start-oci-registry [
|
||
registry_type: string = "zot"
|
||
config_path?: string
|
||
] -> bool {
|
||
print $"Starting OCI registry service \(($registry_type)\)..."
|
||
|
||
let registry_dir = get-registry-directory $registry_type
|
||
|
||
if not ($registry_dir | path exists) {
|
||
print $"ERROR: Registry directory not found: ($registry_dir)"
|
||
return false
|
||
}
|
||
|
||
cd $registry_dir
|
||
|
||
let compose_file = if ($config_path | is-empty) {
|
||
"docker-compose.yml"
|
||
} else {
|
||
$config_path
|
||
}
|
||
|
||
let result = (^docker-compose -f $compose_file up -d | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
print "✅ Registry service started"
|
||
return true
|
||
} else {
|
||
print $"ERROR: Failed to start registry: ($result.stderr)"
|
||
return false
|
||
}
|
||
}
|
||
|
||
# Stop registry service
|
||
export def stop-oci-registry [
|
||
registry_type: string = "zot"
|
||
] -> bool {
|
||
print $"Stopping OCI registry service \(($registry_type)\)..."
|
||
|
||
let registry_dir = get-registry-directory $registry_type
|
||
|
||
if not ($registry_dir | path exists) {
|
||
print $"ERROR: Registry directory not found: ($registry_dir)"
|
||
return false
|
||
}
|
||
|
||
cd $registry_dir
|
||
|
||
let result = (^docker-compose down | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
print "✅ Registry service stopped"
|
||
return true
|
||
} else {
|
||
print $"ERROR: Failed to stop registry: ($result.stderr)"
|
||
return false
|
||
}
|
||
}
|
||
|
||
# Get registry status
|
||
export def get-oci-registry-status [
|
||
registry_type: string = "zot"
|
||
] -> record {
|
||
let registry_dir = get-registry-directory $registry_type
|
||
|
||
if not ($registry_dir | path exists) {
|
||
return {
|
||
running: false
|
||
error: "Registry directory not found"
|
||
}
|
||
}
|
||
|
||
cd $registry_dir
|
||
|
||
let result = (^docker-compose ps --format json | complete)
|
||
|
||
if $result.exit_code != 0 {
|
||
return {
|
||
running: false
|
||
error: $result.stderr
|
||
}
|
||
}
|
||
|
||
let containers = ($result.stdout | from json)
|
||
let running = ($containers | all { |c| $c.State == "running" })
|
||
|
||
{
|
||
running: $running
|
||
containers: $containers
|
||
type: $registry_type
|
||
}
|
||
}
|
||
|
||
# Check registry health
|
||
export def check-oci-registry-health [
|
||
registry_url: string
|
||
] -> bool {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/" --timeout 5sec
|
||
} | complete)
|
||
|
||
$result.exit_code == 0
|
||
}
|
||
|
||
# Get registry info
|
||
export def get-oci-registry-info [
|
||
registry_url: string
|
||
] -> record {
|
||
# Try to fetch catalog
|
||
let catalog_result = (do {
|
||
http get $"http://($registry_url)/v2/_catalog"
|
||
} | complete)
|
||
|
||
let catalog = if $catalog_result.exit_code == 0 {
|
||
$catalog_result.stdout | from json
|
||
} else {
|
||
{repositories: []}
|
||
}
|
||
|
||
# Count namespaces
|
||
let namespaces = ($catalog.repositories
|
||
| each { |r| $r | split row "/" | first }
|
||
| uniq
|
||
| length)
|
||
|
||
{
|
||
url: $registry_url
|
||
healthy: ($catalog_result.exit_code == 0)
|
||
repositories: ($catalog.repositories | length)
|
||
namespaces: $namespaces
|
||
timestamp: (date now | format date "%Y-%m-%d %H:%M:%S")
|
||
}
|
||
}
|
||
|
||
# Get repository list
|
||
export def get-oci-registry-repositories [
|
||
registry_url: string
|
||
] -> list {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/_catalog"
|
||
} | complete)
|
||
|
||
if $result.exit_code != 0 {
|
||
return []
|
||
}
|
||
|
||
let catalog = ($result.stdout | from json)
|
||
$catalog.repositories
|
||
}
|
||
|
||
# Get repository tags
|
||
export def get-oci-repository-tags [
|
||
registry_url: string
|
||
repository: string
|
||
] -> list {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/($repository)/tags/list"
|
||
} | complete)
|
||
|
||
if $result.exit_code != 0 {
|
||
return []
|
||
}
|
||
|
||
let tags = ($result.stdout | from json)
|
||
$tags.tags | default []
|
||
}
|
||
|
||
# Get manifest for image
|
||
export def get-oci-image-manifest [
|
||
registry_url: string
|
||
repository: string
|
||
tag: string
|
||
] -> record {
|
||
let result = (do {
|
||
http get $"http://($registry_url)/v2/($repository)/manifests/($tag)" --headers {
|
||
"Accept": "application/vnd.oci.image.manifest.v1+json"
|
||
}
|
||
} | complete)
|
||
|
||
if $result.exit_code != 0 {
|
||
return {}
|
||
}
|
||
|
||
$result.stdout | from json
|
||
}
|
||
|
||
# Delete image tag
|
||
export def delete-oci-image-tag [
|
||
registry_url: string
|
||
repository: string
|
||
tag: string
|
||
] -> bool {
|
||
# First get the manifest digest
|
||
let manifest_result = (do {
|
||
http get $"http://($registry_url)/v2/($repository)/manifests/($tag)" --headers {
|
||
"Accept": "application/vnd.oci.image.manifest.v1+json"
|
||
} --full
|
||
} | complete)
|
||
|
||
if $manifest_result.exit_code != 0 {
|
||
print $"ERROR: Failed to get manifest: ($manifest_result.stderr)"
|
||
return false
|
||
}
|
||
|
||
let manifest = ($manifest_result.stdout | from json)
|
||
let digest = ($manifest.headers | where name == "Docker-Content-Digest" | first | get value)
|
||
|
||
# Delete using digest
|
||
let delete_result = (do {
|
||
http delete $"http://($registry_url)/v2/($repository)/manifests/($digest)"
|
||
} | complete)
|
||
|
||
if $delete_result.exit_code == 0 {
|
||
print $"✅ Image ($repository):($tag) deleted"
|
||
return true
|
||
} else {
|
||
print $"ERROR: Failed to delete image: ($delete_result.stderr)"
|
||
return false
|
||
}
|
||
}
|
||
|
||
# Garbage collection (Zot)
|
||
export def run-oci-registry-gc [
|
||
registry_type: string = "zot"
|
||
] -> bool {
|
||
match $registry_type {
|
||
"zot" => {
|
||
# Zot runs GC automatically based on config
|
||
print "ℹ Zot runs garbage collection automatically"
|
||
print " Check config.json for GC settings"
|
||
return true
|
||
}
|
||
"distribution" => {
|
||
# Distribution requires manual GC
|
||
print "Running garbage collection..."
|
||
|
||
let registry_dir = get-registry-directory $registry_type
|
||
|
||
let result = (^docker-compose exec registry \
|
||
registry garbage-collect /etc/docker/registry/config.yml | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
print "✅ Garbage collection completed"
|
||
return true
|
||
} else {
|
||
print $"ERROR: GC failed: ($result.stderr)"
|
||
return false
|
||
}
|
||
}
|
||
"harbor" => {
|
||
print "ℹ Harbor runs GC via UI or API"
|
||
print " Use Harbor admin interface for GC"
|
||
return true
|
||
}
|
||
_ => {
|
||
print $"ERROR: Unknown registry type: ($registry_type)"
|
||
return false
|
||
}
|
||
}
|
||
}
|
||
|
||
# Get registry metrics (if available)
|
||
export def get-oci-registry-metrics [
|
||
registry_url: string
|
||
registry_type: string = "zot"
|
||
] -> string {
|
||
let metrics_url = match $registry_type {
|
||
"zot" => $"http://($registry_url)/metrics"
|
||
"distribution" => $"http://($registry_url):5001/metrics"
|
||
_ => null
|
||
}
|
||
|
||
if ($metrics_url | is-empty) {
|
||
return "Metrics not available for this registry type"
|
||
}
|
||
|
||
let result = (do {
|
||
http get $metrics_url
|
||
} | complete)
|
||
|
||
if $result.exit_code == 0 {
|
||
$result.stdout
|
||
} else {
|
||
$"ERROR: Failed to fetch metrics: ($result.stderr)"
|
||
}
|
||
}
|
||
|
||
# Helper: Get registry directory
|
||
def get-registry-directory [registry_type: string] -> string {
|
||
let config = (get-config)
|
||
let base_path = ($config | get paths.base)
|
||
$"($base_path)/provisioning/platform/oci-registry/($registry_type)"
|
||
}
|
||
|
||
# Push artifact to registry
|
||
export def push-oci-artifact [
|
||
registry_url: string
|
||
repository: string
|
||
tag: string
|
||
artifact_path: string
|
||
] -> bool {
|
||
if not ($artifact_path | path exists) {
|
||
print $"ERROR: Artifact not found: ($artifact_path)"
|
||
return false
|
||
}
|
||
|
||
# This would require oras or docker buildx
|
||
print "ℹ Use 'oras push' or 'docker push' to upload artifacts"
|
||
print $" Target: ($registry_url)/($repository):($tag)"
|
||
print $" Artifact: ($artifact_path)"
|
||
|
||
false
|
||
}
|
||
|
||
# Pull artifact from registry
|
||
export def pull-oci-artifact [
|
||
registry_url: string
|
||
repository: string
|
||
tag: string
|
||
output_path: string
|
||
] -> bool {
|
||
# This would require oras or docker pull
|
||
print "ℹ Use 'oras pull' or 'docker pull' to download artifacts"
|
||
print $" Source: ($registry_url)/($repository):($tag)"
|
||
print $" Output: ($output_path)"
|
||
|
||
false
|
||
}
|