Skip to content

feat(create): expose Hetzner config as CLI flags; drop required .onctl YAML - #918

Merged
cdalar merged 2 commits into
mainfrom
feat/hetzner-flags-no-yaml
Jun 19, 2026
Merged

cdalar merged 2 commits into
mainfrom
feat/hetzner-flags-no-yaml

Conversation

@cdalar

@cdalar cdalar commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

Makes onctl usable for Hetzner with zero config files. Previously onctl required a .onctl directory (from onctl init) and fatally refused to run without it. Every setting that lived in hetzner.yaml / onctl.yaml is now a CLI flag with a default.

Scope is Hetzner only this pass — AWS/GCP/Azure/Firecracker keep their YAML (separate follow-up).

What changed

  • setDefaults() (cmd/common.go): viper.SetDefault for all Hetzner + global keys — hetzner.location=fsn1, hetzner.vm.type=cpx21, hetzner.vm.image=ubuntu-22.04, hetzner.vm.username=root, ssh.publicKey/privateKey, vm.cloud-init.timeout=3m, actions.githubOwner=cdalar. Values identical to the old templates.
  • Generic create flags: --type, --location, --username, --cloud-init-timeout (plus existing --image), each viper.BindPFlag'd to the key the rest of the code already reads — so values flow through unchanged with no churn to the ~40 read sites.
  • Persistent --provider flag (overrides ONCTL_CLOUD); --github-owner on action.
  • Ordering fix: provider construction + config load moved from Execute() into rootCmd.PersistentPreRunE, so it runs after cobra parses flags (flags can override config). A missing .onctl is now best-effort (logged at DEBUG), not fatal.
  • Removed embedded init/hetzner.yaml and init/onctl.yaml (defaults now in code). onctl init still scaffolds the other providers.

Credentials are unaffected — still env (HCLOUD_TOKEN, AWS_*, …).

Why

Drives the onctl-runners controller (and onctl UX generally) without a per-VM/provider config file — e.g. onctl create -n x --type cpx31 --location nbg1 --provider hetzner.

Tests

  • go test ./... green. New cmd/flags_defaults_test.go covers flag existence, viper binding (override flows through), and defaults.
  • Manual zero-config check: with an empty HOME (no ~/.onctl), onctl ls reaches the Hetzner API (invalid-token) instead of demanding onctl init.
  • onctl create --help shows the new flags.

Suggested reviewer smoke test (real VM)

mv ~/.onctl ~/.onctl.bak   # prove no config needed
HCLOUD_TOKEN=… onctl create -n t1            # cpx21/fsn1/ubuntu-22.04 defaults
HCLOUD_TOKEN=… onctl create -n t2 --type cpx31 --location nbg1 --image ubuntu-24.04
onctl ls && onctl destroy t1 -f && onctl destroy t2 -f
mv ~/.onctl.bak ~/.onctl

Out of scope

AWS/GCP/Azure/Firecracker flag conversion; the onctl-runners controller switch to --type/--provider (follow-up once this ships).

🤖 Generated with Claude Code

https://claude.ai/code/session_013fQKc2HmtfdtBeKfXBXab6

…d .onctl YAML

onctl previously required a .onctl config dir (from `onctl init`) and fatally
refused to run without it. For Hetzner, every setting that lived in
hetzner.yaml / onctl.yaml is now a CLI flag with a default, so onctl works with
no config files on disk.

- setDefaults() (cmd/common.go): viper.SetDefault for all Hetzner + global keys
  (location=fsn1, vm.type=cpx21, vm.image=ubuntu-22.04, vm.username=root,
  ssh.publicKey/privateKey, vm.cloud-init.timeout=3m, actions.githubOwner).
- Generic create flags --type/--location/--username/--cloud-init-timeout
  (+ existing --image), each viper.BindPFlag'd to the key the code already
  reads, so values flow through unchanged. Defaults match the old YAML.
- Persistent --provider flag (overrides ONCTL_CLOUD); --github-owner on action.
- Provider construction + config load moved from Execute() into
  rootCmd.PersistentPreRunE so it runs after flag parsing (flags can override
  config). Missing .onctl is now best-effort (logged), not fatal.
- Remove embedded init/hetzner.yaml and init/onctl.yaml (defaults are in code).
  Other providers keep their YAML for now (separate follow-up).

Credentials are unaffected (still env: HCLOUD_TOKEN, etc.). Adds
flags_defaults_test.go covering flag existence, viper binding, and defaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013fQKc2HmtfdtBeKfXBXab6

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbe4653e80

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/root.go Resolved
Comment thread cmd/root.go Resolved
@cdalar
cdalar force-pushed the feat/hetzner-flags-no-yaml branch from 684204d to 848728e Compare June 19, 2026 11:24
@codecov

codecov Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 34.42623% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 22.41%. Comparing base (0257702) to head (2e8a77c).
⚠️ Report is 19 commits behind head on main.

