- CLAUDE.md: fix module count (174→41+3), KnownModules count (68→80), update error handling convention to reflect coreerr.E() migration - cmd/ansible: replace fmt.Errorf with coreerr.E(), os.Stat with coreio.Local.Exists()/IsDir(), os.Getwd with filepath.Abs() - Add 38 tests for untested critical paths: non-SSH module handlers (debug, fail, assert, set_fact, include_vars, meta), handleLookup, SetInventory, iterator functions, resolveExpr with registered vars/ facts/task vars/host vars/filters Coverage: 23.4% → 27.7% Co-Authored-By: Virgil <virgil@lethean.io>
4.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
core/go-ansible is a pure Go Ansible playbook engine. It parses YAML playbooks, inventories, and roles, then executes tasks on remote hosts via SSH. 41 module handler implementations (plus 3 community modules), Jinja2-compatible templating, privilege escalation (become), and event-driven callbacks. This is a library — there is no standalone binary. The CLI integration lives in cmd/ansible/ and is compiled as part of the core CLI binary.
Build & Test
go build ./... # verify compilation
go test ./... # run all tests
go test -race ./... # with race detection
go test -run TestParsePlaybook_Good_SimplePlay # single test
go test -v ./... # verbose output
go work sync # if in a Go workspace
No SSH access is needed for tests — the suite uses a mock SSH client (mock_ssh_test.go).
Architecture
Single flat ansible package with four layers:
Playbook YAML ──► Parser ──► []Play ──► Executor ──► Module Handlers ──► SSH Client ──► Remote Host
│ │
Inventory YAML ──► Parser ──► Inventory Callbacks (OnPlayStart, OnTaskEnd, ...)
types.go— Core structs (Playbook,Play,Task,TaskResult,Inventory,Host,Facts) andKnownModulesregistry (80 entries: both FQCNansible.builtin.*and short forms).parser.go— YAML parsing for playbooks, inventories, tasks, and roles. CustomTask.UnmarshalYAMLscans map keys againstKnownModulesto extract the module name and args (since Ansible embeds the module name as a YAML key, not a fixed field). Free-form syntax (shell: echo hello) is stored asArgs["_raw_params"]. Iterator variants (ParsePlaybookIter,ParseTasksIter, etc.) returniter.Seqvalues.executor.go— Orchestration engine: host resolution from inventory, play execution order (gather facts → pre_tasks → roles → tasks → post_tasks → notified handlers),when:condition evaluation,{{ }}Jinja2-style templating with filter support, loop execution, block/rescue/always, handler notification.modules.go— 41 module handler implementations dispatched via aswitchon the normalised module name. Each handler extracts args viagetStringArg/getBoolArg, constructs shell commands, runs them via SSH, and returns aTaskResult.ssh.go— SSH client with lazy connection, auth chain (key file → default keys → password),known_hostsverification, become/sudo wrapping, file transfer viacat >piped through stdin.cmd/ansible/— CLI command registration viacore/cli. Providesansible <playbook>andansible test <host>subcommands with flags for inventory, limit, tags, extra-vars, verbosity, and check mode.
Adding a New Module
- Add both FQCN and short form to
KnownModulesintypes.go - Add the dispatch case in
executeModuleswitch inmodules.go - Implement
module{Name}(ctx, client, args)method onExecutorinmodules.go - Write tests in the appropriate
modules_*_test.gofile using mock SSH infrastructure
If adding new YAML keys to Task, update the knownKeys map in Task.UnmarshalYAML (parser.go) to prevent them being mistaken for module names.
Test Organisation
| File | Coverage |
|---|---|
types_test.go |
YAML unmarshalling for Task, RoleRef, Inventory, Facts |
parser_test.go |
Playbook, inventory, and task file parsing |
executor_test.go |
Executor lifecycle, conditions, templating, loops, tags |
ssh_test.go |
SSH client construction and defaults |
modules_cmd_test.go |
Command modules: shell, command, raw, script |
modules_file_test.go |
File modules: copy, template, file, lineinfile, stat, slurp, fetch, get_url |
modules_svc_test.go |
Service modules: service, systemd, user, group |
modules_infra_test.go |
Infrastructure modules: apt, pip, git, unarchive, ufw, docker_compose |
modules_adv_test.go |
Advanced modules: debug, fail, assert, set_fact, pause, wait_for, uri, blockinfile, cron, hostname, sysctl, reboot |
Coding Standards
- UK English in comments and documentation (colour, organisation, centre)
- Test naming:
_Good(happy path),_Bad(expected errors),_Ugly(edge cases/panics) - Use
coreerr.E(scope, message, err)fromgo-logfor all errors in production code (neverfmt.Errorf) - Tests use
testify/assert(soft) andtestify/require(hard) - Licence: EUPL-1.2