Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
# Configuration for ansible-lint, run via `make ansible-lint` (hack/ansible-lint.sh).
profile: basic

# Collections are pre-installed by hack/ansible-lint.sh; never reach out to galaxy.
offline: true

exclude_paths:
# Claude Code skill/command content, not Ansible
- .claude/
# CloudFormation templates, not Ansible
- deploy/aws-hypervisor/templates/

# Roles are resolved relative to deploy/openshift-clusters/ at runtime, which
# ansible-lint cannot see when invoked from the repository root.
mock_roles:
- git-user

# Baseline debt: rules that fire on the pre-existing tree. New violations of any
# rule NOT listed here fail `make verify`. Burn these down over time by fixing
# the findings and removing entries from this list.
skip_list:
- command-instead-of-module
- command-instead-of-shell
- jinja[spacing]
- key-order[task]
- literal-compare
- name[casing]
- name[missing]
- name[play]
- name[template]
- role-name
- role-name[path]
- schema[playbook]
- var-naming[no-role-prefix]
- var-naming[read-only]
- yaml[empty-lines]
- yaml[line-length]
- yaml[new-line-at-end-of-file]
- yaml[trailing-spaces]
- yaml[truthy]
71 changes: 36 additions & 35 deletions .claude/commands/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ All deployment methods require an SSH key on the local machine. Check for any of

If no SSH key exists, create one with: `ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519`

**Note for non-default key paths:** Set `SSH_PUBLIC_KEY` in [deploy/aws-hypervisor/instance.env](deploy/aws-hypervisor/instance.env). This is used by both the AWS hypervisor and dev-scripts deployments.
**Note for non-default key paths:** Set `SSH_PUBLIC_KEY` in [config/instance.env](config/instance.env). This is used by both the AWS hypervisor and dev-scripts deployments.

### Inventory File

Expand All @@ -60,22 +60,19 @@ Required for: external, kcli, dev-scripts

Required for: kcli, dev-scripts

The same pull secret is used by both kcli and dev-scripts (stored in different locations).

- kcli location: [deploy/openshift-clusters/roles/kcli/kcli-install/files/pull-secret.json](deploy/openshift-clusters/roles/kcli/kcli-install/files/pull-secret.json)
- dev-scripts location: [deploy/openshift-clusters/roles/dev-scripts/install-dev/files/pull-secret.json](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/pull-secret.json)
The same pull secret is used by both kcli and dev-scripts. Create it once in the central config folder: [config/pull-secret.json](config/pull-secret.json). The sync (run by every `make` target, or explicitly via `cd deploy && make sync-config`) distributes it to both role locations automatically.

