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.5.1.tar.gz (155.9 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.5.1-py3-none-any.whl (47.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ikctl-1.5.1.tar.gz
  • Upload date:
  • Size: 155.9 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.5.1.tar.gz
Algorithm Hash digest
SHA256 2a062552ddad1803da51d7e9fe0ee71c78f2fa3b74fb43ea8bb2347885ae4e6b
MD5 8e479886c679c5bd56c1ce81969cc968
BLAKE2b-256 36cca3fb3c79454ae57b32acf3f9adfd44ee3b70cf10cdd949501e005e82d9dd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ikctl-1.5.1-py3-none-any.whl
  • Upload date:
  • Size: 47.2 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.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6f01d1cae85435b5d0d8acb8df1c4f8a4151268b9462cf38a0079e2487f2d766
MD5 ca4cb4d3ff385467dcf73851bf37a45d
BLAKE2b-256 6657d07e4de1fac643901bc1818e552ffd4dc42121fbcaba094b04165a6ad34e

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