provisioning/docs/src/api-reference/path-resolution.md
2026-01-14 04:59:11 +00:00

16 KiB

Path Resolution API

This document describes the path resolution system used throughout the provisioning infrastructure for discovering configurations, extensions, and resolving workspace paths.

Overview

The path resolution system provides a hierarchical and configurable mechanism for:

  • Configuration file discovery and loading
  • Extension discovery (providers, task services, clusters)
  • Workspace and project path management
  • Environment variable interpolation
  • Cross-platform path handling

Configuration Resolution Hierarchy

The system follows a specific hierarchy for loading configuration files:

1. System defaults      (config.defaults.toml)
2. User configuration   (config.user.toml)
3. Project configuration (config.project.toml)
4. Infrastructure config (infra/config.toml)
5. Environment config   (config.{env}.toml)
6. Runtime overrides    (CLI arguments, ENV vars)

Configuration Search Paths

The system searches for configuration files in these locations:

# Default search paths (in order)
/usr/local/provisioning/config.defaults.toml
$HOME/.config/provisioning/config.user.toml
$PWD/config.project.toml
$PROVISIONING_KLOUD_PATH/config.infra.toml
$PWD/config.{PROVISIONING_ENV}.toml

Path Resolution API

Core Functions

resolve-config-path(pattern: string, search_paths: list<string>) -> string

Resolves configuration file paths using the search hierarchy.

Parameters:

  • pattern: File pattern to search for (for example, "config.*.toml")
  • search_paths: Additional paths to search (optional)

Returns:

  • Full path to the first matching configuration file
  • Empty string if no file found

Example:

use path-resolution.nu *
let config_path = (resolve-config-path "config.user.toml" [])
# Returns: "/home/user/.config/provisioning/config.user.toml"

resolve-extension-path(type: string, name: string) -> record

Discovers extension paths (providers, taskservs, clusters).

Parameters:

  • type: Extension type ("provider", "taskserv", "cluster")
  • name: Extension name (for example, "upcloud", "kubernetes", "buildkit")

Returns:

{
    base_path: "/usr/local/provisioning/providers/upcloud",
    schemas_path: "/usr/local/provisioning/providers/upcloud/schemas",
    nulib_path: "/usr/local/provisioning/providers/upcloud/nulib",
    templates_path: "/usr/local/provisioning/providers/upcloud/templates",
    exists: true
}

resolve-workspace-paths() -> record

Gets current workspace path configuration.

Returns:

{
    base: "/usr/local/provisioning",
    current_infra: "/workspace/infra/production",
    kloud_path: "/workspace/kloud",
    providers: "/usr/local/provisioning/providers",
    taskservs: "/usr/local/provisioning/taskservs",
    clusters: "/usr/local/provisioning/cluster",
    extensions: "/workspace/extensions"
}

Path Interpolation

The system supports variable interpolation in configuration paths:

Supported Variables

  • {{paths.base}} - Base provisioning path
  • {{paths.kloud}} - Current kloud path
  • {{env.HOME}} - User home directory
  • {{env.PWD}} - Current working directory
  • {{now.date}} - Current date (YYYY-MM-DD)
  • {{now.time}} - Current time (HH:MM:SS)
  • {{git.branch}} - Current git branch
  • {{git.commit}} - Current git commit hash

interpolate-path(template: string, context: record) -> string

Interpolates variables in path templates.

Parameters:

  • template: Path template with variables
  • context: Variable context record

Example:

let template = "{{paths.base}}/infra/{{env.USER}}/{{git.branch}}"
let result = (interpolate-path $template {
    paths: { base: "/usr/local/provisioning" },
    env: { USER: "admin" },
    git: { branch: "main" }
})
# Returns: "/usr/local/provisioning/infra/admin/main"

Extension Discovery API

Provider Discovery

discover-providers() -> list<record>

Discovers all available providers.

Returns:

[
    {
        name: "upcloud",
        path: "/usr/local/provisioning/providers/upcloud",
        type: "provider",
        version: "1.2.0",
        enabled: true,
        has_schemas: true,
        has_nulib: true,
        has_templates: true
    },
    {
        name: "aws",
        path: "/usr/local/provisioning/providers/aws",
        type: "provider",
        version: "2.1.0",
        enabled: true,
        has_schemas: true,
        has_nulib: true,
        has_templates: true
    }
]

get-provider-config(name: string) -> record

Gets provider-specific configuration and paths.

Parameters:

  • name: Provider name

Returns:

{
    name: "upcloud",
    base_path: "/usr/local/provisioning/providers/upcloud",
    config: {
        api_url: "https://api.upcloud.com/1.3",
        auth_method: "basic",
        interface: "API"
    },
    paths: {
        schemas: "/usr/local/provisioning/providers/upcloud/schemas",
        nulib: "/usr/local/provisioning/providers/upcloud/nulib",
        templates: "/usr/local/provisioning/providers/upcloud/templates"
    },
    metadata: {
        version: "1.2.0",
        description: "UpCloud provider for server provisioning"
    }
}

