Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Taskserv Developer Guide

Overview

This guide covers how to develop, create, and maintain taskservs in the provisioning system. Taskservs are reusable infrastructure components that can be deployed across different cloud providers and environments.

Architecture Overview

Layered System

The provisioning system uses a 3-layer architecture for taskservs:

  1. Layer 1 (Core): provisioning/extensions/taskservs/{category}/{name} - Base taskserv definitions
  2. Layer 2 (Workspace): provisioning/workspace/templates/taskservs/{category}/{name}.k - Template configurations
  3. Layer 3 (Infrastructure): workspace/infra/{infra}/task-servs/{name}.k - Infrastructure-specific overrides

Resolution Order

The system resolves taskservs in this priority order:

  • Infrastructure layer (highest priority) - specific to your infrastructure
  • Workspace layer (medium priority) - templates and patterns
  • Core layer (lowest priority) - base extensions

Taskserv Structure

Standard Directory Layout

provisioning/extensions/taskservs/{category}/{name}/
├── kcl/                    # KCL configuration
│   ├── kcl.mod            # Module definition
│   ├── {name}.k           # Main schema
│   ├── version.k          # Version information
│   └── dependencies.k     # Dependencies (optional)
├── default/               # Default configurations
│   ├── defs.toml          # Default values
│   └── install-{name}.sh  # Installation script
├── README.md              # Documentation
└── info.md               # Metadata

Categories

Taskservs are organized into these categories:

  • container-runtime: containerd, crio, crun, podman, runc, youki
  • databases: postgres, redis
  • development: coder, desktop, gitea, nushell, oras, radicle
  • infrastructure: kms, os, provisioning, webhook, kubectl, polkadot
  • kubernetes: kubernetes (main orchestration)
  • networking: cilium, coredns, etcd, ip-aliases, proxy, resolv
  • storage: external-nfs, mayastor, oci-reg, rook-ceph

Creating New Taskservs

Method 1: Using the Extension Creation Tool

# Create a new taskserv interactively
nu provisioning/tools/create-extension.nu interactive

# Create directly with parameters
nu provisioning/tools/create-extension.nu taskserv my-service \
  --template basic \
  --author "Your Name" \
  --description "My service description" \
  --output provisioning/extensions

Method 2: Manual Creation

  1. Choose a category and create the directory structure:
mkdir -p provisioning/extensions/taskservs/{category}/{name}/kcl
mkdir -p provisioning/extensions/taskservs/{category}/{name}/default
  1. Create the KCL module definition (kcl/kcl.mod):
[package]
name = "my-service"
version = "1.0.0"
description = "Service description"

[dependencies]
k8s = { oci = "oci://ghcr.io/kcl-lang/k8s", tag = "1.30" }
  1. Create the main KCL schema (kcl/my-service.k):
# My Service Configuration
schema MyService {
    # Service metadata
    name: str = "my-service"
    version: str = "latest"
    namespace: str = "default"

    # Service configuration
    replicas: int = 1
    port: int = 8080

    # Resource requirements
    cpu: str = "100m"
    memory: str = "128Mi"

    # Additional configuration
    config?: {str: any} = {}
}

# Default configuration
my_service_config: MyService = MyService {
    name = "my-service"
    version = "latest"
    replicas = 1
    port = 8080
}
  1. Create version information (kcl/version.k):
# Version information for my-service taskserv
schema MyServiceVersion {
    current: str = "1.0.0"
    compatible: [str] = ["1.0.0"]
    deprecated?: [str] = []
}

my_service_version: MyServiceVersion = MyServiceVersion {}
  1. Create default configuration (default/defs.toml):
[service]
name = "my-service"
version = "latest"
port = 8080

[deployment]
replicas = 1
strategy = "RollingUpdate"

[resources]
cpu_request = "100m"
cpu_limit = "500m"
memory_request = "128Mi"
memory_limit = "512Mi"
  1. Create installation script (default/install-my-service.sh):
#!/bin/bash
set -euo pipefail

# My Service Installation Script
echo "Installing my-service..."

# Configuration
SERVICE_NAME="${SERVICE_NAME:-my-service}"
SERVICE_VERSION="${SERVICE_VERSION:-latest}"
NAMESPACE="${NAMESPACE:-default}"

# Install service
kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -

# Apply configuration
envsubst < my-service-deployment.yaml | kubectl apply -f -

echo "✅ my-service installed successfully"

Working with Templates

Creating Workspace Templates

Templates provide reusable configurations that can be customized per infrastructure:

# Create template directory
mkdir -p provisioning/workspace/templates/taskservs/{category}

# Create template file
cat > provisioning/workspace/templates/taskservs/{category}/{name}.k << 'EOF'
# Template for {name} taskserv
import taskservs.{category}.{name}.kcl.{name} as base

# Template configuration extending base
{name}_template: base.{Name} = base.{name}_config {
    # Template customizations
    version = "stable"
    replicas = 2  # Production default

    # Environment-specific overrides will be applied at infrastructure layer
}
EOF

Infrastructure Overrides

Create infrastructure-specific configurations:

# Create infrastructure override
mkdir -p workspace/infra/{your-infra}/task-servs