Files with missing lines Patch % Lines
cmd/root.go 2.85% 34 Missing ⚠️
cmd/destroy.go 0.00% 3 Missing ⚠️
cmd/ssh.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #918      +/-   ##
==========================================
+ Coverage   21.40%   22.41%   +1.00%     
==========================================
  Files          41       42       +1     
  Lines        4031     4163     +132     
==========================================
+ Hits          863      933      +70     
- Misses       3059     3114      +55     
- Partials      109      116       +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Keep config errors fatal outside Hetzner by extracting initState()
  from PersistentPreRunE, matching the pre-flags behavior for aws/gcp/
  azure/firecracker while still defaulting Hetzner when .onctl is missing.
- Add ensureProvider() and skip __complete/__completeNoDesc in
  PersistentPreRunE so shell completion doesn't dereference a nil
  provider or fatally error when config is missing.
- Fix TestCreateFlagsBindToViper flaking under randomized test order by
  loading an isolated empty config before asserting on viper defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0181WDmhDAKfTzXfFUZFKGvM
@cdalar
cdalar force-pushed the feat/hetzner-flags-no-yaml branch from 848728e to 2e8a77c Compare June 19, 2026 11:30
@cdalar
cdalar merged commit f665f23 into main Jun 19, 2026
15 checks passed
@cdalar
cdalar deleted the feat/hetzner-flags-no-yaml branch June 19, 2026 12:15
cdalar added a commit that referenced this pull request Jun 19, 2026
…racker → fc (#919)

* feat(create): expose Firecracker config as CLI flags; drop firecracker.yaml

Mirrors the Hetzner pass (#918) for Firecracker so the provider works with no
.onctl YAML:

- setDefaults(): firecracker.* defaults (kernelImage, rootfsImage, vcpuCount,
  memSizeMib, binPath, network.bridge/cidr, vm.username) matching the old
  firecracker.yaml. providerfirecracker.GetConfig still defaults these for
  direct package use; kernelImage/rootfsImage (which GetConfig left empty) now
  resolve to the conventional ~/.onctl paths with no config.
- create flags --kernel-image, --rootfs-image, --fc-binary, --vcpu, --memory
  bound to the firecracker.* keys read by GetConfig; the generic --username
  also drives firecracker.vm.username.
- Removed embedded internal/files/init/firecracker.yaml (`onctl init` no longer
  scaffolds it).
- flags_defaults_test.go covers the new flags' existence, viper binding, and
  defaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha7EmqjjYwGC3f1wk41TE2

* refactor: rename the firecracker provider to fc

Renames the provider *identity* from `firecracker` to `fc` while keeping every
reference to the Firecracker technology/binary intact:

- Provider string: `--provider fc`, `ONCTL_CLOUD=fc`, cloudProviderList entry.
- Config keys: firecracker.* -> fc.* (e.g. fc.kernelImage, fc.vcpuCount,
  fc.network.bridge, fc.vm.username).
- Package internal/providerfirecracker -> internal/providerfc.
- Exported Go types: ProviderFirecracker->ProviderFC, FirecrackerConfig->FCConfig,
  FirecrackerVMConfig->FCVMConfig, FirecrackerProcess->FCProcess,
  FirecrackerAPI->FCAPI (plus unexported helpers: firecrackerRequest->fcRequest,
  firecrackerStatus*->fcStatus*, defaultFirecrackerKernelArgs->defaultFCKernelArgs,
  firecrackerMAC/TapName/VM, parseFirecrackerType, load/saveFirecrackerMetadata,
  allocateFirecrackerIP, and the test helpers).
- Files pkg/cloud/firecracker.go -> fc.go, firecracker_test.go -> fc_test.go.
- README provider name + ONCTL_CLOUD updated.

Deliberately KEPT (these name the Firecracker technology, not the provider):
- the literal `firecracker` binary name (fc.binPath default),
- the ~/.onctl/firecracker image/state directory paths (so existing image
  layouts keep working),
- comments/strings describing the Firecracker API, VMM and microVMs,
- the firecracker/firecracker-host-setup.sh template path in the README.

go build / go vet / go test ./... all green; gofmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha7EmqjjYwGC3f1wk41TE2

* docs(fc): add local testing guide for the fc provider rename

Walkthrough for testing this branch on a GCP fc-host VM: building/copying the
binary, running create/pause/resume/destroy against the new `fc` provider and
flags, and confirming the old `firecracker` provider name is rejected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha7EmqjjYwGC3f1wk41TE2

* fix(cmd): allow fc provider to run without .onctl config

initState only let the hetzner provider skip a missing/unreadable
config file. The fc provider now ships built-in defaults too (this
PR), so it needs the same configless path or fresh `ONCTL_CLOUD=fc`
runs abort before defaults/flags are applied.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gf7TpG2y985TySw8Pg7Cn3

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

⌂ 换网址