Task Service Discovery

discover-taskservs() -> list<record>

Discovers all available task services.

Returns:

[
    {
        name: "kubernetes",
        path: "/usr/local/provisioning/taskservs/kubernetes",
        type: "taskserv",
        category: "orchestration",
        version: "1.28.0",
        enabled: true
    },
    {
        name: "cilium",
        path: "/usr/local/provisioning/taskservs/cilium",
        type: "taskserv",
        category: "networking",
        version: "1.14.0",
        enabled: true
    }
]

get-taskserv-config(name: string) -> record

Gets task service configuration and version information.

Parameters:

  • name: Task service name

Returns:

{
    name: "kubernetes",
    path: "/usr/local/provisioning/taskservs/kubernetes",
    version: {
        current: "1.28.0",
        available: "1.28.2",
        update_available: true,
        source: "github",
        release_url: "https://github.com/kubernetes/kubernetes/releases"
    },
    config: {
        category: "orchestration",
        dependencies: ["containerd"],
        supports_versions: ["1.26.x", "1.27.x", "1.28.x"]
    }
}

Cluster Discovery

discover-clusters() -> list<record>

Discovers all available cluster configurations.

Returns:

[
    {
        name: "buildkit",
        path: "/usr/local/provisioning/cluster/buildkit",
        type: "cluster",
        category: "build",
        components: ["buildkit", "registry", "storage"],
        enabled: true
    }
]

Environment Management API

Environment Detection

detect-environment() -> string

Automatically detects the current environment based on:

  1. PROVISIONING_ENV environment variable
  2. Git branch patterns (main → prod, develop → dev, etc.)
  3. Directory structure analysis
  4. Configuration file presence

Returns:

  • Environment name string (dev, test, prod, etc.)

get-environment-config(env: string) -> record

Gets environment-specific configuration.

Parameters:

  • env: Environment name

Returns:

{
    name: "production",
    paths: {
        base: "/opt/provisioning",
        kloud: "/data/kloud",
        logs: "/var/log/provisioning"
    },
    providers: {
        default: "upcloud",
        allowed: ["upcloud", "aws"]
    },
    features: {
        debug: false,
        telemetry: true,
        rollback: true
    }
}

Environment Switching

switch-environment(env: string, validate: bool = true) -> null

Switches to a different environment and updates path resolution.

Parameters:

  • env: Target environment name
  • validate: Whether to validate environment configuration

Effects:

  • Updates PROVISIONING_ENV environment variable
  • Reconfigures path resolution for new environment
  • Validates environment configuration if requested

Workspace Management API

Workspace Discovery

discover-workspaces() -> list<record>

Discovers available workspaces and infrastructure directories.

Returns:

[
    {
        name: "production",
        path: "/workspace/infra/production",
        type: "infrastructure",
        provider: "upcloud",
        settings: "settings.ncl",
        valid: true
    },
    {
        name: "development",
        path: "/workspace/infra/development",
        type: "infrastructure",
        provider: "local",
        settings: "dev-settings.ncl",
        valid: true
    }
]

set-current-workspace(path: string) -> null

Sets the current workspace for path resolution.

Parameters:

  • path: Workspace directory path

Effects:

  • Updates CURRENT_INFRA_PATH environment variable
  • Reconfigures workspace-relative path resolution

Project Structure Analysis

analyze-project-structure(path: string = $PWD) -> record

Analyzes project structure and identifies components.

Parameters:

  • path: Project root path (defaults to current directory)

Returns:

{
    root: "/workspace/project",
    type: "provisioning_workspace",
    components: {
        providers: [
            { name: "upcloud", path: "providers/upcloud" },
            { name: "aws", path: "providers/aws" }
        ],
        taskservs: [
            { name: "kubernetes", path: "taskservs/kubernetes" },
            { name: "cilium", path: "taskservs/cilium" }
        ],
        clusters: [
            { name: "buildkit", path: "cluster/buildkit" }
        ],
        infrastructure: [
            { name: "production", path: "infra/production" },
            { name: "staging", path: "infra/staging" }
        ]
    },
    config_files: [
        "config.defaults.toml",
        "config.user.toml",
        "config.prod.toml"
    ]
}

Caching and Performance

Path Caching

The path resolution system includes intelligent caching:

cache-paths(duration: duration = 5 min) -> null

Enables path caching for the specified duration.

Parameters:

  • duration: Cache validity duration

invalidate-path-cache() -> null

Invalidates the path resolution cache.

get-cache-stats() -> record

Gets path resolution cache statistics.

Returns:

{
    enabled: true,
    size: 150,
    hit_rate: 0.85,
    last_invalidated: "2025-09-26T10:00:00Z"
}

Cross-Platform Compatibility

Path Normalization

normalize-path(path: string) -> string

Normalizes paths for cross-platform compatibility.

