Skip to main content

CLI tool for deploying software to remote and local servers via SSH/SFTP.

Project description

ikctl — Install Kit Control

CLI tool to deploy and execute bash scripts ("kits") on remote servers via SSH/SFTP or on the local machine. Supports parallel execution, DAG-based pipeline orchestration, and git-based kit repositories.

How it works

A kit is a folder containing bash scripts and an ikctl.yaml manifest. ikctl uploads the scripts to the remote server via SFTP and executes them over SSH.

A pipeline is a YAML file that chains multiple kits across different server groups, with dependencies, parallel execution and output passing between steps.

Everything is driven by ~/.ikctl/config, which defines one or more contexts (server groups, kits source, secrets).

~/.ikctl/config          ← main config: contexts, active context
~/kits/
  config.yaml            ← server groups
  show-date/
    ikctl.yaml           ← kit manifest (uploads + pipeline + outputs)
    date.sh              ← the actual script
~/kits/pipelines/
  deploy.yaml            ← pipeline YAML

Kits are auto-discovered — no index file needed. Any folder under path_kits that contains an ikctl.yaml is a kit.

Requirements

  • Python 3.13+
  • git (for git-based kit repositories)

Installation

Recommended — pipx (isolated, no system conflicts):

pipx install ikctl

With uv:

uv tool install ikctl

With pip (on Debian/Ubuntu you may need --break-system-packages):

pip install ikctl --break-system-packages

From source:

git clone <repo>
cd ikctl
uv sync
uv run ikctl --version

Initial setup

On first run, ikctl creates ~/.ikctl/ and ~/kits/ automatically.

Minimal ~/.ikctl/config:

context: production
contexts:
  production:
    path_kits: ~/kits               # where your kits live (auto-discovered)
    path_servers: ~/kits            # where config.yaml lives
    path_secrets: ~/.passwords/pw   # file containing the sudo/ssh password
    path_pipelines: ~/kits/pipelines # optional: pipelines directory
    mode: remote
    timeout_connect: 30.0           # SSH connect timeout (seconds)
    timeout_exec: 120.0             # local command timeout (seconds)
    exclude:                        # optional: kits to hide from discovery
      - internal/debug-kit

Git-based kits (optional)

Pull kits from a git repository instead of a local directory:

contexts:
  production:
    kits_repo: git@gitlab.com:company/kits.git   # SSH repo
    kits_ref: main                                # branch, tag or commit
    # kits_token: $GITLAB_TOKEN                  # for private HTTPS repos
    path_servers: ~/kits/production
    path_secrets: ~/.passwords/password
    mode: remote

For private HTTPS repos:

    kits_repo: https://gitlab.com/company/kits.git
    kits_token: $GITLAB_TOKEN    # references an env variable
export GITLAB_TOKEN=glpat-xxxxxxxxxxxx
ikctl --list kits   # clones on first use, pulls on subsequent runs

Server config

# ~/kits/config.yaml
servers:
  - name: workers
    user: ubuntu
    hosts: [10.0.0.10, 10.0.0.11, 10.0.0.12]
    port: 22
    pkey: ~/.ssh/id_ed25519        # key-based auth

  - name: master
    user: ubuntu
    hosts: [10.0.0.5]
    port: 22
    pkey: ~/.ssh/id_ed25519

  - name: db
    user: root
    hosts: [10.0.0.20]
    port: 22
    password: $PASSWORD             # password auth (env var)

SSH authentication

Config key Auth method Notes
pkey: ~/.ssh/id_ed25519 Public key only Ed25519, ECDSA or RSA
password: $PASSWORD Password only
Neither SSH agent + ~/.ssh/ discovery

pkey and password are mutually exclusive — only one is attempted.

Kit structure

# ~/kits/kubeadm-init/ikctl.yaml
kits:
  uploads:
    - kubeadm-init.sh     # files to upload to the remote server
  pipeline:
    - kubeadm-init.sh     # scripts to execute in order
  outputs:                # optional: documents KEY=VALUE the script emits
    JOIN_TOKEN: "kubeadm join token for worker nodes"
    JOIN_ENDPOINT: "API server endpoint (IP:6443)"

The outputs: field documents what KEY=VALUE lines the script writes to stdout. These values are available to subsequent pipeline steps via {{ steps.<id>.KEY }}.

Usage

