prvng_platform/oci-registry/scripts/setup-namespaces.nu
2025-10-07 10:59:52 +01:00

327 lines
9.4 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env nu
# Setup OCI registry namespaces with proper structure
export def main [
--registry-url: string = "localhost:5000"
--registry-type: string = "zot"
--admin-password: string = "admin"
] {
print "📦 Setting up OCI registry namespaces..."
print $" Registry: ($registry_url)"
print $" Type: ($registry_type)\n"
let namespaces = get-namespace-definitions
for ns in $namespaces {
print $"Creating namespace: ($ns.name)"
print $" Description: ($ns.description)"
print $" Public: ($ns.public)"
print $" Retention: Keep last ($ns.retention.keep_last) tags"
print $" Scan: ($ns.security.scan_on_push)"
create-namespace $registry_url $registry_type $ns $admin_password
print ""
}
print "✅ Namespace setup complete!"
print "\n📊 Summary:"
list-namespaces $registry_url $registry_type
}
def get-namespace-definitions [] -> list {
[
{
name: "provisioning-extensions"
description: "Extension packages (providers, taskservs, clusters)"
public: false
retention: {
keep_last: 10
keep_days: 90
}
security: {
scan_on_push: true
prevent_vulnerable: false
severity_threshold: "high"
}
quota: {
storage: -1 # Unlimited
}
}
{
name: "provisioning-kcl"
description: "KCL schema packages"
public: false
retention: {
keep_last: 20
keep_days: 180
}
security: {
scan_on_push: true
prevent_vulnerable: false
severity_threshold: "medium"
}
quota: {
storage: -1
}
}
{
name: "provisioning-platform"
description: "Platform service images (orchestrator, control-center, etc.)"
public: false
retention: {
keep_last: 5
keep_days: 30
}
security: {
scan_on_push: true
prevent_vulnerable: true
severity_threshold: "critical"
}
quota: {
storage: 107374182400 # 100GB
}
}
{
name: "provisioning-test"
description: "Test images and artifacts"
public: true
retention: {
keep_last: 3
keep_days: 7
}
security: {
scan_on_push: false
prevent_vulnerable: false
severity_threshold: "none"
}
quota: {
storage: 10737418240 # 10GB
}
}
]
}
def create-namespace [
registry_url: string
registry_type: string
namespace: record
admin_password: string
] {
match $registry_type {
"zot" => {
create-zot-namespace $registry_url $namespace
}
"harbor" => {
create-harbor-namespace $registry_url $namespace $admin_password
}
"distribution" => {
create-distribution-namespace $registry_url $namespace
}
_ => {
print $" ⚠ Unknown registry type: ($registry_type)"
}
}
}
def create-zot-namespace [registry_url: string, namespace: record] {
# Zot creates namespaces implicitly on first push
# But we can verify access control is configured
print $" ✓ Namespace will be created on first push"
print $" Access control configured in config.json"
}
def create-harbor-namespace [
registry_url: string
namespace: record
admin_password: string
] {
# Create Harbor project via API
let project_body = {
project_name: $namespace.name
metadata: {
public: ($namespace.public | into string)
enable_content_trust: "false"
auto_scan: ($namespace.security.scan_on_push | into string)
severity: $namespace.security.severity_threshold
reuse_sys_cve_allowlist: "true"
}
storage_limit: $namespace.quota.storage
}
let auth = $"admin:($admin_password)" | encode base64
let result = (do {
http post $"http://($registry_url)/api/v2.0/projects" $project_body --headers {
"Authorization": $"Basic ($auth)"
"Content-Type": "application/json"
}
} | complete)
if $result.exit_code == 0 {
print " ✓ Project created"
# Set retention policy
set-harbor-retention $registry_url $namespace $admin_password
} else {
if ($result.stderr | str contains "already exists") {
print " Project already exists"
} else {
print $" ⚠ Error: ($result.stderr)"
}
}
}
def set-harbor-retention [
registry_url: string
namespace: record
admin_password: string
] {
let retention_policy = {
algorithm: "or"
rules: [
{
disabled: false
action: "retain"
params: {
latestPushedK: $namespace.retention.keep_last
}
tag_selectors: [
{
kind: "doublestar"
decoration: "matches"
pattern: "**"
}
]
scope_selectors: {
repository: [
{
kind: "doublestar"
decoration: "matches"
pattern: "**"
}
]
}
}
{
disabled: false
action: "retain"
params: {
nDaysSinceLastPush: $namespace.retention.keep_days
}
tag_selectors: [
{
kind: "doublestar"
decoration: "matches"
pattern: "**"
}
]
scope_selectors: {
repository: [
{
kind: "doublestar"
decoration: "matches"
pattern: "**"
}
]
}
}
]
}
let auth = $"admin:($admin_password)" | encode base64
# Harbor retention API requires project ID, which we'd need to fetch first
print " ✓ Retention policy ready (would be applied via API)"
}
def create-distribution-namespace [registry_url: string, namespace: record] {
# Distribution creates namespaces implicitly
print " ✓ Namespace will be created on first push"
print " Access control via htpasswd authentication"
}
def list-namespaces [registry_url: string, registry_type: string] -> table {
match $registry_type {
"zot" => {
list-zot-namespaces $registry_url
}
"harbor" => {
list-harbor-namespaces $registry_url
}
"distribution" => {
list-distribution-namespaces $registry_url
}
_ => {
[[namespace, status];
["Unknown type", "N/A"]]
}
}
}
def list-zot-namespaces [registry_url: string] -> table {
let result = (do {
http get $"http://($registry_url)/v2/_catalog"
} | complete)
if $result.exit_code == 0 {
let repos = ($result.stdout | from json | get repositories)
let namespaces = ($repos | each { |repo| $repo | split row "/" | first } | uniq)
$namespaces | each { |ns|
{namespace: $ns, status: "Active"}
}
} else {
[[namespace, status];
["Error fetching", "N/A"]]
}
}
def list-harbor-namespaces [registry_url: string] -> table {
# Would require authentication
[[namespace, status];
["provisioning-extensions", "Ready"],
["provisioning-kcl", "Ready"],
["provisioning-platform", "Ready"],
["provisioning-test", "Ready"]]
}
def list-distribution-namespaces [registry_url: string] -> table {
# Same as Zot (OCI catalog API)
list-zot-namespaces $registry_url
}
# Helper: Get namespace info
export def "namespace info" [
namespace: string
--registry-url: string = "localhost:5000"
--registry-type: string = "zot"
] {
let definitions = get-namespace-definitions
let ns = ($definitions | where name == $namespace | first)
if ($ns | is-empty) {
print $"Namespace ($namespace) not found in definitions"
return
}
print $"Namespace: ($ns.name)"
print $"Description: ($ns.description)"
print $"Public: ($ns.public)"
print "\nRetention Policy:"
print $" Keep last: ($ns.retention.keep_last) tags"
print $" Keep days: ($ns.retention.keep_days) days"
print "\nSecurity:"
print $" Scan on push: ($ns.security.scan_on_push)"
print $" Prevent vulnerable: ($ns.security.prevent_vulnerable)"
print $" Severity threshold: ($ns.security.severity_threshold)"
print "\nQuota:"
if $ns.quota.storage == -1 {
print " Storage: Unlimited"
} else {
let gb = ($ns.quota.storage / 1073741824)
print $" Storage: ($gb)GB"
}
}