Parameters:

  • path: Input path (may contain mixed separators)

Returns:

  • Normalized path using platform-appropriate separators

Example:

# On Windows
normalize-path "path/to/file" # Returns: "path\to\file"

# On Unix
normalize-path "path\to\file" # Returns: "path/to/file"

join-paths(segments: list<string>) -> string

Safely joins path segments using platform separators.

Parameters:

  • segments: List of path segments

Returns:

  • Joined path string

Configuration Validation API

Path Validation

validate-paths(config: record) -> record

Validates all paths in configuration.

Parameters:

  • config: Configuration record

Returns:

{
    valid: true,
    errors: [],
    warnings: [
        { path: "paths.extensions", message: "Path does not exist" }
    ],
    checks_performed: 15
}

validate-extension-structure(type: string, path: string) -> record

Validates extension directory structure.

Parameters:

  • type: Extension type (provider, taskserv, cluster)
  • path: Extension base path

Returns:

{
    valid: true,
    required_files: [
        { file: "manifest.toml", exists: true },
        { file: "schemas/main.ncl", exists: true },
        { file: "nulib/mod.nu", exists: true }
    ],
    optional_files: [
        { file: "templates/server.j2", exists: false }
    ]
}

Command-Line Interface

Path Resolution Commands

The path resolution API is exposed via Nushell commands:

# Show current path configuration
provisioning show paths

# Discover available extensions
provisioning discover providers
provisioning discover taskservs
provisioning discover clusters

# Validate path configuration
provisioning validate paths

# Switch environments
provisioning env switch prod

# Set workspace
provisioning workspace set /path/to/infra

Integration Examples

Python Integration

import subprocess
import json

class PathResolver:
    def __init__(self, provisioning_path="/usr/local/bin/provisioning"):
        self.cmd = provisioning_path

    def get_paths(self):
        result = subprocess.run([
            "nu", "-c", f"use {self.cmd} *; show-config --section=paths --format=json"
        ], capture_output=True, text=True)
        return json.loads(result.stdout)

    def discover_providers(self):
        result = subprocess.run([
            "nu", "-c", f"use {self.cmd} *; discover providers --format=json"
        ], capture_output=True, text=True)
        return json.loads(result.stdout)

# Usage
resolver = PathResolver()
paths = resolver.get_paths()
providers = resolver.discover_providers()

JavaScript/Node.js Integration

const { exec } = require('child_process');
const util = require('util');
const execAsync = util.promisify(exec);

class PathResolver {
  constructor(provisioningPath = '/usr/local/bin/provisioning') {
    this.cmd = provisioningPath;
  }

  async getPaths() {
    const { stdout } = await execAsync(
      `nu -c "use ${this.cmd} *; show-config --section=paths --format=json"`
    );
    return JSON.parse(stdout);
  }

  async discoverExtensions(type) {
    const { stdout } = await execAsync(
      `nu -c "use ${this.cmd} *; discover ${type} --format=json"`
    );
    return JSON.parse(stdout);
  }
}

// Usage
const resolver = new PathResolver();
const paths = await resolver.getPaths();
const providers = await resolver.discoverExtensions('providers');

Error Handling

Common Error Scenarios

  1. Configuration File Not Found

    Error: Configuration file not found in search paths
    Searched: ["/usr/local/provisioning/config.defaults.toml", ...]
    
  2. Extension Not Found

    Error: Provider 'missing-provider' not found
    Available providers: ["upcloud", "aws", "local"]
    
  3. Invalid Path Template

    Error: Invalid template variable: {{invalid.var}}
    Valid variables: ["paths.*", "env.*", "now.*", "git.*"]
    
  4. Environment Not Found

    Error: Environment 'staging' not configured
    Available environments: ["dev", "test", "prod"]
    

Error Recovery

The system provides graceful fallbacks:

  • Missing configuration files use system defaults
  • Invalid paths fall back to safe defaults
  • Extension discovery continues if some paths are inaccessible
  • Environment detection falls back to 'local' if detection fails

Performance Considerations

Best Practices

  1. Use Path Caching: Enable caching for frequently accessed paths
  2. Batch Discovery: Discover all extensions at once rather than individually
  3. Lazy Loading: Load extension configurations only when needed
  4. Environment Detection: Cache environment detection results

Monitoring

Monitor path resolution performance:

# Get resolution statistics
provisioning debug path-stats

# Monitor cache performance
provisioning debug cache-stats

# Profile path resolution
provisioning debug profile-paths

Security Considerations

Path Traversal Protection

The system includes protections against path traversal attacks:

  • All paths are normalized and validated
  • Relative paths are resolved within safe boundaries
  • Symlinks are validated before following

Access Control

Path resolution respects file system permissions:

  • Configuration files require read access
  • Extension directories require read/execute access
  • Workspace directories may require write access for operations

This path resolution API provides a comprehensive and flexible system for managing the complex path requirements of multi-provider, multi-environment infrastructure provisioning.