ikctl [-l {kits,servers,context,mode,pipelines}] [-i INSTALL] [-n NAME]
      [-p [PARAM ...]] [-s {sudo}] [-c CONTEXT] [-m {local,remote}]
      [-v] [--dry-run] [--debug] [--describe KIT]
      [--pipeline FILE] [--timeout-connect F] [--timeout-exec F]
      [--parallel-workers N]

List

ikctl --list kits       # all discovered kits (shows declared outputs)
ikctl --list servers    # configured server groups
ikctl --list context    # active context and all paths
ikctl --list pipelines  # pipeline YAML files in path_pipelines

Inspect a kit

ikctl --describe kubeadm-init

Shows the kit's scripts and declared outputs:

╭─ Kit ───────────────╮
│  kubeadm-init       │
╰─────────────────────╯
Uploads:  kubeadm-init.sh
Pipeline: kubeadm-init.sh
Outputs:
  JOIN_TOKEN    → kubeadm join token for worker nodes
  JOIN_ENDPOINT → API server endpoint (IP:6443)

Switch context

ikctl --context staging

Run a kit

# Remote (default)
ikctl --install show-date --name workers

# With parameters passed to the script
ikctl --install deploy --name workers -p v2.1.0

# With sudo
ikctl --install install-docker --name workers --sudo sudo

# Local machine (no SSH)
ikctl --install show-date --mode local

# Preview without executing
ikctl --install deploy --name workers -p v2.1.0 --dry-run

Parallel execution

When a server group has multiple hosts, ikctl runs them concurrently:

ikctl --install show-date --name workers --parallel-workers 4

A spinner appears while connecting to each host and a progress bar during uploads. Output is prefixed with the host IP.

Pipeline orchestration

A pipeline chains kits across server groups with DAG dependencies and output passing:

# ~/kits/pipelines/install-kubernetes.yaml
name: install-kubernetes

steps:
  - id: prepare
    kit: packages
    servers: all-nodes
    sudo: true

  - id: init-master
    kit: kubeadm-init
    servers: master
    sudo: true
    needs: [prepare]
    params:
      - "{{ params.POD_CIDR }}"      # from CLI: -p POD_CIDR=192.168.0.0/16

  - id: join-workers
    kit: join-in-kubes
    servers: workers
    sudo: true
    needs: [init-master]
    params:
      - "{{ steps.init-master.JOIN_TOKEN }}"    # output from previous step
      - "{{ steps.init-master.JOIN_ENDPOINT }}" # output from previous step
# Run pipeline by name (requires path_pipelines in config)
ikctl --pipeline install-kubernetes -p POD_CIDR=192.168.0.0/16

# Or by full path
ikctl --pipeline ~/kits/pipelines/install-kubernetes.yaml -p POD_CIDR=192.168.0.0/16

# Preview
ikctl --pipeline install-kubernetes -p POD_CIDR=192.168.0.0/16 --dry-run

Steps without needs run in parallel. Steps fail gracefully — dependents are marked as skipped.

Debug mode

# Show all internal logs (paramiko included)
ikctl --install show-date --name workers --debug

Without --debug, only useful output is shown (Rich formatted).

Timeouts

ikctl --install show-date --name workers --timeout-connect 60
ikctl --install build --mode local --timeout-exec 300

Or set per context in ~/.ikctl/config with timeout_connect and timeout_exec.

License

Apache License 2.0 — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ikctl-1.4.2.tar.gz (156.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ikctl-1.4.2-py3-none-any.whl (47.3 kB view details)

Uploaded Python 3

File details

Details for the file ikctl-1.4.2.tar.gz.

File metadata

  • Download URL: ikctl-1.4.2.tar.gz
  • Upload date:
  • Size: 156.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ikctl-1.4.2.tar.gz
Algorithm Hash digest
SHA256 845e27f692992c20042835bd9ed6d952dcde0f557d53793a421861b5304f80bc
MD5 e982f1e6d96657300d10bd862b7416c6
BLAKE2b-256 222b9defa0148ad97c27fc4aea3efbdffdeaff2684cef457c5a0a7daf3efd6fb

See more details on using hashes here.

File details

Details for the file ikctl-1.4.2-py3-none-any.whl.

File metadata

  • Download URL: ikctl-1.4.2-py3-none-any.whl
  • Upload date:
  • Size: 47.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ikctl-1.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 002e21c402bbf54fe7e2de011f8b2411e5ba6711b33173ccb3cea597b90043a1
MD5 ae287e263a09535dee5b3d9f4a6d625b
BLAKE2b-256 ee956f22b6d9f64b2db87e325610a6e348869766bf4d9a4fcedd5af42e840764

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page