**Setup logic:**
- Check if file exists in either location
- If it exists in one location, offer to copy it to the other
- Check if [config/pull-secret.json](config/pull-secret.json) exists
- If not, check the canonical locations (`deploy/openshift-clusters/roles/dev-scripts/install-dev/files/pull-secret.json` and `deploy/openshift-clusters/roles/kcli/kcli-install/files/pull-secret.json`) - a file there means the user configured it the direct-edit way, which is still valid
- If it doesn't exist anywhere:
- User gets pull secret from: https://cloud.redhat.com/openshift/install/pull-secret
- **For CI builds**: Must include `registry.ci.openshift.org` access (see [CI Token](#ci-token) below)
- Suggest creating file and pasting content
- Suggest creating [config/pull-secret.json](config/pull-secret.json) and pasting content

**Validation:**
- Validate pull secret is valid JSON: `jq . < <path-to-pull-secret>`
- Check for CI registry access (if needed): `jq '.auths | has("registry.ci.openshift.org")' < <path-to-pull-secret>`
- Validate pull secret is valid JSON: `jq . < config/pull-secret.json`
- Check for CI registry access (if needed): `jq '.auths | has("registry.ci.openshift.org")' < config/pull-secret.json`
Comment thread
coderabbitai[bot] marked this conversation as resolved.

### CI Token

Expand Down Expand Up @@ -107,10 +104,11 @@ Required for: dev-scripts (when using CI builds)
- `export RHSM_ORG="your-org-id"`
- Guide: https://access.redhat.com/solutions/3341191

- **Option B**: Local config file [vars/init-host.yml.local](vars/init-host.yml.local)
- Template: [vars/init-host.yml.sample](vars/init-host.yml.sample)
- Check if exists
- Suggest copying: `cp vars/init-host.yml.sample vars/init-host.yml.local`
- **Option B**: Local config file [config/init-host.yml.local](config/init-host.yml.local)
- Base file: [deploy/openshift-clusters/vars/init-host.yml](deploy/openshift-clusters/vars/init-host.yml)
- Check if exists (also accept the direct-edit location `deploy/openshift-clusters/vars/init-host.yml.local`)
- Suggest copying: `cp deploy/openshift-clusters/vars/init-host.yml config/init-host.yml.local`
- The sync distributes it to `deploy/openshift-clusters/vars/init-host.yml.local`; suggest `cd deploy && make sync-config` before running the playbook directly

- **Option C**: Command line (they'll add when running playbook)

Expand All @@ -135,17 +133,18 @@ Required for: dev-scripts (when using CI builds)

**Files to configure:**

1. **Instance environment**: [deploy/aws-hypervisor/instance.env](deploy/aws-hypervisor/instance.env)
- Template: [deploy/aws-hypervisor/instance.env.template](deploy/aws-hypervisor/instance.env.template)
- Check if it exists
1. **Instance environment**: [config/instance.env](config/instance.env)
- Template: [config/instance.env.template](config/instance.env.template)
- Check if it exists (also accept the direct-edit location [deploy/aws-hypervisor/instance.env](deploy/aws-hypervisor/instance.env))
- User must edit ALL variables with their specific values
- Optional: Set `RHSM_ACTIVATION_KEY` and `RHSM_ORG` for hands-off deployment
- Guide: https://access.redhat.com/solutions/3341191
- Suggest copying: `cp deploy/aws-hypervisor/instance.env.template deploy/aws-hypervisor/instance.env`
- Suggest copying: `cp config/instance.env.template config/instance.env`
- Every `make` target syncs it to `deploy/aws-hypervisor/instance.env` where the scripts read it

**Validation:**
- Verify [deploy/aws-hypervisor/instance.env](deploy/aws-hypervisor/instance.env) exists
- Test by sourcing: `source deploy/aws-hypervisor/instance.env` (should not error)
- Verify [config/instance.env](config/instance.env) (or `deploy/aws-hypervisor/instance.env`) exists
- Test by sourcing: `source config/instance.env` (should not error)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

**Next steps:**
- Quick deploy: `cd deploy && make deploy arbiter-ipi`
Expand All @@ -165,11 +164,12 @@ Required for: dev-scripts (when using CI builds)

**Files to configure:**

1. **Optional persistent config**: [deploy/openshift-clusters/vars/kcli.yml](deploy/openshift-clusters/vars/kcli.yml)
- Template: [deploy/openshift-clusters/vars/kcli.yml.template](deploy/openshift-clusters/vars/kcli.yml.template)
- Check if exists
1. **Optional persistent config**: [config/kcli.yml](config/kcli.yml)
- Template: [config/kcli.yml.template](config/kcli.yml.template)
- Check if exists (also accept the direct-edit location [deploy/openshift-clusters/vars/kcli.yml](deploy/openshift-clusters/vars/kcli.yml))
- For setting preferred defaults (cluster name, resources, etc.)
- Suggest copying: `cp deploy/openshift-clusters/vars/kcli.yml.template deploy/openshift-clusters/vars/kcli.yml`
- Suggest copying: `cp config/kcli.yml.template config/kcli.yml`
- The sync distributes it to `deploy/openshift-clusters/vars/kcli.yml`; suggest `cd deploy && make sync-config` before running the playbook directly

**Validation:**
- Verify inventory file exists
Expand All @@ -192,28 +192,29 @@ Required for: dev-scripts (when using CI builds)

**Files to configure:**

1. **Topology config files** in [deploy/openshift-clusters/roles/dev-scripts/install-dev/files/](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/):
1. **Topology config files** in [config/](config/):

a. **Arbiter config**: [config_arbiter.sh](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter.sh)
- Template: [config_arbiter_example.sh](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter_example.sh)
- Check if exists
a. **Arbiter config**: [config/config_arbiter.sh](config/config_arbiter.sh)
- Template: [config/config_arbiter_example.sh](config/config_arbiter_example.sh)
- Check if exists (also accept the direct-edit location `deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter.sh`)
- User must set:
- `OPENSHIFT_RELEASE_IMAGE` (e.g., `quay.io/openshift-release-dev/ocp-release:4.19.0-rc.5-multi-x86_64`)
- `CI_TOKEN` (see [CI Token](#ci-token)) unless using `OPENSHIFT_CI="True"`
- Suggest copying: `cp deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter_example.sh deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter.sh`
- Suggest copying: `cp config/config_arbiter_example.sh config/config_arbiter.sh`

b. **Fencing config**: [config_fencing.sh](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing.sh)
- Template: [config_fencing_example.sh](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing_example.sh)
- Check if exists
b. **Fencing config**: [config/config_fencing.sh](config/config_fencing.sh)
- Template: [config/config_fencing_example.sh](config/config_fencing_example.sh)
- Check if exists (also accept the direct-edit location `deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing.sh`)
- Same requirements as arbiter config
- Suggest copying: `cp deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing_example.sh deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing.sh`
- Suggest copying: `cp config/config_fencing_example.sh config/config_fencing.sh`

- The sync distributes these to `deploy/openshift-clusters/roles/dev-scripts/install-dev/files/`; suggest `cd deploy && make sync-config` before running the playbook directly
- **Config reference**: https://github.com/openshift-metal3/dev-scripts/blob/master/config_example.sh
Comment on lines +211 to 212

@coderabbitai coderabbitai Bot Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the nested list indentation.

The bullet indentation under the numbered item is inconsistent here and triggers MD005. Based on static analysis, align it with the sibling list items.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 211-211: Inconsistent indentation for list items at the same level
Expected: 6; Actual: 3

(MD005, list-indent)


[warning] 212-212: Inconsistent indentation for list items at the same level
Expected: 6; Actual: 3

(MD005, list-indent)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/commands/setup.md around lines 211 - 212, The markdown list under
the numbered setup step has inconsistent nested bullet indentation, causing
MD005. Update the bullet items in the setup instructions so they are aligned
consistently with the other sibling list items in this section, keeping the
existing content but fixing the nested list structure.

Source: Linters/SAST tools

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Won't fix — this is a Claude Code prompt file, not rendered documentation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@fonta-rh, understood — thanks for the context. Since this file is consumed as a Claude Code prompt rather than rendered Markdown, the indentation styling isn't functionally important. I'll skip flagging this going forward.


**Validation:**
- Verify inventory file exists
- For arbiter: Check [config_arbiter.sh](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter.sh) exists
- For fencing: Check [config_fencing.sh](deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing.sh) exists
- For arbiter: Check [config/config_arbiter.sh](config/config_arbiter.sh) (or the direct-edit location) exists
- For fencing: Check [config/config_fencing.sh](config/config_fencing.sh) (or the direct-edit location) exists
- Verify pull secret exists and is valid JSON

**Next steps:**
Expand Down
12 changes: 6 additions & 6 deletions .claude/commands/setup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Configures deployment to your own RHEL 9 server (non-AWS).
Configures automated RHEL hypervisor deployment in AWS EC2.

**Files configured:**
- `deploy/aws-hypervisor/instance.env` - AWS instance configuration
- `config/instance.env` - AWS instance configuration (synced to `deploy/aws-hypervisor/instance.env`)

**Use when:** You want to deploy a hypervisor in AWS

Expand All @@ -49,8 +49,8 @@ Configures kcli-based OpenShift deployment (fencing topology).

**Files configured:**
- `deploy/openshift-clusters/inventory.ini` - Target host details
- `deploy/openshift-clusters/roles/kcli/kcli-install/files/pull-secret.json` - OpenShift pull secret
- `deploy/openshift-clusters/vars/kcli.yml` (optional) - Persistent kcli preferences
- `config/pull-secret.json` - OpenShift pull secret (synced to the kcli role files directory)
- `config/kcli.yml` (optional) - Persistent kcli preferences (synced to `deploy/openshift-clusters/vars/kcli.yml`)
- SSH key validation

**Use when:** You want to deploy using the modern kcli method
Expand All @@ -60,9 +60,9 @@ Configures traditional dev-scripts deployment (arbiter or fencing topology).

**Files configured:**
- `deploy/openshift-clusters/inventory.ini` - Target host details
- `deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_arbiter.sh` - Arbiter config
- `deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_fencing.sh` - Fencing config
- `deploy/openshift-clusters/roles/dev-scripts/install-dev/files/pull-secret.json` - OpenShift pull secret
- `config/config_arbiter.sh` - Arbiter config (synced to the dev-scripts role files directory)
- `config/config_fencing.sh` - Fencing config (synced to the dev-scripts role files directory)
- `config/pull-secret.json` - OpenShift pull secret (synced to both the dev-scripts and kcli role files directories)
- Ansible collections installation
- SSH key validation

Expand Down
41 changes: 31 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,30 @@ ansible-playbook kcli-install.yml -i inventory.ini -e "force_cleanup=true"

#### Assisted Installer Method (Spoke TNF via ACM)
```bash
# Copy and customize the configuration template
cp vars/assisted.yml.template vars/assisted.yml
# Copy and customize the configuration template (from the repository root)
cp config/assisted.yml.template config/assisted.yml

# Deploy hub + spoke TNF cluster via assisted installer
make deploy fencing-assisted
```

### Linting and Validation
```bash
# Shell script linting (from repository root)
# Run all checks (from repository root)
make verify

# Shell script linting
make shellcheck
# or manually:
./hack/shellcheck.sh

# YAML formatting
make yamlfmt

# Ansible linting and playbook syntax checks
make ansible-lint
```

`make ansible-lint` runs ansible-lint (configured by `.ansible-lint`) plus `ansible-playbook --syntax-check` for every playbook. Pre-existing findings are baselined in the `.ansible-lint` skip list; do not add new entries to the skip list — fix new violations instead.

## Architecture and Structure

### Core Components
Expand Down Expand Up @@ -121,20 +130,32 @@ make shellcheck

### Key Configuration Files

#### Dev-scripts Method
- `inventory.ini`: Ansible inventory (copy from `inventory.ini.sample`)
#### Central config/ Folder
User configuration files are created in `config/` at the repository root (templates and examples live there; see `config/README.md`). Every make-accessible script syncs `config/` files to the canonical locations below before doing anything else (newer-wins, never deletes); `make sync-config` runs the sync explicitly. Editing the canonical locations directly still works: a `config/` file only becomes authoritative once the user creates it.

- `config/instance.env`: AWS hypervisor settings (copy from `config/instance.env.template`)
- `config/pull-secret.json`: OpenShift pull secret, fanned out to both dev-scripts and kcli role locations
- `config/config_arbiter.sh`, `config/config_fencing.sh`, `config/config_sno.sh`: dev-scripts topology configs (copy from the `config/config_*_example.sh` files)
- `config/config_baremetal_fencing.sh`: baremetal fencing topology config (generated by `make baremetal-adopt`)
- `config/kcli.yml`: kcli variable overrides (copy from `config/kcli.yml.template`)
- `config/assisted.yml`: assisted installer variables (copy from `config/assisted.yml.template`)
- `config/init-host.yml.local`: external-host RHSM overrides (copy from `deploy/openshift-clusters/vars/init-host.yml`)

#### Dev-scripts Method (canonical locations)
- `inventory.ini`: Ansible inventory (copy from `inventory.ini.sample`; generated by `make inventory` on AWS)
- `roles/dev-scripts/install-dev/files/config_arbiter.sh`: Arbiter topology config
- `roles/dev-scripts/install-dev/files/config_fencing.sh`: Fencing topology config
- `roles/dev-scripts/install-dev/files/config_sno.sh`: Single Node OpenShift config
- `roles/dev-scripts/install-dev/files/config_baremetal_fencing.sh`: Baremetal fencing topology config
- `roles/dev-scripts/install-dev/files/pull-secret.json`: OpenShift pull secret

#### Kcli Method
#### Kcli Method (canonical locations)
- `vars/kcli.yml`: Variable override file for persistent configuration
- `roles/kcli/kcli-install/files/pull-secret.json`: OpenShift pull secret
- SSH key automatically read from `~/.ssh/id_ed25519.pub` on ansible controller

#### Assisted Installer Method
- `vars/assisted.yml`: Variable override file (copy from `vars/assisted.yml.template`)
#### Assisted Installer Method (canonical locations)
- `vars/assisted.yml`: Variable override file (create as `config/assisted.yml`)
- Hub cluster must be deployed first via dev-scripts (`make deploy fencing-ipi`)
- Spoke credentials output to `~/<spoke_cluster_name>/auth/` on hypervisor
- Hub proxy preserved as `hub-proxy.env`
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ shellcheck:
yamlfmt:
@./hack/yamlfmt.sh

ansible-lint:
@./hack/ansible-lint.sh

test-resource-agents:
@./helpers/resource-agents-build/local-build-test.sh $(ARGS)

verify:
VALIDATE_ONLY=true $(MAKE) shellcheck
VALIDATE_ONLY=true $(MAKE) yamlfmt
$(MAKE) ansible-lint

install-pre-commit:
@echo "Installing pre-commit hook..."
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This repository provides automation for deploying and managing two-node OpenShif

## Quick Start

Configuration files (instance settings, pull secret, topology configs) are created in the central [config/](config/) folder; see [config/README.md](config/README.md) for the full list. Every `make` command syncs them to the locations where the automation reads them. Editing the canonical locations directly still works as before.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
### Option 1: AWS Hypervisor (Automated)

If you have AWS access, use the automated workflow. Most lifecycle operations can be performed from the [deploy](deploy/) folder using `make`:
Expand Down Expand Up @@ -48,6 +50,8 @@ ansible-playbook setup.yml -i inventory.ini # dev-scripts (arbiter or fen
ansible-playbook kcli-install.yml -i inventory.ini # kcli (fencing only)
```

If you created your configuration files in [config/](config/), run `make sync-config` from the [deploy/](deploy/) folder first to distribute them, since the playbooks are invoked directly here.

See [deploy/openshift-clusters/README-external-host.md](deploy/openshift-clusters/README-external-host.md) for detailed instructions.

## Deployment Methods
Expand Down Expand Up @@ -103,6 +107,19 @@ Alternatively, `make patch-nodes` (from `deploy/`) clones the resource-agents re

See [helpers/README.md](helpers/README.md) for full documentation.

## Development

Verify changes before committing (runs shellcheck, yamlfmt, and Ansible validation):

```bash
make verify # run all checks
make shellcheck # shell script linting
make yamlfmt # YAML formatting
make ansible-lint # ansible-lint and playbook syntax checks
```

`make ansible-lint` runs [ansible-lint](https://ansible.readthedocs.io/projects/lint/) (configured by `.ansible-lint`) and `ansible-playbook --syntax-check` for every playbook in a container. Pre-existing findings are baselined in the `.ansible-lint` skip list; new violations fail verification. Install the pre-commit hook with `make install-pre-commit` to run `make verify` automatically.

## Troubleshooting with Claude Code

If you're using [Claude Code](https://claude.ai/code), it can help you troubleshoot etcd issues on two-node fencing clusters. Simply ask Claude to diagnose your etcd problems and it will automatically collect diagnostics, analyze the cluster state, and recommend remediation steps. See [.claude/commands/etcd/README.md](.claude/commands/etcd/README.md) for details.
7 changes: 7 additions & 0 deletions config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Real config files (created by the user, may contain credentials) must never
# be committed. Only templates, examples, the README, and this file are tracked.
*
!.gitignore
!README.md
!*.template
!config_*_example.sh
Loading