cat > workspace/infra/{your-infra}/task-servs/{name}.k << 'EOF'
# Infrastructure-specific configuration for {name}
import provisioning.workspace.templates.taskservs.{category}.{name} as template

# Infrastructure customizations
{name}_config: template.{name}_template {
    # Override for this specific infrastructure
    version = "1.2.3"  # Pin to specific version
    replicas = 3       # Scale for this environment

    # Infrastructure-specific settings
    resources = {
        cpu = "200m"
        memory = "256Mi"
    }
}
EOF

CLI Commands

Taskserv Management

# Create taskserv (deploy to infrastructure)
provisioning/core/cli/provisioning taskserv create {name} --infra {infra-name} --check

# Generate taskserv configuration
provisioning/core/cli/provisioning taskserv generate {name} --infra {infra-name}

# Delete taskserv
provisioning/core/cli/provisioning taskserv delete {name} --infra {infra-name} --check

# List available taskservs
nu -c "use provisioning/core/nulib/taskservs/discover.nu *; discover-taskservs"

# Check taskserv versions
provisioning/core/cli/provisioning taskserv versions {name}
provisioning/core/cli/provisioning taskserv check-updates {name}

Discovery and Testing

# Test layer resolution for a taskserv
nu -c "use provisioning/workspace/tools/layer-utils.nu *; test_layer_resolution {name} {infra} {provider}"

# Show layer statistics
nu -c "use provisioning/workspace/tools/layer-utils.nu *; show_layer_stats"

# Get taskserv information
nu -c "use provisioning/core/nulib/taskservs/discover.nu *; get-taskserv-info {name}"

# Search taskservs
nu -c "use provisioning/core/nulib/taskservs/discover.nu *; search-taskservs {query}"

Best Practices

1. Naming Conventions

  • Use kebab-case for taskserv names: my-service, data-processor
  • Use descriptive names that indicate the service purpose
  • Avoid generic names like service, app, tool

2. Configuration Design

  • Define sensible defaults in the base schema
  • Make configurations parameterizable through variables
  • Support multi-environment deployment (dev, test, prod)
  • Include resource limits and requests

3. Dependencies

  • Declare all dependencies explicitly in kcl.mod
  • Use version constraints to ensure compatibility
  • Consider dependency order for installation

4. Documentation

  • Provide comprehensive README.md with usage examples
  • Document all configuration options
  • Include troubleshooting sections
  • Add version compatibility information

5. Testing

  • Test taskservs across different providers (AWS, UpCloud, local)
  • Validate with --check flag before deployment
  • Test layer resolution to ensure proper override behavior
  • Verify dependency resolution works correctly

Troubleshooting

Common Issues

  1. Taskserv not discovered

    • Ensure kcl/kcl.mod exists and is valid TOML
    • Check directory structure matches expected layout
    • Verify taskserv is in correct category folder
  2. Layer resolution not working

    • Use test_layer_resolution tool to debug
    • Check file paths and naming conventions
    • Verify import statements in KCL files
  3. Dependency resolution errors

    • Check kcl.mod dependencies section
    • Ensure dependency versions are compatible
    • Verify dependency taskservs exist and are discoverable
  4. Configuration validation failures

    • Use kcl check to validate KCL syntax
    • Check for missing required fields
    • Verify data types match schema definitions

Debug Commands

# Enable debug mode for taskserv operations
provisioning/core/cli/provisioning taskserv create {name} --debug --check

# Check KCL syntax
kcl check provisioning/extensions/taskservs/{category}/{name}/kcl/{name}.k

# Validate taskserv structure
nu provisioning/tools/create-extension.nu validate provisioning/extensions/taskservs/{category}/{name}

# Show detailed discovery information
nu -c "use provisioning/core/nulib/taskservs/discover.nu *; discover-taskservs | where name == '{name}'"

Contributing

Pull Request Guidelines

  1. Follow the standard directory structure
  2. Include comprehensive documentation
  3. Add tests and validation
  4. Update category documentation if adding new categories
  5. Ensure backward compatibility

Review Checklist

  • Proper directory structure and naming
  • Valid KCL schemas with appropriate types
  • Comprehensive README documentation
  • Working installation scripts
  • Proper dependency declarations
  • Template configurations (if applicable)
  • Layer resolution testing

Advanced Topics

Custom Categories

To add new taskserv categories:

  1. Create the category directory structure
  2. Update the discovery system if needed
  3. Add category documentation
  4. Create initial taskservs for the category
  5. Add category templates if applicable

Cross-Provider Compatibility

Design taskservs to work across multiple providers:

schema MyService {
    # Provider-agnostic configuration
    name: str
    version: str

    # Provider-specific sections
    aws?: AWSConfig
    upcloud?: UpCloudConfig
    local?: LocalConfig
}

Advanced Dependencies

Handle complex dependency scenarios:

# Conditional dependencies
schema MyService {
    database_type: "postgres" | "mysql" | "redis"

    # Dependencies based on configuration
    if database_type == "postgres":
        postgres_config: PostgresConfig
    elif database_type == "redis":
        redis_config: RedisConfig
}

This guide provides comprehensive coverage of taskserv development. For specific examples, see the existing taskservs in provisioning/extensions/taskservs/ and their corresponding templates in provisioning/workspace/templates/taskservs/.