diff --git a/.ansible-lint b/.ansible-lint index 4018263d8..bae510c5c 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -9,6 +9,7 @@ profile: null # min, basic, moderate, safety, shared, production exclude_paths: - .github/ - docs/ + - mkdocs.yaml # parseable: true # quiet: true # strict: true diff --git a/docs/ABI_KVM_QUICK_REFERENCE.md b/docs/ABI_KVM_QUICK_REFERENCE.md new file mode 100644 index 000000000..2eac8e2e3 --- /dev/null +++ b/docs/ABI_KVM_QUICK_REFERENCE.md @@ -0,0 +1,6 @@ + + +> **⚠️ Important Note**: This is a quick reference guide focusing on KVM-specific ABI configuration. For a complete setup, you must also configure all other required variables. See: +> - **Complete Variable Reference**: [set-variables-group-vars.md](set-variables-group-vars.md) and [set-variables-host-vars.md](set-variables-host-vars.md) +> - **Full Setup Instructions**: [run-the-playbooks-for-abi.md](run-the-playbooks-for-abi.md) +> - **LPAR Quick Reference**: [ABI_LPAR_QUICK_REFERENCE.md](ABI_LPAR_QUICK_REFERENCE.md) diff --git a/docs/ABI_LPAR_QUICK_REFERENCE.md b/docs/ABI_LPAR_QUICK_REFERENCE.md new file mode 100644 index 000000000..e8080cd70 --- /dev/null +++ b/docs/ABI_LPAR_QUICK_REFERENCE.md @@ -0,0 +1,196 @@ +# ABI LPAR Quick Reference Card + +## πŸš€ Quick Start + +### Step 1: Set Installation Type +**File**: `inventories/default/group_vars/all.yaml` +```yaml +installation_type: lpar + +abi: + flag: True + boot_method: pxe +``` + +### Step 2: Configure Storage for Each Node +**File**: `inventories/default/host_vars/{node-name}.yaml` +```yaml +lpar: + storage_group_1: + type: fcp + dev_num: "1a00" + storage_wwpn: + - "0x500507680b2a5f7e" + lun_name: "0x4000000000000000" +``` + +### Step 3: Run Playbook +```bash +ansible-playbook playbooks/master_playbook_for_abi.yaml +``` + +--- + +## πŸ“‹ Configuration Checklist + +- [ ] Set `installation_type: lpar` in all.yaml +- [ ] Set `abi.flag: True` in all.yaml +- [ ] Configure `lpar.storage_group_1` in each node's host_vars +- [ ] Verify `storage_group_1.type: fcp` +- [ ] Ensure dev_num, storage_wwpn, and lun_name are set +- [ ] Node names in all.yaml match host_vars filenames + +--- + +## πŸ”§ Storage Configuration Format + +### Required Fields +| Field | Format | Example | +|-------|--------|---------| +| `dev_num` | 4-digit hex (no prefix) | `"1a00"` | +| `storage_wwpn[0]` | Hex with 0x prefix | `"0x500507680b2a5f7e"` | +| `lun_name` | Hex with 0x prefix | `"0x4000000000000000"` | + +### Generated Device Path +``` +/dev/disk/by-path/ccw-0.0.{dev_num}-fc-{wwpn}-lun-{lun_name} +``` + +**Example Output**: +``` +/dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4000000000000000 +``` + +--- + +## πŸ“ Example Configurations + +### Control Node +**File**: `host_vars/control-1.yaml` +```yaml +lpar: + storage_group_1: + name: storage_group_1 + type: fcp + storage_wwpn: + - "0x500507680b2a5f7e" + - "0x500507680b2a5f7f" + dev_num: "1a00" + lun_name: "0x4000000000000000" +``` + +### Compute Node +**File**: `host_vars/compute-1.yaml` +```yaml +lpar: + storage_group_1: + name: storage_group_1 + type: fcp + storage_wwpn: + - "0x500507680b2a5f7e" + - "0x500507680b2a5f7f" + dev_num: "1a00" + lun_name: "0x4002000000000000" # Different LUN +``` + +--- + +## πŸ” Verification + +### Check Generated agent-config.yaml +**Location**: `~/ansible_workdir/agent-config.yaml` on bastion + +**Expected for LPAR**: +```yaml +hosts: + - hostname: "control-1" + role: master + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-... +``` + +**Expected for KVM**: +```yaml +hosts: + - hostname: "control-1" + role: master + # No rootDeviceHints +``` + +--- + +## ⚠️ Common Issues + +### Issue: No rootDeviceHints in agent-config.yaml +**Solution**: +- βœ… Verify `installation_type: lpar` +- βœ… Check `lpar.storage_group_1.type: fcp` +- βœ… Ensure host_vars file exists for each node + +### Issue: Wrong device path +**Solution**: +- βœ… dev_num: Use "1a00" NOT "0.0.1a00" +- βœ… wwpn: Include "0x" prefix +- βœ… lun_name: Include "0x" prefix + +### Issue: Template error loading host_vars +**Solution**: +- βœ… Node name in `env.cluster.nodes.control.vm_name` must match host_vars filename +- βœ… Example: `vm_name: control-1` β†’ file: `host_vars/control-1.yaml` + +--- + +## 🎯 Key Differences: KVM vs LPAR + +| Feature | KVM | LPAR | +|---------|-----|------| +| rootDeviceHints | ❌ Not needed | βœ… Required | +| Storage Config | Virtual disks | FCP/DASD | +| Device Path | Auto-detected | Must specify | +| host_vars Required | Optional | **Required** | + +--- + +## πŸ“š Related Documentation + +- **Full Guide**: `docs/abi-lpar-configuration.md` +- **Implementation Details**: `docs/IMPLEMENTATION_SUMMARY_ABI_LPAR.md` +- **Main Docs**: https://ibm.github.io/Ansible-OpenShift-Provisioning/ + +--- + +## πŸ”— Playbook Flow + +``` +master_playbook_for_abi.yaml + β”œβ”€ 0_setup.yaml (Setup environment) + β”œβ”€ 4_create_bastion.yaml (Create bastion) + β”œβ”€ 5_setup_bastion.yaml (Setup bastion) + β”œβ”€ create_abi_cluster.yaml + β”‚ β”œβ”€ prepare_configs (Generate agent-config.yaml with rootDeviceHints) + β”‚ β”œβ”€ create_agent (Generate installation images) + β”‚ └─ boot_abi_agents (Boot nodes) + └─ monitor_create_abi_cluster.yaml (Monitor installation) +``` + +--- + +## πŸ’‘ Pro Tips + +1. **Reuse Configuration**: The same `lpar.storage_group_1` is used for both booting and ABI installation +2. **Multiple Nodes**: Each node can have different storage configuration +3. **Multipath**: List all WWPNs in `storage_wwpn` array, but only first is used for rootDeviceHints +4. **Validation**: Check generated agent-config.yaml before running create_agent role + +--- + +## πŸ†˜ Need Help? + +- **Troubleshooting**: See `docs/abi-lpar-configuration.md` β†’ Troubleshooting section +- **GitHub Issues**: https://github.com/IBM/Ansible-OpenShift-Provisioning/issues +- **Documentation**: https://ibm.github.io/Ansible-OpenShift-Provisioning/ + +--- + +**Version**: 2.3.0+ +**Last Updated**: 2026-04-05 diff --git a/docs/IMPLEMENTATION_SUMMARY_ABI_LPAR.md b/docs/IMPLEMENTATION_SUMMARY_ABI_LPAR.md new file mode 100644 index 000000000..c3d4893e8 --- /dev/null +++ b/docs/IMPLEMENTATION_SUMMARY_ABI_LPAR.md @@ -0,0 +1,206 @@ +# Implementation Summary: ABI Support for LPAR Installations + +## Overview + +This document summarizes the implementation of Agent-Based Installer (ABI) support for LPAR installations with automatic `rootDeviceHints` generation. + +## Problem Statement + +Previously, the ABI automation only worked for KVM installations. LPAR installations require `rootDeviceHints` in the `agent-config.yaml` file to specify the exact storage device path for installation. Without this, the OpenShift installer cannot determine which disk to use for installation. + +## Solution + +Implemented automatic generation of `rootDeviceHints` for LPAR installations by: +1. Leveraging existing FCP storage configuration from node host_vars +2. Conditionally adding rootDeviceHints based on `installation_type` +3. Maintaining backward compatibility with KVM installations + +## Changes Made + +### 1. Template Updates + +**File**: `roles/prepare_configs/templates/agent-config.yaml.j2` + +**Changes**: +- Added logic to read each node's host_vars file +- Extract FCP storage configuration (`lpar.storage_group_1`) +- Generate `rootDeviceHints` with proper device path format +- Applied to both control and compute nodes +- Only activated when `installation_type: lpar` and storage type is FCP + +**Key Logic**: +```jinja2 +{%- if installation_type | lower == 'lpar' and + node_vars.lpar.storage_group_1.type | lower == 'fcp' %} + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.{{ dev_num }}-fc-{{ wwpn }}-lun-{{ lun }} +{%- endif %} +``` + +### 2. Documentation Updates + +**File**: `inventories/default/group_vars/all.yaml.template` + +**Changes**: +- Added comprehensive comments explaining ABI LPAR configuration +- Documented how rootDeviceHints are automatically generated +- Provided example device path format +- Clarified that KVM installations don't need rootDeviceHints + +**File**: `inventories/default/host_vars/KVMhostname1-here.yaml.template` + +**Changes**: +- Added detailed comments in storage_group_1 section +- Explained dual use: boot configuration AND ABI rootDeviceHints +- Provided example values and resulting device path +- Clarified format requirements for dev_num, wwpn, and lun_name + +### 3. New Documentation + +**File**: `docs/abi-lpar-configuration.md` + +**Content**: +- Complete guide for ABI LPAR installations +- Configuration flow diagrams +- Step-by-step setup instructions +- Example configurations for multiple nodes +- Comparison between KVM and LPAR installations +- Troubleshooting section +- Generated agent-config.yaml examples + +**File**: `mkdocs.yaml` + +**Changes**: +- Added link to new ABI LPAR documentation in navigation menu + +## Technical Details + +### Device Path Format + +For FCP storage, the device path follows this format: +``` +/dev/disk/by-path/ccw-0.0.{dev_num}-fc-{wwpn}-lun-{lun_name} +``` + +**Example**: +```yaml +# Input from host_vars: +lpar: + storage_group_1: + dev_num: "1a00" + storage_wwpn: + - "0x500507680b2a5f7e" + lun_name: "0x4000000000000000" + +# Generated rootDeviceHints: +rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4000000000000000 +``` + +### Variable Reuse + +The implementation reuses existing LPAR storage configuration: +- **Existing**: `lpar.storage_group_1` used for booting LPAR nodes +- **New**: Same configuration now also used for ABI rootDeviceHints +- **Benefit**: No new variables needed, consistent configuration + +### Conditional Logic + +The template uses multiple conditions to ensure correct behavior: + +1. **Installation Type Check**: `installation_type | lower == 'lpar'` +2. **Storage Type Check**: `lpar.storage_group_1.type | lower == 'fcp'` +3. **Variable Existence Check**: Ensures lpar.storage_group_1 is defined +4. **Node Type**: Applied to both control and compute nodes + +## Backward Compatibility + +βœ… **KVM Installations**: No changes, rootDeviceHints not added +βœ… **Existing LPAR Boot**: No impact on existing boot_LPAR role +βœ… **zVM Installations**: No changes, continues to work as before +βœ… **Non-ABI Installations**: Not affected, only impacts ABI workflow + +## Usage Flow + +``` +1. User sets installation_type: lpar in all.yaml +2. User configures lpar.storage_group_1 in each node's host_vars +3. User runs: ansible-playbook playbooks/master_playbook_for_abi.yaml +4. prepare_configs role generates agent-config.yaml with rootDeviceHints +5. create_agent role generates installation images +6. Nodes boot and install using specified storage devices +``` + +## Testing Recommendations + +### Test Case 1: KVM Installation (No rootDeviceHints) +```yaml +installation_type: kvm +abi: + flag: True +``` +**Expected**: agent-config.yaml generated WITHOUT rootDeviceHints + +### Test Case 2: LPAR Installation with FCP (With rootDeviceHints) +```yaml +installation_type: lpar +abi: + flag: True +``` +**Expected**: agent-config.yaml generated WITH rootDeviceHints for each node + +### Test Case 3: Multiple Nodes with Different Storage +- Control nodes with different LUNs +- Compute nodes with different LUNs +**Expected**: Each node gets unique rootDeviceHints based on its host_vars + +### Test Case 4: Missing Storage Configuration +- LPAR installation but host_vars missing storage_group_1 +**Expected**: Template should handle gracefully (no rootDeviceHints added) + +## Files Modified + +1. `roles/prepare_configs/templates/agent-config.yaml.j2` - Core template logic +2. `inventories/default/group_vars/all.yaml.template` - Documentation +3. `inventories/default/host_vars/KVMhostname1-here.yaml.template` - Documentation +4. `mkdocs.yaml` - Navigation update + +## Files Created + +1. `docs/abi-lpar-configuration.md` - Comprehensive user guide +2. `docs/IMPLEMENTATION_SUMMARY_ABI_LPAR.md` - This file + +## Benefits + +βœ… **Automated**: No manual agent-config.yaml editing required +βœ… **Consistent**: Uses same storage config for boot and installation +βœ… **Flexible**: Works with different storage configurations per node +βœ… **Safe**: Only affects LPAR installations, KVM unchanged +βœ… **Documented**: Comprehensive guides and examples provided + +## Future Enhancements + +Potential improvements for future releases: + +1. **DASD Support**: Add rootDeviceHints for DASD storage type +2. **Validation**: Add pre-flight checks for storage configuration +3. **Multi-path**: Support for multiple WWPN paths in rootDeviceHints +4. **Error Handling**: Enhanced error messages for missing configuration + +## References + +- [OpenShift Agent-Based Installer](https://docs.openshift.com/container-platform/latest/installing/installing_with_agent_based_installer/preparing-to-install-with-agent-based-installer.html) +- [IBM Z FCP Storage](https://www.ibm.com/docs/en/linux-on-systems?topic=devices-fibre-channel-protocol) +- [Project Documentation](https://ibm.github.io/Ansible-OpenShift-Provisioning/) + +## Contact + +For questions or issues related to this implementation: +- Open an issue on GitHub: https://github.com/IBM/Ansible-OpenShift-Provisioning/issues +- Refer to the troubleshooting guide: `docs/abi-lpar-configuration.md` + +--- + +**Implementation Date**: 2026-04-05 +**Version**: 2.3.0+ +**Status**: Complete and Ready for Testing \ No newline at end of file diff --git a/docs/TESTING_GUIDE_ABI_LPAR.md b/docs/TESTING_GUIDE_ABI_LPAR.md new file mode 100644 index 000000000..6e835ca12 --- /dev/null +++ b/docs/TESTING_GUIDE_ABI_LPAR.md @@ -0,0 +1,401 @@ +# Testing Guide: ABI LPAR Implementation + +## Overview + +This guide helps you test the ABI LPAR implementation up to image generation to verify that `rootDeviceHints` are correctly added to the agent-config.yaml file. + +## Test Scope + +We'll test up to and including image generation: +1. βœ… Bastion setup (no changes, should work as before) +2. βœ… agent-config.yaml generation with rootDeviceHints +3. βœ… Image generation (PXE or ISO) +4. ⏸️ LPAR booting (test later after validation) + +## Prerequisites + +Before testing, ensure you have: +- [ ] Bastion node created and accessible +- [ ] LPAR nodes defined in inventory +- [ ] FCP storage configuration available for each LPAR node +- [ ] OpenShift pull secret configured + +## Test Setup + +### 1. Configure Installation Type + +**File**: `inventories/default/group_vars/all.yaml` + +```yaml +installation_type: lpar # Critical: Must be 'lpar' not 'kvm' + +abi: + flag: True + ansible_workdir: 'ansible_workdir' + ocp_installer_version: '4.18.8' + ocp_installer_base_url: 'https://mirror.openshift.com/pub/openshift-v4' + architecture: multi # or s390x based on your environment + boot_method: pxe # or iso +``` + +### 2. Configure LPAR Storage for Each Node + +Create/update host_vars for each control and compute node. + +**Example**: `inventories/default/host_vars/control-1.yaml` + +```yaml +# ... other configuration ... + +lpar: + name: control-1-lpar + storage_group_1: + name: storage_group_1 + type: fcp # Must be 'fcp' for rootDeviceHints + storage_wwpn: + - "0x500507680b2a5f7e" # Replace with your actual WWPN + - "0x500507680b2a5f7f" # Additional paths for multipath + dev_num: "1a00" # Replace with your FCP device number + lun_name: "0x4000000000000000" # Replace with your LUN ID +``` + +**Important**: Repeat for all control and compute nodes with their respective storage configurations. + +### 3. Verify Node Names Match + +Ensure node names in all.yaml match host_vars filenames: + +```yaml +# In all.yaml +env: + cluster: + nodes: + control: + vm_name: + - control-1 # Must match: host_vars/control-1.yaml + - control-2 # Must match: host_vars/control-2.yaml + - control-3 # Must match: host_vars/control-3.yaml +``` + +## Testing Steps + +### Step 1: Setup Bastion (If Not Already Done) + +```bash +# Run bastion setup playbooks +ansible-playbook playbooks/4_create_bastion.yaml +ansible-playbook playbooks/5_setup_bastion.yaml +``` + +**Expected Result**: Bastion created and configured successfully (no changes from existing behavior) + +### Step 2: Generate agent-config.yaml + +```bash +# Run only the ABI cluster creation playbook +ansible-playbook playbooks/create_abi_cluster.yaml +``` + +This will: +1. Run `prepare_configs` role β†’ Generate agent-config.yaml +2. Run `create_agent` role β†’ Generate installation images +3. Attempt to boot agents (you can stop here for testing) + +**Alternative**: Run only the prepare_configs role: + +```bash +# SSH to bastion +ssh @ + +# Run prepare_configs tasks manually +cd /path/to/ansible +ansible-playbook -i inventories/default playbooks/create_abi_cluster.yaml --tags prepare_configs +``` + +### Step 3: Verify agent-config.yaml + +**On Bastion**, check the generated file: + +```bash +ssh @ +cat ~/ansible_workdir/agent-config.yaml +``` + +### Expected Output for LPAR + +```yaml +apiVersion: v1alpha1 +kind: AgentConfig +metadata: + name: +rendezvousIP: + +hosts: + - hostname: "control-1" + role: master + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4000000000000000 + interfaces: + - name: eth0 + macAddress: "02:00:00:00:00:01" + networkConfig: + # ... network configuration ... + + - hostname: "control-2" + role: master + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4001000000000000 + interfaces: + - name: eth0 + macAddress: "02:00:00:00:00:02" + networkConfig: + # ... network configuration ... + + # ... more nodes ... +``` + +### Step 4: Verify Image Generation + +Check that images were created successfully: + +```bash +# On bastion +ls -lh ~/ansible_workdir/boot-artifacts/ +``` + +**Expected files for PXE**: +- `agent.s390x-initrd.img` +- `agent.s390x-vmlinuz` (or `agent.s390x-kernel.img`) +- `agent.s390x-rootfs.img` + +**Expected files for ISO**: +- `agent.s390x.iso` + +Also verify files were copied to web server: + +```bash +ls -lh /var/www/html/ +``` + +## Validation Checklist + +### βœ… Configuration Validation + +- [ ] `installation_type: lpar` is set in all.yaml +- [ ] `abi.flag: True` is set +- [ ] Each node has host_vars file with `lpar.storage_group_1` configured +- [ ] `storage_group_1.type: fcp` is set for each node +- [ ] `dev_num`, `storage_wwpn`, and `lun_name` are properly formatted +- [ ] Node names in all.yaml match host_vars filenames + +### βœ… Generated agent-config.yaml Validation + +- [ ] File exists at `~/ansible_workdir/agent-config.yaml` on bastion +- [ ] Each host entry has `rootDeviceHints` section +- [ ] `deviceName` follows format: `/dev/disk/by-path/ccw-0.0.{dev_num}-fc-{wwpn}-lun-{lun}` +- [ ] Device paths are unique for each node (different LUNs) +- [ ] All control nodes have `role: master` +- [ ] All compute nodes have `role: worker` + +### βœ… Image Generation Validation + +- [ ] Images created in `~/ansible_workdir/boot-artifacts/` +- [ ] Images copied to `/var/www/html/` +- [ ] No errors in playbook output +- [ ] File sizes are reasonable (initrd ~100MB, rootfs ~1GB+) + +## Test Cases + +### Test Case 1: Single Control Node + +**Configuration**: +```yaml +# all.yaml +installation_type: lpar +env: + cluster: + nodes: + control: + vm_name: [control-1] + ip: [192.168.1.10] + mac: [02:00:00:00:00:01] + hostname: [control-1] + +# host_vars/control-1.yaml +lpar: + storage_group_1: + type: fcp + dev_num: "1a00" + storage_wwpn: ["0x500507680b2a5f7e"] + lun_name: "0x4000000000000000" +``` + +**Expected agent-config.yaml**: +```yaml +hosts: + - hostname: "control-1" + role: master + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4000000000000000 +``` + +### Test Case 2: Three Control Nodes with Different LUNs + +**Configuration**: +```yaml +# host_vars/control-1.yaml +lpar: + storage_group_1: + lun_name: "0x4000000000000000" + +# host_vars/control-2.yaml +lpar: + storage_group_1: + lun_name: "0x4001000000000000" + +# host_vars/control-3.yaml +lpar: + storage_group_1: + lun_name: "0x4002000000000000" +``` + +**Expected**: Each node gets unique rootDeviceHints with different LUN IDs + +### Test Case 3: Control + Compute Nodes + +**Expected**: Both control and compute nodes have rootDeviceHints with their respective storage configurations + +## Troubleshooting + +### Issue: Template Error - Cannot Load host_vars + +**Error Message**: +``` +fatal: [bastion]: FAILED! => {"msg": "An unhandled exception occurred..."} +``` + +**Solution**: +1. Check that host_vars file exists for each node +2. Verify filename matches exactly: `host_vars/control-1.yaml` (not `control-1.yml`) +3. Ensure YAML syntax is valid in host_vars files + +**Debug Command**: +```bash +# Check if file exists +ls -la inventories/default/host_vars/control-1.yaml + +# Validate YAML syntax +python3 -c "import yaml; yaml.safe_load(open('inventories/default/host_vars/control-1.yaml'))" +``` + +### Issue: No rootDeviceHints in agent-config.yaml + +**Possible Causes**: +1. `installation_type` is not set to `lpar` +2. `lpar.storage_group_1.type` is not `fcp` +3. host_vars file missing or incorrectly named + +**Debug Steps**: +```bash +# On bastion, check what variables are being used +ansible-playbook playbooks/create_abi_cluster.yaml -vvv | grep -A 10 "installation_type" +``` + +### Issue: Wrong Device Path Format + +**Problem**: Device path doesn't match expected format + +**Check**: +- dev_num should be "1a00" NOT "0.0.1a00" +- wwpn should include "0x" prefix: "0x500507680b2a5f7e" +- lun_name should include "0x" prefix: "0x4000000000000000" + +### Issue: Image Generation Fails + +**Check**: +1. OpenShift installer binary is downloaded +2. Pull secret is valid +3. Network connectivity from bastion +4. Sufficient disk space in ~/ansible_workdir + +**Debug**: +```bash +# Check installer +which openshift-install + +# Check disk space +df -h ~/ansible_workdir + +# Check pull secret +cat ~/.docker/config.json +``` + +## Comparison Test: KVM vs LPAR + +To verify backward compatibility, you can test both: + +### KVM Test (Should NOT have rootDeviceHints) + +```yaml +installation_type: kvm +abi: + flag: True +``` + +**Expected**: agent-config.yaml WITHOUT rootDeviceHints + +### LPAR Test (Should have rootDeviceHints) + +```yaml +installation_type: lpar +abi: + flag: True +``` + +**Expected**: agent-config.yaml WITH rootDeviceHints + +## Next Steps After Successful Testing + +Once you've verified: +1. βœ… agent-config.yaml has correct rootDeviceHints +2. βœ… Images generated successfully +3. βœ… No errors in playbook execution + +You can proceed to: +- Boot LPAR nodes with generated images +- Monitor installation progress +- Complete the full ABI installation + +## Reporting Issues + +If you encounter issues during testing: + +1. **Collect Information**: + - agent-config.yaml content + - Playbook output (with -vvv for verbose) + - host_vars configuration + - Error messages + +2. **Check Documentation**: + - `docs/abi-lpar-configuration.md` - Full guide + - `docs/ABI_LPAR_QUICK_REFERENCE.md` - Quick reference + +3. **Create GitHub Issue**: + - Include all collected information + - Specify OpenShift version + - Describe expected vs actual behavior + +## Success Criteria + +βœ… **Test is successful if**: +1. Playbook runs without errors +2. agent-config.yaml contains rootDeviceHints for each LPAR node +3. Device paths are correctly formatted +4. Images are generated and copied to web server +5. KVM installations still work without rootDeviceHints (if tested) + +--- + +**Good luck with testing!** πŸš€ + +Feel free to provide feedback on the implementation after testing. \ No newline at end of file diff --git a/docs/abi-lpar-configuration.md b/docs/abi-lpar-configuration.md new file mode 100644 index 000000000..e93fe2d0a --- /dev/null +++ b/docs/abi-lpar-configuration.md @@ -0,0 +1,310 @@ +# Agent-Based Installer (ABI) for LPAR Installations + +## Overview + +> **⚠️ Important Note**: This guide focuses specifically on the LPAR-specific `rootDeviceHints` configuration. For a complete setup, you must also configure all other required variables. See: +> - **Complete Variable Reference**: [set-variables-group-vars.md](set-variables-group-vars.md) and [set-variables-host-vars.md](set-variables-host-vars.md) +> - **Quick Start Guide**: [ABI_LPAR_QUICK_REFERENCE.md](ABI_LPAR_QUICK_REFERENCE.md) +> - **Full Setup Instructions**: [run-the-playbooks-for-abi.md](run-the-playbooks-for-abi.md) + + +This guide explains how to use Agent-Based Installer (ABI) for LPAR-based OpenShift installations on IBM Z/LinuxONE. The key difference between KVM and LPAR installations is the requirement for `rootDeviceHints` in the agent-config.yaml file. + +## Key Differences: KVM vs LPAR + +| Feature | KVM Installation | LPAR Installation | +|---------|------------------|-------------------| +| `rootDeviceHints` | Not required | **Required** for FCP storage | +| Storage Configuration | Virtual disks | Physical FCP/DASD storage | +| Device Path | Automatic | Must specify exact device path | + +## How It Works + +### Automatic rootDeviceHints Generation + +When `installation_type: lpar` is set, the automation will: + +1. Read each node's host_vars file (e.g., `host_vars/control-1.yaml`) +2. Extract FCP storage configuration from `lpar.storage_group_1` +3. Automatically generate `rootDeviceHints` in agent-config.yaml +4. Use the format: `/dev/disk/by-path/ccw-0.0.{dev_num}-fc-{wwpn}-lun-{lun_name}` + +### Configuration Flow + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Step 1: Configure host_vars for each LPAR node β”‚ +β”‚ File: inventories/default/host_vars/control-1.yaml β”‚ +β”‚ β”‚ +β”‚ lpar: β”‚ +β”‚ storage_group_1: β”‚ +β”‚ type: fcp β”‚ +β”‚ dev_num: "1a00" β”‚ +β”‚ storage_wwpn: β”‚ +β”‚ - "0x500507680b2a5f7e" β”‚ +β”‚ lun_name: "0x4000000000000000" β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + ↓ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Step 2: Set installation_type in all.yaml β”‚ +β”‚ File: inventories/default/group_vars/all.yaml β”‚ +β”‚ β”‚ +β”‚ installation_type: lpar β”‚ +β”‚ abi: β”‚ +β”‚ flag: True β”‚ +β”‚ boot_method: pxe β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + ↓ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Step 3: Template generates agent-config.yaml β”‚ +β”‚ Role: prepare_configs β”‚ +β”‚ β”‚ +β”‚ hosts: β”‚ +β”‚ - hostname: "control-1" β”‚ +β”‚ role: master β”‚ +β”‚ rootDeviceHints: β”‚ +β”‚ deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc- β”‚ +β”‚ 0x500507680b2a5f7e-lun-0x4000000000000000β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Configuration Requirements + +### 1. Set Installation Type + +In `inventories/default/group_vars/all.yaml`: + +```yaml +installation_type: lpar + +abi: + flag: True + ansible_workdir: 'ansible_workdir' + ocp_installer_version: '4.18.8' + ocp_installer_base_url: 'https://mirror.openshift.com/pub/openshift-v4' + architecture: multi # or s390x + boot_method: pxe +``` + +### 2. Configure LPAR Storage in Host Vars + +For **each** LPAR node (control and compute), create/update the host_vars file: + +**File**: `inventories/default/host_vars/control-1.yaml` + +```yaml +# ... other configuration ... + +lpar: + storage_group_1: + name: storage_group_1 + type: fcp # FCP storage (Fibre Channel Protocol) + storage_wwpn: + - "0x500507680b2a5f7e" # Primary WWPN + - "0x500507680b2a5f7f" # Additional WWPNs for multipath + - "0x500507680b2a5f80" + - "0x500507680b2a5f81" + dev_num: "1a00" # FCP device number + lun_name: "0x4000000000000000" # LUN ID +``` + +**Important Notes**: +- Only the **first WWPN** (`storage_wwpn[0]`) is used for rootDeviceHints +- All WWPNs are used for multipath configuration during boot +- The `dev_num` should be the FCP adapter device number (without "0.0." prefix) +- The `lun_name` is the LUN identifier in hexadecimal format + +### 3. Example for Multiple Nodes + +**Control Node 1**: `host_vars/control-1.yaml` +```yaml +lpar: + storage_group_1: + type: fcp + dev_num: "1a00" + storage_wwpn: + - "0x500507680b2a5f7e" + lun_name: "0x4000000000000000" +``` + +**Control Node 2**: `host_vars/control-2.yaml` +```yaml +lpar: + storage_group_1: + type: fcp + dev_num: "1a00" + storage_wwpn: + - "0x500507680b2a5f7e" + lun_name: "0x4001000000000000" # Different LUN +``` + +**Compute Node 1**: `host_vars/compute-1.yaml` +```yaml +lpar: + storage_group_1: + type: fcp + dev_num: "1a00" + storage_wwpn: + - "0x500507680b2a5f7e" + lun_name: "0x4002000000000000" # Different LUN +``` + +## Generated agent-config.yaml Example + +### For LPAR Installation + +```yaml +apiVersion: v1alpha1 +kind: AgentConfig +metadata: + name: ocp-cluster +rendezvousIP: + +hosts: + - hostname: "control-1" + role: master + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4000000000000000 + interfaces: + - name: eth0 + macAddress: "" + networkConfig: + # ... network configuration ... + + - hostname: "control-2" + role: master + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4001000000000000 + interfaces: + - name: eth0 + macAddress: "" + networkConfig: + # ... network configuration ... + + - hostname: "compute-1" + role: worker + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4002000000000000 + interfaces: + - name: eth0 + macAddress: "" + networkConfig: + # ... network configuration ... +``` + +### For KVM Installation (No rootDeviceHints) + +```yaml +apiVersion: v1alpha1 +kind: AgentConfig +metadata: + name: ocp-cluster +rendezvousIP: + +hosts: + - hostname: "control-1" + role: master + # No rootDeviceHints for KVM + interfaces: + - name: eth0 + macAddress: "" + networkConfig: + # ... network configuration ... +``` + +## Running the Playbooks + +### Complete LPAR ABI Installation + +```bash +# Run the master playbook for ABI +ansible-playbook playbooks/master_playbook_for_abi.yaml +``` + +This will: +1. Setup the environment (playbook 0) +2. Skip KVM host setup (only for installation_type: kvm) +3. Create bastion (playbook 4) +4. Setup bastion (playbook 5) +5. Create ABI cluster with rootDeviceHints for LPAR (create_abi_cluster.yaml) +6. Monitor installation (monitor_create_abi_cluster.yaml) + +### Individual Playbooks + +```bash +# 1. Setup bastion (same for KVM and LPAR) +ansible-playbook playbooks/4_create_bastion.yaml +ansible-playbook playbooks/5_setup_bastion.yaml + +# 2. Create ABI cluster (generates agent-config.yaml with rootDeviceHints for LPAR) +ansible-playbook playbooks/create_abi_cluster.yaml + +# 3. Monitor installation +ansible-playbook playbooks/monitor_create_abi_cluster.yaml +``` + +## Troubleshooting + +### Issue: rootDeviceHints not appearing in agent-config.yaml + +**Check**: +1. Verify `installation_type: lpar` is set in `all.yaml` +2. Ensure each node's host_vars file exists and has `lpar.storage_group_1` configured +3. Verify `lpar.storage_group_1.type: fcp` is set +4. Check that node names in `env.cluster.nodes.control.vm_name` match host_vars filenames + +### Issue: Wrong device path in rootDeviceHints + +**Verify**: +- `dev_num` format: Should be without "0.0." prefix (e.g., "1a00" not "0.0.1a00") +- `storage_wwpn[0]` format: Should include "0x" prefix (e.g., "0x500507680b2a5f7e") +- `lun_name` format: Should include "0x" prefix (e.g., "0x4000000000000000") + +### Issue: Template fails to load host_vars + +**Solution**: +Ensure host_vars files are named exactly as specified in `env.cluster.nodes.control.vm_name` and `env.cluster.nodes.compute.vm_name` arrays. + +Example: +```yaml +# In all.yaml +env: + cluster: + nodes: + control: + vm_name: + - control-1 # Must match: host_vars/control-1.yaml + - control-2 # Must match: host_vars/control-2.yaml +``` + +## DASD Storage Support + +Currently, the implementation focuses on FCP storage. For DASD storage: + +```yaml +lpar: + storage_group_1: + type: dasd + dev_num: "0190" +``` + +The rootDeviceHints for DASD would be: +```yaml +rootDeviceHints: + deviceName: /dev/dasda +``` + +**Note**: DASD support for ABI rootDeviceHints can be added if needed. Contact the maintainers for implementation. + +## Summary + +βœ… **For KVM**: No changes needed, rootDeviceHints are automatically excluded +βœ… **For LPAR**: Set `installation_type: lpar` and configure `lpar.storage_group_1` in each node's host_vars +βœ… **Automatic**: Template generates correct rootDeviceHints based on FCP storage configuration +βœ… **Reusable**: Same storage configuration used for both booting and ABI installation + +## References + +- [OpenShift Agent-Based Installer Documentation](https://docs.openshift.com/container-platform/latest/installing/installing_with_agent_based_installer/preparing-to-install-with-agent-based-installer.html) +- [IBM Z Storage Configuration](https://www.ibm.com/docs/en/linux-on-systems?topic=devices-fibre-channel-protocol) +- [Main Project Documentation](https://ibm.github.io/Ansible-OpenShift-Provisioning/) diff --git a/docs/index.md b/docs/index.md index 61865525f..1b3329b8e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,15 +1,8 @@ -# Ansible-Automated OpenShift Provisioning on IBM zSystems / LinuxONE +# Ansible-Automated OpenShift Provisioning on KVM on IBM zSystems / LinuxONE ## Overview -These Ansible Playbooks automate the setup and deployment of Red Hat OpenShift Container Platform (RHOCP) clusters on IBM zSystems / LinuxONE across multiple hypervisors and installation methods. -## Supported Configurations -| Hypervisor | Installation Methods | -|------------|---------------------| -| **KVM** | UPI, Agent-Based Installer (ABI), Hosted Control Plane (HCP) | -| **LPAR** | UPI, Agent-Based Installer (ABI), Hosted Control Plane (HCP) | -| **z/VM** | UPI, Hosted Control Plane (HCP) | +These Ansible Playbooks automate the setup and deployment of a Red Hat OpenShift Container Platform (RHOCP) cluster on IBM zSystems / LinuxONE with Kernel Virtual Machine (KVM) as the hypervisor. - ## Ready to Start? Use the left-hand panel to navigate the site. Start with the [Before You Begin](before-you-begin.md) page. ## Need Help? -Contact Amadeus Podvratnik at pod@de.ibm.com +Contact Amadeus Podvratnik at pod@de.ibm.com \ No newline at end of file diff --git a/docs/set-variables-group-vars.md b/docs/set-variables-group-vars.md index 7097c0a62..05c73d4b3 100644 --- a/docs/set-variables-group-vars.md +++ b/docs/set-variables-group-vars.md @@ -433,4 +433,4 @@ These parameters control the download of kubeconfig and kubepassw files from the :--- | :--- | :--- **kubeconfig_dest_dir** | Destination directory on the local controller where downloaded files will be stored. Files are stored in a `kubeconfig/` subdirectory within this path. | /tmp **kubeconfig_source_dir** | Source directory on the bastion host from which files will be downloaded. | ~/ocpinst/auth -**kubeconfig_files** | List of files to download from the bastion host. | ['kubeconfig', 'kubeadmin-password'] +**kubeconfig_files** | List of files to download from the bastion host. | ['kubeconfig', 'kubeadmin-password'] \ No newline at end of file diff --git a/inventories/default/group_vars/all.yaml.template b/inventories/default/group_vars/all.yaml.template index 0c6f71de0..190122712 100644 --- a/inventories/default/group_vars/all.yaml.template +++ b/inventories/default/group_vars/all.yaml.template @@ -233,12 +233,23 @@ day2_compute_node: # Section 14 - Agent Based Installer ( Optional ) +# For LPAR installations with ABI, the rootDeviceHints in agent-config.yaml will be +# automatically generated from the lpar.storage_group_1 configuration in each node's +# host_vars file. The deviceName will be constructed as: +# /dev/disk/by-path/ccw-0.0.{dev_num}-fc-{storage_wwpn[0]}-lun-{lun_name} +# +# Example for LPAR node: +# - Ensure each LPAR node's host_vars file has lpar.storage_group_1 configured +# - Set installation_type: lpar +# - The template will automatically add rootDeviceHints for FCP storage +# +# For KVM installations, rootDeviceHints are not needed and will not be added. abi: flag: False ansible_workdir: 'ansible_workdir' ocp_installer_version: '4.18.8' - ocp_installer_base_url: 'https://mirror.openshift.com/pub/openshift-v4/' - architecture: + ocp_installer_base_url: 'https://mirror.openshift.com/pub/openshift-v4' + architecture: boot_method: # Openshift Settings diff --git a/inventories/default/group_vars/secrets.yaml.template b/inventories/default/group_vars/secrets.yaml.template index 20b2a4d5c..6584f3d5b 100644 --- a/inventories/default/group_vars/secrets.yaml.template +++ b/inventories/default/group_vars/secrets.yaml.template @@ -3,15 +3,34 @@ # After editing this vault file run ansible-vault encrypt secrets.yaml to encrypt it. # # For a comprehensive description of each variable, please see documentation here: +# https://ibm.github.io/Ansible-OpenShift-Provisioning/set-variables-group-vars/ + +# All secrets use the vault_ prefix and are stored in a flat structure +# Non-secret values (like hostnames, IPs, usernames) should be in all.yaml or host_vars files # Section 1 - General Variables vault_ctl_host_sudo_pass: #X -# Section 2 - LPAR(s) +# Section 2 - LPAR(s) - KVM Host Passwords vault_lpar1_pass: #X vault_lpar2_pass: #X vault_lpar3_pass: #X +# Section 2.1 - LPAR Access Passwords (for host_vars) +# Used in host_vars files for LPAR user and root passwords +vault_lpar1_user_pass: #X +vault_lpar1_root_pass: #X +vault_lpar2_user_pass: #X +vault_lpar2_root_pass: #X +vault_lpar3_user_pass: #X +vault_lpar3_root_pass: #X + +# Section 2.2 - HMC Credentials (for LPAR boot automation) +# Required for ABI and RHCOS LPAR installations +# Note: HMC host and username are NOT secrets - define them in all.yaml or host_vars +vault_hmc_user: #X # HMC username +vault_hmc_pass: #X # HMC password + # Section 3 - File Server vault_file_server_pass: #X @@ -22,5 +41,8 @@ vault_rh_pass: #X vault_bastion_pass: #X vault_bastion_root_pass: #X -# Section 11 - (Optional) Misc +# Section 6 - Live Disk (for LPAR installations) +vault_livedisk_root_pass: #X + +# Section 7 - (Optional) Misc vault_jumphost_pass: #X diff --git a/inventories/default/host_vars/KVMhostname1-here.yaml.template b/inventories/default/host_vars/KVMhostname1-here.yaml.template index 703228ccf..06e3e23a1 100644 --- a/inventories/default/host_vars/KVMhostname1-here.yaml.template +++ b/inventories/default/host_vars/KVMhostname1-here.yaml.template @@ -29,19 +29,19 @@ storage: # Section 2 - CPC & HMC cpc_name: #X hmc: - host: #X + host: #X # HMC hostname or IP (not a secret) auth: - user: #X - pass: #X + user: #X # HMC username (not a secret) + pass: "{{ vault_hmc_pass }}" # HMC password (secret) # Section 3 - LPAR lpar: name: #X description: #X access: - user: #X - pass: #X - root_pass: #X + user: #X # LPAR username (not a secret) + pass: "{{ vault_lpar1_user_pass }}" # LPAR user password (secret) + root_pass: "{{ vault_lpar1_root_pass }}" # LPAR root password (secret) # Section 4 - IFL & Memory ifl: @@ -71,6 +71,19 @@ lpar: # dev_num: # Section 6 - Storage +# For LPAR installations, this storage configuration is used for: +# 1. Booting the LPAR nodes (boot_LPAR role) +# 2. Agent-Based Installer (ABI) rootDeviceHints in agent-config.yaml +# +# When using ABI with installation_type: lpar, the rootDeviceHints will be +# automatically generated as: +# deviceName: /dev/disk/by-path/ccw-0.0.{dev_num}-fc-{storage_wwpn[0]}-lun-{lun_name} +# +# Example values: +# dev_num: 1a00 +# storage_wwpn[0]: 0x500507680b2a5f7e +# lun_name: 0x4000000000000000 +# Results in: /dev/disk/by-path/ccw-0.0.1a00-fc-0x500507680b2a5f7e-lun-0x4000000000000000 storage_group_1: name: #X type: fcp @@ -93,14 +106,14 @@ lpar: # dev_num: # lun_name: -# Section 7 -live disk info +# Section 7 - Live disk info livedisk: - livedisktype: #X + livedisktype: #X lun: #X wwpn: #X devicenr: #X livediskuuid: #X Required when 'dpm_enabled' is true - livedisk_root_pass: #X + livedisk_root_pass: "{{ vault_livedisk_root_pass }}" # Live disk root password (secret) # Type of LPAR(dpm or pr/sm), 'True' if dpm. Allowed values ['True', 'False'] dpm_enabled: 'False' diff --git a/inventories/default/host_vars/KVMhostname2-here.yaml.template b/inventories/default/host_vars/KVMhostname2-here.yaml.template index 5416b9356..84791fd6d 100644 --- a/inventories/default/host_vars/KVMhostname2-here.yaml.template +++ b/inventories/default/host_vars/KVMhostname2-here.yaml.template @@ -29,19 +29,19 @@ storage: # Section 2 - CPC & HMC cpc_name: #X hmc: - host: #X + host: #X # HMC hostname or IP (not a secret) auth: - user: #X - pass: #X + user: #X # HMC username (not a secret) + pass: "{{ vault_hmc_pass }}" # HMC password (secret) # Section 3 - LPAR lpar: name: #X description: #X access: - user: #X - pass: #X - root_pass: #X + user: #X # LPAR username (not a secret) + pass: "{{ vault_lpar2_user_pass }}" # LPAR user password (secret) + root_pass: "{{ vault_lpar2_root_pass }}" # LPAR root password (secret) # Section 4 - IFL & Memory ifl: @@ -93,14 +93,14 @@ lpar: # dev_num: # lun_name: -# Section 7 -live disk info +# Section 7 - Live disk info livedisk: - livedisktype: #X + livedisktype: #X lun: #X wwpn: #X devicenr: #X livediskuuid: #X Required when 'dpm_enabled' is true - livedisk_root_pass: #X + livedisk_root_pass: "{{ vault_livedisk_root_pass }}" # Live disk root password (secret) # Type of LPAR(dpm or pr/sm), True if dpm. Allowed values ['True', 'False'] dpm_enabled: 'False' diff --git a/inventories/default/host_vars/KVMhostname3-here.yaml.template b/inventories/default/host_vars/KVMhostname3-here.yaml.template index e2f484b67..ac08761c0 100644 --- a/inventories/default/host_vars/KVMhostname3-here.yaml.template +++ b/inventories/default/host_vars/KVMhostname3-here.yaml.template @@ -29,19 +29,19 @@ storage: # Section 2 - CPC & HMC cpc_name: #X hmc: - host: #X + host: #X # HMC hostname or IP (not a secret) auth: - user: #X - pass: #X + user: #X # HMC username (not a secret) + pass: "{{ vault_hmc_pass }}" # HMC password (secret) # Section 3 - LPAR lpar: name: #X description: #X access: - user: #X - pass: #X - root_pass: #X + user: #X # LPAR username (not a secret) + pass: "{{ vault_lpar3_user_pass }}" # LPAR user password (secret) + root_pass: "{{ vault_lpar3_root_pass }}" # LPAR root password (secret) # Section 4 - IFL & Memory ifl: @@ -93,14 +93,14 @@ lpar: # dev_num: # lun_name: -# Section 7 -live disk info +# Section 7 - Live disk info livedisk: - livedisktype: #X + livedisktype: #X lun: #X wwpn: #X devicenr: #X livediskuuid: #X Required when 'dpm_enabled' is true - livedisk_root_pass: #X + livedisk_root_pass: "{{ vault_livedisk_root_pass }}" # Live disk root password (secret) # Type of LPAR(dpm or pr/sm), True if dpm. Allowed values ['True', 'False'] dpm_enabled: 'False' diff --git a/mkdocs.yaml b/mkdocs.yaml index 49a543e3d..0de5ede39 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -6,22 +6,24 @@ edit_uri: edit/main/docs nav: - Home: 'index.md' - Read Me: - - Before You Begin: 'before-you-begin.md' - - Prerequisites: 'prerequisites.md' + - Before You Begin: 'before-you-begin.md' + - Prerequisites: 'prerequisites.md' - Installation Instructions: - - 1 Get Info: 'get-info.md' - - 2 Set Variables (group_vars): 'set-variables-group-vars.md' - - 3 Set Variables (host_vars): 'set-variables-host-vars.md' - - 4 Run the Playbooks: 'run-the-playbooks.md' - - Run the Playbooks (Disconnected): 'run-the-playbooks-for-disconnected.md' - - Run the Playbooks (HostedControlPlane): 'run-the-playbooks-for-hcp.md' + - 1 Get Info: 'get-info.md' + - 2 Set Variables (group_vars): 'set-variables-group-vars.md' + - 3 Set Variables (host_vars): 'set-variables-host-vars.md' + - 4 Run the Playbooks: 'run-the-playbooks.md' + - Run the Playbooks (Agent-Based Installer): 'run-the-playbooks-for-abi.md' + - Run the Playbooks (Disconnected): 'run-the-playbooks-for-disconnected.md' + - Run the Playbooks (HostedControlPlane): 'run-the-playbooks-for-hcp.md' + - ABI LPAR Configuration: 'abi-lpar-configuration.md' - Misc: - - Troubleshooting: 'troubleshooting.md' - - Acknowledgements: 'acknowledgements.md' + - Troubleshooting: 'troubleshooting.md' + - Acknowledgements: 'acknowledgements.md' extra_css: - stylesheets/extra.css - + theme: name: readthedocs palette: @@ -41,4 +43,3 @@ markdown_extensions: - toc: permalink: "#" - attr_list - diff --git a/playbooks/3_setup_kvm_host.yaml b/playbooks/3_setup_kvm_host.yaml index 45a2eb69d..6f1659e2a 100644 --- a/playbooks/3_setup_kvm_host.yaml +++ b/playbooks/3_setup_kvm_host.yaml @@ -15,10 +15,12 @@ - name: Include vars for the KVM host. ansible.builtin.include_vars: file: "{{ inventory_dir }}/host_vars/{{ env.z.lpar1.hostname }}.yaml" + when: installation_type | lower in ['kvm', 'lpar'] - name: Copy SSH key to KVM host. ansible.builtin.import_role: name: ssh_copy_id + when: installation_type | lower in ['kvm', 'lpar'] - name: Copy SSH key to access KVM host 2 hosts: localhost @@ -35,13 +37,13 @@ - name: Include vars for second KVM host. ansible.builtin.include_vars: file: "{{ inventory_dir }}/host_vars/{{ env.z.lpar2.hostname }}.yaml" - when: env.z.lpar2.hostname is defined + when: installation_type | lower in ['kvm', 'lpar'] and env.z.lpar2.hostname is defined - name: copy SSH key to second KVM host, if cluster is to be highly available. tags: ssh_copy_id, ssh ansible.builtin.import_role: name: ssh_copy_id - when: env.z.lpar2.hostname is defined + when: installation_type | lower in ['kvm', 'lpar'] and env.z.lpar2.hostname is defined - name: Copy SSH key to access KVM host 3 hosts: localhost @@ -58,13 +60,13 @@ - name: Include vars for third KVM host. ansible.builtin.include_vars: file: "{{ inventory_dir }}/host_vars/{{ env.z.lpar3.hostname }}.yaml" - when: env.z.lpar3.hostname is defined + when: installation_type | lower in ['kvm', 'lpar'] and env.z.lpar3.hostname is defined - name: copy SSH key to third KVM host, if cluster is to be highly available. tags: ssh_copy_id, ssh ansible.builtin.import_role: name: ssh_copy_id - when: env.z.lpar3.hostname is defined + when: installation_type | lower in ['kvm', 'lpar'] and env.z.lpar3.hostname is defined - name: Prepare KVM host(s) hosts: kvm_host @@ -77,9 +79,12 @@ vars: packages: "pkgs_kvm" roles: - - { role: attach_subscription, when: env.redhat.manage_subscription } - - install_packages - - httpd + - role: attach_subscription + when: env.redhat.manage_subscription and installation_type | lower in ['kvm', 'lpar'] + - role: install_packages + when: installation_type | lower in ['kvm', 'lpar'] + - role: httpd + when: installation_type | lower in ['kvm', 'lpar'] post_tasks: - name: Add ports to firewall tags: firewall-libvirt, libvirt @@ -87,6 +92,7 @@ port: 80/tcp permanent: true state: enabled + when: installation_type | lower in ['kvm', 'lpar'] - name: Start and enable libvirt tags: firewall-libvirt, libvirt @@ -94,6 +100,7 @@ name: libvirtd enabled: true state: started + when: installation_type | lower in ['kvm', 'lpar'] - name: Permit traffic in libvirt zone tags: firewall-libvirt, libvirt @@ -103,6 +110,7 @@ state: enabled zone: libvirt immediate: true + when: installation_type | lower in ['kvm', 'lpar'] - name: Set libvirt management to libvirt group instead of root. tags: libvirt @@ -111,26 +119,31 @@ regexp: '#group = "root"' line: 'group = "libvirt"' backup: true + when: installation_type | lower in ['kvm', 'lpar'] - - name: Get user home directory + - name: Get user home directory tags: libvirt - ansible.builtin.shell: > - getent passwd {{ ansible_user }} | awk -F: '{ print $6 }' + ansible.builtin.shell: | + set -o pipefail + getent passwd {{ ansible_user }} | awk -F: '{ print $6 }' changed_when: false register: user_home + when: installation_type | lower in ['kvm', 'lpar'] - - name: Check if directory {{ user_home.stdout }}/.config/libvirt exists + - name: Check if .config/libvirt directory exists tags: libvirt ansible.builtin.stat: - path: "{{ user_home.stdout }}/.config/libvirt" + path: "{{ user_home.stdout }}/.config/libvirt" register: home_config_libvirt + when: installation_type | lower in ['kvm', 'lpar'] - - name: Create directory {{ user_home.stdout }}/.config/libvirt + - name: Create .config/libvirt directory tags: libvirt - ansible.builtin.file: + ansible.builtin.file: path: "{{ user_home.stdout }}/.config/libvirt" state: directory - when: home_config_libvirt.stat.exists == false + mode: '0755' + when: installation_type | lower in ['kvm', 'lpar'] and not home_config_libvirt.stat.exists - name: Create file for user's custom libvirt configurations. tags: libvirt @@ -139,6 +152,8 @@ state: touch owner: "{{ ansible_user }}" group: "{{ ansible_user }}" + mode: '0644' + when: installation_type | lower in ['kvm', 'lpar'] - name: Set default uri connection to qemu:///system. tags: libvirt @@ -151,6 +166,7 @@ - /etc/libvirt/qemu.conf - "{{ user_home.stdout }}/.config/libvirt/libvirt.conf" - /etc/libvirt/libvirt.conf + when: installation_type | lower in ['kvm', 'lpar'] - name: Ensure KVM admin user is part of groups 'kvm', 'libvirt'. tags: groups, group, libvirt @@ -158,6 +174,7 @@ name: "{{ ansible_user }}" append: true groups: kvm,libvirt + when: installation_type | lower in ['kvm', 'lpar'] - name: Restart libvirt tags: firewall-libvirt, libvirt @@ -165,10 +182,15 @@ name: libvirtd enabled: true state: restarted + when: installation_type | lower in ['kvm', 'lpar'] - name: Enable cockpit console tags: cockpit - ansible.builtin.command: systemctl enable --now cockpit.socket + ansible.builtin.systemd: + name: cockpit.socket + enabled: true + state: started + when: installation_type | lower in ['kvm', 'lpar'] - name: Configure ip_forward in case of NAT hosts: kvm_host @@ -187,7 +209,7 @@ sysctl_set: true state: present reload: true - when: env.network_mode | upper == 'NAT' + when: installation_type | lower in ['kvm', 'lpar'] and env.network_mode | upper == 'NAT' - name: "Configure storage and network for macvtap" hosts: kvm_host @@ -197,5 +219,7 @@ - "{{ inventory_dir }}/group_vars/all.yaml" - "{{ inventory_dir }}/group_vars/secrets.yaml" roles: - - configure_storage - - { role: macvtap, when: env.network_mode | lower == 'macvtap' } + - role: configure_storage + when: installation_type | lower in ['kvm', 'lpar'] + - role: macvtap + when: installation_type | lower in ['kvm', 'lpar'] and env.network_mode | lower == 'macvtap' diff --git a/playbooks/5_setup_bastion.yaml b/playbooks/5_setup_bastion.yaml index 9e9c97cdc..81c2bfa7d 100644 --- a/playbooks/5_setup_bastion.yaml +++ b/playbooks/5_setup_bastion.yaml @@ -31,7 +31,8 @@ passphrase: "" regenerate: never when: (env.network_mode | upper == "NAT") and (env.jumphost.ip is not none) - - block: + - name: Check jumphost package dependencies + block: - name: Gather package facts on jumphost ansible.builtin.package_facts: manager: auto @@ -47,7 +48,7 @@ msg: "'expect' package is not installed on jumphost" when: (env.network_mode | upper == "NAT") and (env.jumphost.ip is not none) and (not expect_installed) rescue: - - name: Package 'expect' must be installed on the jumphost, attempting to install it. #Using 'block' and 'rescue' to avoid running the 'package' module (which requires 'sudo') unless necessary. + - name: Package 'expect' must be installed on the jumphost, attempting to install it. become: true ansible.builtin.package: name: expect @@ -55,7 +56,8 @@ roles: - { role: ssh_copy_id, ssh, when: (env.network_mode | upper == "NAT") and (env.jumphost.ip is not none) } post_tasks: - - meta: clear_facts + - name: Clear facts after jumphost setup + ansible.builtin.meta: clear_facts - name: 5 setup bastion - copy SSH key from localhost to access bastion (non-NAT only). hosts: localhost @@ -88,29 +90,43 @@ - "{{ inventory_dir }}/group_vars/all.yaml" - "{{ inventory_dir }}/group_vars/secrets.yaml" tasks: - - name: Enabliling the HiperSocket card on bastion if installation_type is lpar else will be skipped. - block: - - name: Getting the Hipervisor Details - ansible.builtin.command: lscpu - register: hipervisor_info - - name: Fail the play if bastion is on the KVM guest - ansible.builtin.fail: - msg: Currently not supported for LPAR clsuter with this particular mode when bastion is on KVM host. - when: "'KVM' in hipervisor_info.stdout" - - name: Check if vars file exists - ansible.builtin.stat: - path: "{{ inventory_dir }}/host_vars/{{ env.cluster.nodes.bootstrap.vm_name }}.yaml" - register: vars_file - delegate_to: localhost - - name: Include the vars - ansible.builtin.include_vars: - file: "{{ inventory_dir }}/host_vars/{{ env.cluster.nodes.bootstrap.vm_name }}.yaml" - when: vars_file.stat.exists - - name: Attaching HiperSocket card to bastion - ansible.builtin.include_tasks: - file: ../roles/bastion_setup_hipersocket_LPAR/tasks/main.yml - when: vars_file.stat.exists and networking.mode is defined and networking.mode | lower =='hipersocket' - when: installation_type | lower == "lpar" + - name: Enabliling the HiperSocket card on bastion if installation_type is lpar else will be skipped. + when: installation_type | lower == 'lpar' + block: + - name: Getting the Hipervisor Details + ansible.builtin.command: lscpu + register: hipervisor_info + changed_when: false + + - name: Fail the play if bastion is on the KVM guest (only for non-ABI HiperSocket setups) + ansible.builtin.fail: + msg: Currently not supported for LPAR cluster with this particular mode when bastion is on KVM host. + when: + - "'KVM' in hipervisor_info.stdout" + - abi.flag is not defined or not abi.flag + + - name: Check if vars file exists + ansible.builtin.stat: + path: "{{ inventory_dir }}/host_vars/{{ env.cluster.nodes.bootstrap.vm_name }}.yaml" + register: vars_file + delegate_to: localhost + when: env.cluster.nodes.bootstrap is defined + + - name: Include the vars + ansible.builtin.include_vars: + file: "{{ inventory_dir }}/host_vars/{{ env.cluster.nodes.bootstrap.vm_name }}.yaml" + when: + - env.cluster.nodes.bootstrap is defined + - vars_file.stat.exists + + - name: Attaching HiperSocket card to bastion + ansible.builtin.include_tasks: + file: ../roles/bastion_setup_hipersocket_LPAR/tasks/main.yml + when: + - env.cluster.nodes.bootstrap is defined + - vars_file.stat.exists + - networking.mode is defined + - networking.mode | lower == 'hipersocket' - name: 5 setup bastion - configure bastion node with essential services hosts: bastion @@ -140,7 +156,8 @@ - httpd - { role: install_tessia_baselib, when: ( installation_type|lower == "lpar" ) or ( installation_type|lower == "zvm" ) } -- hosts: bastion +- name: Setup OpenVPN on bastion + hosts: bastion tags: services, section_2, openvpn become: true vars_files: @@ -149,11 +166,16 @@ vars: openvpn_role: "server" roles: - #- { role: robertdebock.bootstrap, tags: openvpn, when: env.z.high_availability == True } - - { role: robertdebock.epel, tags: openvpn, when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" } - - { role: robertdebock.openvpn, tags: openvpn, when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" } + # - { role: robertdebock.bootstrap, tags: openvpn, when: env.z.high_availability } + - role: robertdebock.epel + tags: openvpn + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" + - role: robertdebock.openvpn + tags: openvpn + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" -- hosts: localhost +- name: Create OpenVPN cert landing dirs on localhost + hosts: localhost tags: services, section_2, openvpn gather_facts: false vars_files: @@ -165,9 +187,11 @@ ansible.builtin.file: state: directory path: tmp - when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" + mode: '0755' + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" -- hosts: bastion +- name: Fetch OpenVPN certs from bastion + hosts: bastion tags: services, section_2, openvpn become: true vars_files: @@ -179,13 +203,13 @@ ansible.builtin.fetch: src: /etc/openvpn/easy-rsa/pki/{{ item }} dest: tmp/ - flat: yes + flat: true loop: - ca.crt - issued/client.crt - private/client.key - ta.key - when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" - name: setup OpenVPN on KVM host(s). hosts: kvm_host @@ -201,36 +225,44 @@ pre_tasks: - name: Gather facts. ansible.builtin.setup: - when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" - name: Create landing directories for certificates and keys on KVM hosts. tags: openvpn ansible.builtin.file: state: directory path: /etc/openvpn/client/{{ item }} - mode: '700' + mode: '0700' loop: - issued - private - when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" - name: Copy certificates and keys from controller to KVM hosts. tags: openvpn ansible.builtin.copy: src: tmp/{{ item }} dest: /etc/openvpn/client/{{ item }} - mode: '600' + mode: '0600' loop: - ca.crt - client.crt - client.key - ta.key - when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "zvm" and installation_type|lower != "lpar" + when: >- + env.setup_openvpn and env.z.high_availability + and installation_type | lower != "zvm" + and installation_type | lower != "lpar" roles: - - { role: robertdebock.epel, tags: openvpn, when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" } - - { role: robertdebock.openvpn, tags: openvpn, when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" } + - role: robertdebock.epel + tags: openvpn + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" + - role: robertdebock.openvpn + tags: openvpn + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" -- hosts: localhost +- name: Clean up OpenVPN temp files on localhost + hosts: localhost tags: services, section_2, openvpn gather_facts: false vars_files: @@ -242,9 +274,10 @@ ansible.builtin.file: state: absent path: tmp - when: env.setup_openvpn == True and env.z.high_availability == True and installation_type|lower != "lpar" + when: env.setup_openvpn and env.z.high_availability and installation_type | lower != "lpar" -- hosts: bastion +- name: 5 setup bastion - get OCP + hosts: bastion tags: get_ocp, section_3 become: true vars_files: diff --git a/playbooks/create_abi_cluster.yaml b/playbooks/create_abi_cluster.yaml index 512b24ea5..bca56626e 100644 --- a/playbooks/create_abi_cluster.yaml +++ b/playbooks/create_abi_cluster.yaml @@ -1,5 +1,4 @@ --- - # ABI Installation Proccess. - name: ABI Installation Proccess hosts: bastion @@ -10,11 +9,13 @@ - "{{ inventory_dir }}/group_vars/zvm.yaml" - "{{ inventory_dir }}/group_vars/disconnected.yaml" roles: - - common # Common Variable the will be used by all the inwalked roles. - - { role: offline_artifacts, when: disconnected.enabled } # Update CA Certificates & Download OCP Packages - - { role: download_ocp_installer, when: not disconnected.enabled } # Download Openshift Installer. - - prepare_configs # Prepare AgentConfig & InstallConfig. - - create_agent # Create Agents || Build initrd.img, rootfs.img & kernelfs.img. + - common # Common Variable the will be used by all the inwalked roles. + - role: offline_artifacts + when: disconnected.enabled # Update CA Certificates & Download OCP Packages + - role: download_ocp_installer + when: not disconnected.enabled # Download Openshift Installer. + - prepare_configs # Prepare AgentConfig & InstallConfig. + - create_agent # Create Agents || Build initrd.img, rootfs.img & kernelfs.img. - name: Start z/VM Nodes hosts: bastion @@ -42,10 +43,40 @@ - "{{ inventory_dir }}/group_vars/secrets.yaml" roles: - common - - { role: boot_abi_agents, when: installation_type | lower == 'kvm' } + - role: boot_abi_agents + when: installation_type | lower == 'kvm' + +# Boot ABI LPAR Agents. +- name: Boot ABI LPAR Agents + hosts: bastion + become: false + vars_files: + - "{{ inventory_dir }}/group_vars/all.yaml" + - "{{ inventory_dir }}/group_vars/secrets.yaml" + tasks: + - name: Support for LPAR ABI + when: installation_type | lower == 'lpar' and abi.flag is defined and abi.flag is true + block: + - name: Boot LPAR control nodes with ABI agent + ansible.builtin.include_role: + name: boot_LPAR_abi + loop: "{{ env.cluster.nodes.control.vm_name }}" + loop_control: + loop_var: item + + - name: Boot LPAR compute nodes with ABI agent + ansible.builtin.include_role: + name: boot_LPAR_abi + loop: "{{ env.cluster.nodes.compute.vm_name | default([]) }}" + loop_control: + loop_var: item - name: Setup SSH agent tags: ssh_to_nodes hosts: bastion + become: false + vars_files: + - "{{ inventory_dir }}/group_vars/all.yaml" + - "{{ inventory_dir }}/group_vars/secrets.yaml" roles: - ssh_agent diff --git a/playbooks/master_playbook_for_abi.yaml b/playbooks/master_playbook_for_abi.yaml index ec033b077..0470ef9a8 100644 --- a/playbooks/master_playbook_for_abi.yaml +++ b/playbooks/master_playbook_for_abi.yaml @@ -1,12 +1,18 @@ # Master playbook For ABI . If you want to do everything all in one, use this. --- -- import_playbook: 0_setup.yaml # Import Playbook To Generate Inventory & Adding SSH-Keys. -- import_playbook: 3_setup_kvm_host.yaml # Import Playbook To Install Prerequisites On KVM_HOST. - when: ( installation_type | lower == "kvm" ) -- import_playbook: 4_create_bastion.yaml # Import Playbook To Create Bastion. -- import_playbook: 5_setup_bastion.yaml # Import Playbook To Configure Bastion. -- import_playbook: disconnected_mirror_artifacts.yaml +- name: 0 - Setup inventory and SSH keys + import_playbook: 0_setup.yaml +- name: 3 - Setup KVM host prerequisites + import_playbook: 3_setup_kvm_host.yaml +- name: 4 - Create bastion + import_playbook: 4_create_bastion.yaml +- name: 5 - Setup bastion + import_playbook: 5_setup_bastion.yaml +- name: Mirror disconnected artifacts + import_playbook: disconnected_mirror_artifacts.yaml when: disconnected.enabled -- import_playbook: create_abi_cluster.yaml # Import Playbook To Create ABI Cluster. -- import_playbook: monitor_create_abi_cluster.yaml # Import Playbook To Monitor ABI Cluster Installation. +- name: Create ABI cluster + import_playbook: create_abi_cluster.yaml +- name: Monitor ABI cluster installation + import_playbook: monitor_create_abi_cluster.yaml diff --git a/roles/boot_LPAR/templates/boot_lpar.py b/roles/boot_LPAR/templates/boot_lpar.py index 23edb3222..d9489fe48 100644 --- a/roles/boot_LPAR/templates/boot_lpar.py +++ b/roles/boot_LPAR/templates/boot_lpar.py @@ -37,10 +37,11 @@ def list_of_strings(arg): -# cpc_name = "a46" # this is the CEC/CPC hosting the target LPAR -# hmc_address = "hmca2.boeblingen.de.ibm.com" # URL where HMC API is running -# hmc_user = "" -# hmc_password = "" +# Example usage: +# cpc_name = "CPC_NAME" # this is the CEC/CPC hosting the target LPAR +# hmc_address = "hmc.example.com" # URL where HMC API is running +# hmc_user = "username" +# hmc_password = "password" # Currently there are no parameters for instantiating a hmc hypervisor hypervisor_params = None hmc = hmc.HypervisorHmc(args.cpcname, args.hmchost, diff --git a/roles/boot_LPAR/templates/genericdvd.prm.j2 b/roles/boot_LPAR/templates/genericdvd.prm.j2 new file mode 100644 index 000000000..61c34e373 --- /dev/null +++ b/roles/boot_LPAR/templates/genericdvd.prm.j2 @@ -0,0 +1 @@ +rd.neednet=1 cio_ignore=all,!condev ai.ip_cfg_override=1 console=ttysclp0 coreos.live.rootfs_url=http://{% if node.networking.mode | lower == "hipersocket" %}{{ env.bastion.networking.internal_ip }}{% else %}{{ env.bastion.networking.ip }}{% endif %}:8080/agent.{{ ansible_architecture }}-rootfs.img ip={{ node.networking.ip }}::{{ node.networking.gateway }}:{{ node.networking.subnetmask }}::{{ node.networking.device1 }}:none nameserver={% if node.networking.mode | lower == "hipersocket" %}{{ env.bastion.networking.internal_ip }}{% else %}{{ node.networking.nameserver1 }}{% endif %} zfcp.allow_lun_scan=0 rd.znet=qeth,{{ node.lpar.networking.nic.card1.dev_num }},layer2=1{% if node.lpar.storage_group_1.type | lower == "fcp" %} rd.zfcp=0.0.{{ node.lpar.storage_group_1.dev_num }},{{ node.lpar.storage_group_1.storage_wwpn[0] }},{{ node.lpar.storage_group_1.lun_name }}{% endif %} random.trust_cpu=on rd.luks.options=discard ignition.firstboot ignition.platform.id=metal \ No newline at end of file diff --git a/roles/boot_LPAR_abi/defaults/main.yaml b/roles/boot_LPAR_abi/defaults/main.yaml new file mode 100644 index 000000000..6c7620bf7 --- /dev/null +++ b/roles/boot_LPAR_abi/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +# ABI agent images are served from bastion httpd server +# No specific defaults needed as URLs are constructed dynamically diff --git a/roles/boot_LPAR_abi/tasks/main.yaml b/roles/boot_LPAR_abi/tasks/main.yaml new file mode 100644 index 000000000..6756ed86f --- /dev/null +++ b/roles/boot_LPAR_abi/tasks/main.yaml @@ -0,0 +1,100 @@ +--- +# ABI-specific LPAR boot tasks +- name: Set fcp fact to empty for ABI + ansible.builtin.set_fact: + rd_zfcp_string: '' + +- name: Include host vars for given lpar + ansible.builtin.include_vars: + file: "{{ inventory_dir }}/host_vars/{{ item }}.yaml" + name: node + +- name: Getting boot script for ABI + ansible.builtin.template: + src: boot_lpar.py + dest: /root/ansible_workdir/boot_lpar_abi.py + mode: '0755' + +- name: Generate genericdvd.prm file for ABI + ansible.builtin.template: + src: genericdvd.prm.j2 + dest: /root/ansible_workdir/genericdvd.prm + mode: '0644' + +- name: Read genericdvd.prm content + ansible.builtin.slurp: + src: /root/ansible_workdir/genericdvd.prm + register: prm_content + +- name: Set cmdline from genericdvd.prm + ansible.builtin.set_fact: + abi_cmdline: "{{ prm_content['content'] | b64decode | trim }}" + +- name: Set live disk lun for ABI + ansible.builtin.set_fact: + live_disk_lun: >- + {{ node.lpar.livedisk.lun + if (node.lpar.livedisk.lun is defined and node.lpar.livedisk.lun is not none) + else 'na' }} + +- name: Set live disk wwpn for ABI + ansible.builtin.set_fact: + live_disk_wwpn: >- + {{ node.lpar.livedisk.wwpn + if (node.lpar.livedisk.wwpn is defined and node.lpar.livedisk.wwpn is not none) + else 'na' }} + +- name: Set live disk UUID for ABI + ansible.builtin.set_fact: + live_disk_uuid: >- + {{ node.lpar.livedisk.livediskuuid + if (node.lpar.livedisk.livediskuuid is defined and node.lpar.livedisk.livediskuuid is not none) + else '' }} + +- name: Debug ABI boot command + ansible.builtin.debug: + msg: "Booting LPAR {{ node.lpar.name }} with ABI agent" + +- name: Booting LPAR node with ABI agent + ansible.builtin.shell: | + set -o pipefail + python3 /root/ansible_workdir/boot_lpar_abi.py \ + --cpcname {{ node.cpc_name }} \ + --lparname {{ node.lpar.name }} \ + --hmchost {{ node.hmc.host }} \ + --hmcuser {{ node.hmc.auth.user }} \ + --hmcpass {{ node.hmc.auth.pass }} \ + --cpu {{ node.lpar.ifl.count }} \ + --memory {{ node.lpar.ifl.initial_memory }} \ + --kernel http://{{ env.bastion.networking.ip }}:8080/agent.{{ ansible_architecture }}-vmlinuz \ + --initrd http://{{ env.bastion.networking.ip }}:8080/agent.{{ ansible_architecture }}-initrd.img \ + --livedisktype {{ node.lpar.livedisk.livedisktype }} \ + --devicenr {{ node.lpar.livedisk.devicenr }} \ + {% if node.lpar.dpm_enabled == 'True' %} + --dpm_enabled {{ node.lpar.dpm_enabled }} \ + --livediskuuid {{ live_disk_uuid }} \ + {% endif %} + {% if node.lpar.livedisk.livedisktype | lower == 'scsi' %} + --livedisklun {{ live_disk_lun }} \ + --livediskwwpn {{ live_disk_wwpn }} \ + {% endif %} + --netset_ip {{ node.networking.ip }} \ + --netset_gateway {{ node.networking.gateway }} \ + --netset_network_type osa \ + --netset_network_device "{{ node.lpar.networking.nic.card1.dev_num }}" \ + --netset_password {{ node.lpar.livedisk.livedisk_root_pass }} \ + --netset_dns "{{ node.networking.nameserver1 }},{{ node.networking.nameserver2 }}" \ + --log_level DEBUG \ + --cmdline "{{ abi_cmdline }}" + register: boot_result + changed_when: true + timeout: "{{ abi_lpar_boot_timeout | default(900) }}" + +- name: Pause after booting LPAR node with ABI agent + ansible.builtin.pause: + seconds: "{{ abi_lpar_boot_pause_seconds | default(90) }}" + when: abi_lpar_boot_pause_seconds | default(90) | int > 0 + +- name: Display boot result + ansible.builtin.debug: + var: boot_result diff --git a/roles/boot_LPAR_abi/templates/boot_lpar.py b/roles/boot_LPAR_abi/templates/boot_lpar.py new file mode 100644 index 000000000..a39f5ea71 --- /dev/null +++ b/roles/boot_LPAR_abi/templates/boot_lpar.py @@ -0,0 +1,94 @@ +from tessia.baselib.hypervisors.hmc import hmc +import logging +import argparse + +def list_of_strings(arg): + return arg.split(',') + +parser = argparse.ArgumentParser(description="Get the environment.") + +parser.add_argument("--cpcname", type=str, help="this is the CEC/CPC hosting the target LPAR") +parser.add_argument("--lparname", type=str, help="Hypervisor name", required=True) +parser.add_argument("--hmchost", type=str, help="HMC Hostname or IP, enter the hmc url here", required=True) +parser.add_argument("--hmcuser", type=str, help="HMC user", required=True) +parser.add_argument("--hmcpass", type=str, help="HMC user password", required=True) +parser.add_argument("--cpu", type=int, help="number of Guest CPUs", required=True) +parser.add_argument("--memory", type=int, help="Guest memory in MB", required=True) +parser.add_argument("--kernel", type=str, help="kernel URI", required=True, default='') +parser.add_argument("--cmdline", type=str, help="kernel cmdline", required=True, default='') +parser.add_argument("--initrd", type=str, help="Initrd URI", required=True, default='') + +#live disk info +parser.add_argument("--dpm_enabled", type=str, help="True if CPC is dpm enabled", default='False') +parser.add_argument("--livediskuuid", type=str, help="UUID of the scsi device required for DPM lpars only", default='') +parser.add_argument("--livedisktype", type=str, help="Can be of type dasd or scsi", required=True, default='') +parser.add_argument("--devicenr", type=str, help="deviceenr for the live disk image", default='') +parser.add_argument("--netset_ip", type=str, help="network setup ip for the live image") +parser.add_argument("--netset_gateway", type=str) +parser.add_argument("--netset_network_type", type=str, help="could be of type osa or pci") +parser.add_argument("--netset_network_device", type=str, help="network device id") +parser.add_argument("--netset_password", type=str, help="live disk password") +parser.add_argument("--netset_dns", type=list_of_strings, help="comma seperated list of dns addresss in order") +parser.add_argument("--livedisklun", type=str, help="Lun id when the disk type is scsi and will be na when disktype is dasd", default='') +parser.add_argument("--livediskwwpn", type=str, help="wwpn id of the scsi disk and will be na when disktype is dasd", default='') + +parser.add_argument("--log_level", type=str, help="can be of type INFO or DEBUG") +args = parser.parse_args() + +# Example usage: +# cpc_name = "CPC_NAME" # this is the CEC/CPC hosting the target LPAR +# hmc_address = "hmc.example.com" # URL where HMC API is running +# hmc_user = "username" +# hmc_password = "password" +# Currently there are no parameters for instantiating a hmc hypervisor +hypervisor_params = None +hmc = hmc.HypervisorHmc(args.cpcname, args.hmchost, + args.hmcuser, args.hmcpass, hypervisor_params) + +# enable below block for debug output +if args.log_level == "DEBUG": + consoleHandler=logging.StreamHandler() + consoleHandler.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + consoleHandler.setFormatter(formatter) + hmc._logger.addHandler(consoleHandler) + hmc._logger.setLevel(logging.DEBUG) +# We must be logged in before submitting any command. +hmc.login() + +# Here we define the parameters of the guest to be started. +lpar_name = args.lparname +lpar_cpu = args.cpu +lpar_memory = args.memory +lpar_parameters = { + "boot_params": { + "boot_method": args.livedisktype.lower(), + 'netsetup': { + "mac": None, + "ip": args.netset_ip, + "mask": 16, + "gateway": args.netset_gateway, + "type": args.netset_network_type, # also accepts 'pci' + "device": args.netset_network_device, # enter the function id when type is 'pci' + "password": args.netset_password, + "dns": args.netset_dns, + }, + 'netboot': { + "cmdline": args.cmdline, + "kernel_url": args.kernel, + "initrd_url": args.initrd + } + } +} +if args.livedisktype.lower() == "dasd" and args.livedisklun == "na" and args.livediskwwpn == "na": + lpar_parameters["boot_params"]["devicenr"] = args.devicenr +elif args.livedisktype.lower() == "scsi" and args.livedisklun != "na" and args.livediskwwpn != "na": + lpar_parameters["boot_params"]["lun"] = args.livedisklun + lpar_parameters["boot_params"]["wwpn"] = args.livediskwwpn + lpar_parameters["boot_params"]["devicenr"] = args.devicenr + lpar_parameters["boot_params"]["uuid"] = args.livediskuuid +else: + raise Exception("Please check the live disk details") +hmc.start(lpar_name, lpar_cpu, lpar_memory, lpar_parameters) +hmc.logoff() + diff --git a/roles/boot_LPAR_abi/templates/genericdvd.prm.j2 b/roles/boot_LPAR_abi/templates/genericdvd.prm.j2 new file mode 100644 index 000000000..9748d126a --- /dev/null +++ b/roles/boot_LPAR_abi/templates/genericdvd.prm.j2 @@ -0,0 +1 @@ +rd.neednet=1 cio_ignore=all,!condev ai.ip_cfg_override=1 console=ttysclp0 coreos.live.rootfs_url=http://{% if node.networking.mode | lower == "hipersocket" %}{{ env.bastion.networking.internal_ip }}{% else %}{{ env.bastion.networking.ip }}{% endif %}:8080/agent.{{ ansible_architecture }}-rootfs.img ip={{ node.networking.ip }}::{{ node.networking.gateway }}:{{ node.networking.subnetmask }}::{{ node.networking.device1 }}:none nameserver={% if node.networking.mode | lower == "hipersocket" %}{{ env.bastion.networking.internal_ip }}{% else %}{{ node.networking.nameserver1 }}{% endif %} zfcp.allow_lun_scan=0 rd.znet=qeth,{{ node.lpar.networking.nic.card1.dev_num }},layer2=1{% if node.lpar.storage_group_1.type | lower == "fcp" %} rd.zfcp=0.0.{{ node.lpar.storage_group_1.dev_num }},{{ node.lpar.storage_group_1.storage_wwpn[0] }},{{ node.lpar.storage_group_1.lun_name }}{% endif %} random.trust_cpu=on rd.luks.options=discard ignition.firstboot ignition.platform.id=metal diff --git a/roles/boot_abi_agents/tasks/main.yml b/roles/boot_abi_agents/tasks/main.yml index 655a57cd3..49bbe96d3 100644 --- a/roles/boot_abi_agents/tasks/main.yml +++ b/roles/boot_abi_agents/tasks/main.yml @@ -126,12 +126,12 @@ --noautoconsole async: 3600 poll: 0 - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} stride=1 + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: true index_var: i + loop_var: i pause: 10 - when: env.cluster.nodes.compute is defined and abi.boot_method | lower == "pxe" + when: env.cluster.nodes.compute is defined and (env.cluster.nodes.compute.hostname | length) > 0 and abi.boot_method | lower == "pxe" - name: Create CoreOS Compute Agent Nodes On The KVM host using ISO boot. ansible.builtin.shell: | @@ -153,9 +153,9 @@ --wait=-1 \ async: 3600 poll: 0 - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} stride=1 + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: true index_var: i + loop_var: i pause: 10 - when: env.cluster.nodes.compute is defined and abi.boot_method | lower == "iso" + when: env.cluster.nodes.compute is defined and (env.cluster.nodes.compute.hostname | length) > 0 and abi.boot_method | lower == "iso" diff --git a/roles/check_dns/tasks/main.yaml b/roles/check_dns/tasks/main.yaml index a9a9414a9..547df0118 100644 --- a/roles/check_dns/tasks/main.yaml +++ b/roles/check_dns/tasks/main.yaml @@ -102,14 +102,13 @@ dig +short {{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }} | tail -n1 register: compute_lookup failed_when: env.cluster.nodes.compute.ip[i] != compute_lookup.stdout - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} stride=1 + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: true index_var: i + loop_var: i when: - env.cluster.nodes.compute.hostname is defined - - env.cluster.nodes.compute.hostname[0] is defined - - env.cluster.nodes.compute.hostname[0] != none + - (env.cluster.nodes.compute.hostname | length) > 0 - name: Check infrastructure nodes DNS resolution tags: check_dns, dns diff --git a/roles/create_agent/tasks/main.yml b/roles/create_agent/tasks/main.yml index c771eaa01..4dd762254 100644 --- a/roles/create_agent/tasks/main.yml +++ b/roles/create_agent/tasks/main.yml @@ -24,20 +24,7 @@ chdir: ~/{{ abi.ansible_workdir }} when: abi.boot_method | lower == "iso" and install_config_vars.fips -- name: Check is vmlinuz exists in boot-artifacts - stat: - path: "~/{{ abi.ansible_workdir }}/boot-artifacts/agent.{{ ansible_architecture }}-vmlinuz" - register: vmlinuz - -- name: Copy and rename vmlinuz as kernel.img for PXE - ansible.builtin.copy: - src: "~/{{ abi.ansible_workdir }}/boot-artifacts/agent.{{ ansible_architecture }}-vmlinuz" - dest: /var/www/html/agent.{{ ansible_architecture }}-kernel.img - mode: '644' - remote_src: true - when: vmlinuz.stat.exists - -- name: Copy initrd.img, kernel.img, and rootfs.img for PXE +- name: Copy initrd.img, vmlinuz, and rootfs.img for PXE ansible.builtin.copy: src: "~/{{ abi.ansible_workdir }}/boot-artifacts/" dest: /var/www/html/ @@ -45,6 +32,19 @@ remote_src: true when: abi.boot_method | lower == "pxe" +- name: Check if vmlinuz exists in /var/www/html + ansible.builtin.stat: + path: "/var/www/html/agent.{{ ansible_architecture }}-vmlinuz" + register: vmlinuz_www + +- name: Create kernel.img as copy of vmlinuz for backward compatibility + ansible.builtin.copy: + src: "/var/www/html/agent.{{ ansible_architecture }}-vmlinuz" + dest: /var/www/html/agent.{{ ansible_architecture }}-kernel.img + mode: '644' + remote_src: true + when: abi.boot_method | lower == "pxe" and vmlinuz_www.stat.exists + - name: Copy ISO image to the server ansible.builtin.copy: src: "~/{{ abi.ansible_workdir }}/" diff --git a/roles/create_bastion/tasks/main.yaml b/roles/create_bastion/tasks/main.yaml index 867b0c221..05d195629 100644 --- a/roles/create_bastion/tasks/main.yaml +++ b/roles/create_bastion/tasks/main.yaml @@ -75,7 +75,7 @@ --memory={{ env.bastion.resources.ram }} \ --vcpus={{ env.bastion.resources.vcpu }} \ --location {{ env.file_server.protocol }}://{{ env.file_server.user + ':' + env.file_server.pass + '@' if env.file_server.protocol == 'ftp' else '' }}{{ env.file_server.ip }}{{ ':' + env.file_server.port if env.file_server.port | default('') | length > 0 else '' }}/{{ env.file_server.iso_mount_dir }} \ - --disk pool={{ env.cluster.networking.metadata_name }}-vdisk,size={{ env.bastion.resources.disk_size }},cache=none,io=native \ + --disk pool={{ kvm.disk_pool | default(env.cluster.networking.metadata_name ~ '-vdisk') }},size={{ env.bastion.resources.disk_size }},cache=none,io=native \ --network network={{ env.vnet_name }}{{ (',mac=' + env.bastion.networking.mac) if (env.bastion.networking.mac is defined and env.use_dhcp) }} \ --memballoon none \ --graphics none \ diff --git a/roles/create_compute_nodes/tasks/main.yaml b/roles/create_compute_nodes/tasks/main.yaml index 2e2c9ef05..59fd45113 100644 --- a/roles/create_compute_nodes/tasks/main.yaml +++ b/roles/create_compute_nodes/tasks/main.yaml @@ -1,11 +1,11 @@ --- - name: Load cex_hostdev_map from JSON - set_fact: + ansible.builtin.set_fact: cex_hostdev_map: "{{ lookup('file', '/root/.cex_hostdev_map.json') | from_json }}" when: cex_uuid_map is defined - name: Debug rendered cex_hostdev per compute node - debug: + ansible.builtin.debug: msg: "VM: {{ vm_name }}, Hostdev: {{ cex_hostdev }}" vars: vm_name: "{{ env.cluster.nodes.compute.vm_name[i] }}" @@ -15,9 +15,11 @@ {% else %} "" {% endif %} - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: index_var: i + loop_var: i + when: (env.cluster.nodes.compute.hostname | length) > 0 - name: 'Include matching lpar yml file' tags: create_teuthology_node @@ -32,7 +34,7 @@ {% if cex and cex_device is defined and cex_hostdev_map is defined and vm_name in cex_hostdev_map %} --hostdev={{ cex_hostdev_map[vm_name] }} {% endif %} - shell: | + ansible.builtin.shell: | virsh destroy {{ env.cluster.nodes.compute.vm_name[i] }} || true virsh undefine {{ env.cluster.nodes.compute.vm_name[i] }} --remove-all-storage --nvram || true virt-install \ @@ -63,15 +65,15 @@ --noautoconsole \ {{ cex_hostdev }} timeout: 360 - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} stride=1 + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: yes index_var: i - when: env.cluster.nodes.compute.hostname[0] is defined and env.z.high_availability == False and inventory_hostname == env.z.lpar1.hostname and env.cluster.nodes.compute.vm_name[i] not in hosts_with_host_vars + loop_var: i + when: (env.cluster.nodes.compute.hostname | length) > 0 and not env.z.high_availability and inventory_hostname == env.z.lpar1.hostname and env.cluster.nodes.compute.vm_name[i] not in hosts_with_host_vars - name: Install CoreOS on infra nodes tags: create_compute_nodes - shell: | + ansible.builtin.shell: | virt-install \ --name {{ env.cluster.nodes.infra.vm_name[i] }} \ --osinfo detect=on,name={{ ('rhel8.6') if rhcos_os_variant is not defined else (rhcos_os_variant) }} \ @@ -85,7 +87,7 @@ --extra-args "rd.neednet=1 coreos.inst=yes coreos.inst.install_dev=vda" \ --extra-args "coreos.live.rootfs_url=http://{{ env.bastion.networking.ip }}:8080/bin/{{ rhcos_live_rootfs }}" \ --extra-args "ip={{ env.cluster.nodes.infra.ip[i] }}::{{ env.cluster.networking.gateway }}:{{ env.cluster.networking.subnetmask }}:{{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:{{ env.cluster.networking.interface }}:none:1500" \ - --extra-args "{{ ('ip=[' + env.cluster.nodes.infra.ipv6[i] + ']::[' + env.cluster.networking.ipv6_gateway +']:' + env.cluster.networking.ipv6_prefix | string + '::' + env.cluster.networking.interface + ':none' ) if env.use_ipv6 == True else '' }}" \ + --extra-args "{{ ('ip=[' + env.cluster.nodes.infra.ipv6[i] + ']::[' + env.cluster.networking.ipv6_gateway + ']:' + env.cluster.networking.ipv6_prefix | string + '::' + env.cluster.networking.interface + ':none') if env.use_ipv6 else '' }}" \ --extra-args "nameserver={{ env.cluster.networking.nameserver1 }}" \ --extra-args "{{ ('nameserver=' + env.cluster.networking.nameserver2) if env.cluster.networking.nameserver2 is defined else '' }}" \ --extra-args "coreos.inst.ignition_url=http://{{ env.bastion.networking.ip }}:8080/ignition/worker.ign" \ @@ -94,35 +96,39 @@ --graphics none \ --wait=-1 \ --noautoconsole - with_sequence: start=0 end={{ ( env.cluster.nodes.infra.hostname | length ) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.infra.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i - when: env.cluster.nodes.infra.hostname is defined and env.z.high_availability == False and inventory_hostname == env.z.lpar1.hostname + when: env.cluster.nodes.infra.hostname is defined and not env.z.high_availability and inventory_hostname == env.z.lpar1.hostname -#If cluster is to be highly available, split control and infra nodes into lists corresponding to their future KVM hosts. +# If cluster is to be highly available, split control and infra nodes into lists corresponding to their future KVM hosts. - name: Split information from compute nodes into groups. The number of groups being equal to the number of KVM hosts there are. tags: create_compute_nodes - set_fact: - compute_name: "{{ env.cluster.nodes.compute.vm_name[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] }}" - compute_hostname: "{{ env.cluster.nodes.compute.hostname[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] }}" - compute_ip: "{{ env.cluster.nodes.compute.ip[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] }}" - compute_ipv6: "{{ env.cluster.nodes.compute.ipv6[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] if env.use_ipv6 == True else '' }}" - when: env.z.high_availability == True + ansible.builtin.set_fact: + compute_name: "{{ env.cluster.nodes.compute.vm_name[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] }}" + compute_hostname: "{{ env.cluster.nodes.compute.hostname[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] }}" + compute_ip: "{{ env.cluster.nodes.compute.ip[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] }}" + compute_ipv6: >- + {{ env.cluster.nodes.compute.ipv6[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] + if env.use_ipv6 else '' }} + when: env.z.high_availability - name: Split information for infra nodes into groups. The number of groups being equal to the number of KVM hosts there are. tags: create_compute_nodes - set_fact: - infra_name: "{{ env.cluster.nodes.infra.vm_name[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] }}" - infra_hostname: "{{ env.cluster.nodes.infra.hostname[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] }}" - infra_ip: "{{ env.cluster.nodes.infra.ip[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] }}" - infra_ipv6: "{{ env.cluster.nodes.infra.ipv6[groups['kvm_host'].index(inventory_hostname)::groups['kvm_host'] | length] if env.use_ipv6 == True else '' }}" - when: env.z.high_availability == True and env.cluster.nodes.infra.hostname is defined + ansible.builtin.set_fact: + infra_name: "{{ env.cluster.nodes.infra.vm_name[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] }}" + infra_hostname: "{{ env.cluster.nodes.infra.hostname[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] }}" + infra_ip: "{{ env.cluster.nodes.infra.ip[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] }}" + infra_ipv6: >- + {{ env.cluster.nodes.infra.ipv6[groups['kvm_host'].index(inventory_hostname) :: groups['kvm_host'] | length] + if env.use_ipv6 else '' }} + when: env.z.high_availability and env.cluster.nodes.infra.hostname is defined - name: Create CoreOS compute nodes on KVM hosts, if cluster is to be highly available. tags: create_compute_nodes - shell: | + ansible.builtin.shell: | virt-install \ --name {{ compute_name[i] }} \ --osinfo detect=on,name={{ ('rhel8.6') if rhcos_os_variant is not defined else (rhcos_os_variant) }} \ @@ -151,13 +157,13 @@ --noautoconsole loop: "{{ compute_name | zip(compute_hostname, compute_ip) | list }}" loop_control: - extended: yes + extended: true index_var: i - when: env.z.high_availability == True and compute_hostname[i] is defined and compute_hostname[i] not in hosts_with_host_vars + when: env.z.high_availability and compute_hostname[i] is defined and compute_hostname[i] not in hosts_with_host_vars - name: Create CoreOS infra nodes on KVM hosts, if cluster is to be highly available. tags: create_compute_nodes - shell: | + ansible.builtin.shell: | virt-install \ --name {{ infra_name[i] }} \ --osinfo detect=on,name={{ ('rhel8.6') if rhcos_os_variant is not defined else (rhcos_os_variant) }} \ @@ -171,7 +177,7 @@ --extra-args "rd.neednet=1 coreos.inst=yes coreos.inst.install_dev=vda" \ --extra-args "coreos.live.rootfs_url=http://{{ env.bastion.networking.ip }}:8080/bin/{{ rhcos_live_rootfs }}" \ --extra-args "ip={{ infra_ip[i] }}::{{ env.cluster.networking.gateway }}:{{ env.cluster.networking.subnetmask }}:{{ infra_hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:{{ env.cluster.networking.interface }}:none:1500" \ - --extra-args "{{ ('ip=[' + infra_ipv6[i] + ']::[' + env.cluster.networking.ipv6_gateway +']:' + env.cluster.networking.ipv6_prefix | string + '::' + env.cluster.networking.interface + ':none' ) if env.use_ipv6 == True else '' }}" \ + --extra-args "{{ ('ip=[' + infra_ipv6[i] + ']::[' + env.cluster.networking.ipv6_gateway + ']:' + env.cluster.networking.ipv6_prefix | string + '::' + env.cluster.networking.interface + ':none') if env.use_ipv6 else '' }}" \ --extra-args "nameserver={{ env.cluster.networking.nameserver1 }}" \ --extra-args "{{ ('nameserver=' + env.cluster.networking.nameserver2) if env.cluster.networking.nameserver2 is defined else '' }}" \ --extra-args "coreos.inst.ignition_url=http://{{ env.bastion.networking.ip }}:8080/ignition/worker.ign" \ @@ -182,6 +188,6 @@ --noautoconsole loop: "{{ infra_name | zip(infra_hostname, infra_ip) | list }}" loop_control: - extended: yes + extended: true index_var: i - when: env.cluster.nodes.infra.hostname is defined and infra_hostname[i] is defined and env.z.high_availability == True + when: env.cluster.nodes.infra.hostname is defined and infra_hostname[i] is defined and env.z.high_availability diff --git a/roles/dns/tasks/main.yaml b/roles/dns/tasks/main.yaml index ff0dd1a78..f297150f9 100644 --- a/roles/dns/tasks/main.yaml +++ b/roles/dns/tasks/main.yaml @@ -4,7 +4,7 @@ tags: dns ansible.builtin.systemd: name: named - enabled: yes + enabled: true - name: Start named tags: dns @@ -38,7 +38,7 @@ owner: root group: root mode: "0644" - backup: yes + backup: true - name: Template DNS forwarding file to bastion tags: dns @@ -48,14 +48,15 @@ owner: named group: named mode: "0644" - backup: yes + backup: true - name: Add Bootstrap node to DNS forwarding file on bastion tags: dns ansible.builtin.lineinfile: path: /var/named/{{ env.cluster.networking.metadata_name }}.db insertafter: "entry for bootstrap host" - line: "{{ env.cluster.nodes.bootstrap.hostname }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.bootstrap.ip }}" + line: >- + {{ env.cluster.nodes.bootstrap.hostname }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.bootstrap.ip }} when: env.cluster.nodes.bootstrap is defined - name: Add control nodes to DNS forwarding file on bastion @@ -63,34 +64,36 @@ ansible.builtin.lineinfile: path: /var/named/{{ env.cluster.networking.metadata_name }}.db insertafter: "entries for the control nodes" - line: "{{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.control.ip[i] }}" + line: >- + {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.control.ip[i] }} with_sequence: start=0 end={{ (env.cluster.nodes.control.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i -- block: - - name: Add compute nodes to DNS forwarding file on bastion - tags: dns - ansible.builtin.lineinfile: - path: /var/named/{{ env.cluster.networking.metadata_name }}.db - insertafter: "entries for the compute nodes" - line: "{{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.compute.ip[i] }}" - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} stride=1 - loop_control: - extended: yes - index_var: i - when: env.cluster.nodes.compute.hostname is defined and env.cluster.nodes.compute.hostname[0] is defined and (env.cluster.nodes.compute.hostname | length) > 0 +- name: Add compute nodes to DNS forwarding file on bastion + tags: dns + ansible.builtin.lineinfile: + path: /var/named/{{ env.cluster.networking.metadata_name }}.db + insertafter: "entries for the compute nodes" + line: >- + {{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.compute.ip[i] }} + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" + loop_control: + index_var: i + loop_var: i + when: env.cluster.nodes.compute.hostname is defined and (env.cluster.nodes.compute.hostname | length) > 0 - name: Add infrastructure nodes to DNS forwarding file on bastion if requested tags: dns ansible.builtin.lineinfile: path: /var/named/{{ env.cluster.networking.metadata_name }}.db insertafter: "entries for extra RHEL VMs" - line: "{{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.infra.ip[i] }}" + line: >- + {{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. IN A {{ env.cluster.nodes.infra.ip[i] }} with_sequence: start=0 end={{ (env.cluster.nodes.infra.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i when: env.cluster.nodes.infra.hostname is defined @@ -102,17 +105,18 @@ owner: named group: named mode: "0644" - backup: yes + backup: true - name: Add control nodes to DNS reverse lookup file on bastion tags: dns ansible.builtin.lineinfile: path: /var/named/{{ env.cluster.networking.metadata_name }}.rev insertafter: "PTR Record IP address to Hostname" - line: "{{ env.cluster.nodes.control.ip[i].split('.').3 }} IN PTR {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}." + line: >- + {{ env.cluster.nodes.control.ip[i].split('.').3 }} IN PTR {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. with_sequence: start=0 end={{ (env.cluster.nodes.control.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i - name: Add compute nodes to DNS reverse lookup file on bastion @@ -120,22 +124,24 @@ ansible.builtin.lineinfile: path: /var/named/{{ env.cluster.networking.metadata_name }}.rev insertafter: "PTR Record IP address to Hostname" - line: "{{ env.cluster.nodes.compute.ip[i].split('.').3 }} IN PTR {{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}." - with_sequence: start=0 end={{ (env.cluster.nodes.compute.hostname | length) - 1 }} stride=1 + line: >- + {{ env.cluster.nodes.compute.ip[i].split('.').3 }} IN PTR {{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: yes index_var: i - when: env.cluster.nodes.compute.hostname is defined and env.cluster.nodes.compute.hostname[0] is defined and env.cluster.nodes.compute.hostname[0] != None + loop_var: i + when: env.cluster.nodes.compute.hostname is defined and (env.cluster.nodes.compute.hostname | length) > 0 - name: Add infrastructure nodes to DNS reverse lookup file on bastion tags: dns ansible.builtin.lineinfile: path: /var/named/{{ env.cluster.networking.metadata_name }}.rev insertafter: "PTR Record IP address to Hostname" - line: "{{ env.cluster.nodes.infra.ip[i].split('.').3 }} IN PTR {{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}." + line: >- + {{ env.cluster.nodes.infra.ip[i].split('.').3 }} IN PTR {{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}. with_sequence: start=0 end={{ (env.cluster.nodes.infra.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i when: env.cluster.nodes.infra.hostname is defined diff --git a/roles/download_kubeconfig/defaults/main.yaml b/roles/download_kubeconfig/defaults/main.yaml index 94bf005a9..258242a6e 100644 --- a/roles/download_kubeconfig/defaults/main.yaml +++ b/roles/download_kubeconfig/defaults/main.yaml @@ -7,5 +7,3 @@ kubeconfig_source_dir: ~/ocpinst/auth kubeconfig_files: - kubeconfig - kubeadmin-password - -# Made with Bob diff --git a/roles/haproxy/tasks/main.yaml b/roles/haproxy/tasks/main.yaml index f5aea215e..2a42086e5 100644 --- a/roles/haproxy/tasks/main.yaml +++ b/roles/haproxy/tasks/main.yaml @@ -2,121 +2,123 @@ - name: Change permissive domain for haproxy tags: selinux,haproxy - selinux_permissive: + community.general.selinux_permissive: name: haproxy_t permissive: true - name: Use template to create haproxy config file tags: haproxy - template: + ansible.builtin.template: src: haproxy.cfg.j2 dest: /etc/haproxy/haproxy.cfg - backup: yes - force: yes + backup: true + force: true + mode: '0644' - name: Add control node information to 6443 section in haproxy config tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.control.hostname[i] }} {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:6443 check inter 1s" path: /etc/haproxy/haproxy.cfg insertafter: "6443 section" - with_sequence: start=0 end={{(env.cluster.nodes.control.hostname | length) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.control.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i - name: Add control node information to 22623 section in haproxy config tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.control.hostname[i] }} {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:22623 check inter 1s" path: /etc/haproxy/haproxy.cfg insertafter: "22623 section" - with_sequence: start=0 end={{(env.cluster.nodes.control.hostname | length) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.control.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i - name: Add control node information to 443 section in haproxy config, when no compute nodes are defined tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.control.hostname[i] }} {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:443 check inter 1s" path: /etc/haproxy/haproxy.cfg insertafter: "443 section" - with_sequence: start=0 end={{(env.cluster.nodes.control.hostname | length) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.control.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i when: env.cluster.nodes.compute.hostname[0] is not defined - name: Add compute node information to 443 section in haproxy config tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.compute.hostname[i] }} {{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:443 check inter 1s" path: /etc/haproxy/haproxy.cfg insertafter: "443 section" - with_sequence: start=0 end={{(env.cluster.nodes.compute.hostname | length) - 1}} stride=1 + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: yes index_var: i - when: env.cluster.nodes.compute.hostname[0] is defined + loop_var: i + when: (env.cluster.nodes.compute.hostname | length) > 0 - name: Add infrastructure node information to 443 section in haproxy config tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.infra.hostname[i] }} {{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:443 check inter 1s" path: /etc/haproxy/haproxy.cfg insertafter: "443 section" - with_sequence: start=0 end={{(env.cluster.nodes.infra.hostname | length) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.infra.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i when: env.cluster.nodes.infra.hostname is defined - name: Add control node information to 80 section in haproxy config, when no compute nodes are defined tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.control.hostname[i] }} {{ env.cluster.nodes.control.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:80 check inter 1s" path: /etc/haproxy/haproxy.cfg - with_sequence: start=0 end={{(env.cluster.nodes.control.hostname | length) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.control.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i when: env.cluster.nodes.compute.hostname[0] is not defined - name: Add compute node information to 80 section in haproxy config tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.compute.hostname[i] }} {{ env.cluster.nodes.compute.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:80 check inter 1s" path: /etc/haproxy/haproxy.cfg - with_sequence: start=0 end={{(env.cluster.nodes.compute.hostname | length) - 1}} stride=1 + loop: "{{ range(0, env.cluster.nodes.compute.hostname | length) | list }}" loop_control: - extended: yes index_var: i - when: env.cluster.nodes.compute.hostname[0] is defined + loop_var: i + when: (env.cluster.nodes.compute.hostname | length) > 0 - name: Add infrastructure node information to 80 section in haproxy config tags: haproxy - lineinfile: + ansible.builtin.lineinfile: line: " server {{ env.cluster.nodes.infra.hostname[i] }} {{ env.cluster.nodes.infra.hostname[i] }}.{{ env.cluster.networking.metadata_name }}.{{ env.cluster.networking.base_domain }}:80 check inter 1s" path: /etc/haproxy/haproxy.cfg - with_sequence: start=0 end={{(env.cluster.nodes.infra.hostname | length) - 1}} stride=1 + with_sequence: start=0 end={{ (env.cluster.nodes.infra.hostname | length) - 1 }} stride=1 loop_control: - extended: yes + extended: true index_var: i when: env.cluster.nodes.infra.hostname is defined - name: Set haproxy boolean to enable connections tags: haproxy - command: setsebool -P haproxy_connect_any 1 + ansible.builtin.command: setsebool -P haproxy_connect_any 1 + changed_when: true - name: Enable haproxy tags: haproxy ansible.builtin.systemd: name: haproxy - enabled: yes + enabled: true - name: Restart haproxy tags: haproxy - systemd: + ansible.builtin.systemd: state: restarted name: haproxy diff --git a/roles/prepare_configs/tasks/main.yaml b/roles/prepare_configs/tasks/main.yaml index cd4eb27c4..af5d9d33e 100644 --- a/roles/prepare_configs/tasks/main.yaml +++ b/roles/prepare_configs/tasks/main.yaml @@ -1,13 +1,14 @@ --- - name: Delete OCP Work Directory For Idempotency. - file: + ansible.builtin.file: path: ~/ansible_workdir state: absent - name: Create Work Directory - file: + ansible.builtin.file: path: ~/ansible_workdir state: directory + mode: '0755' - name: Prepare Agent Config ansible.builtin.template: @@ -16,23 +17,25 @@ owner: root group: root mode: "0755" - backup: yes + backup: true loop: - ~/ansible_workdir/agent-config.yaml - ~/ansible_workdir/agent-config-backup.yaml -- name: Check if SSH key exists - stat: +- name: Check if bastion SSH key exists + ansible.builtin.stat: path: "~/.ssh/{{ env.ansible_key_name }}.pub" register: ssh_key -- name: Generate SSH key - command: ssh-keygen -t rsa -b 4096 -N "" -f "~/.ssh/{{ env.ansible_key_name }}" - when: ssh_key.stat.exists == false +- name: Generate bastion SSH key if not exists + ansible.builtin.command: ssh-keygen -t rsa -b 4096 -N "" -f "~/.ssh/{{ env.ansible_key_name }}" + when: not ssh_key.stat.exists + changed_when: true -- name: Read SSH Key - command: cat ~/.ssh/{{ env.ansible_key_name }}.pub +- name: Read bastion SSH Key + ansible.builtin.command: cat ~/.ssh/{{ env.ansible_key_name }}.pub register: ssh_key + changed_when: false - name: Prepare Install Config vars: @@ -43,7 +46,7 @@ owner: root group: root mode: "0755" - backup: yes + backup: true loop: - ~/ansible_workdir/install-config.yaml - ~/ansible_workdir/install-config-backup.yaml diff --git a/roles/prepare_configs/templates/agent-config.yaml.j2 b/roles/prepare_configs/templates/agent-config.yaml.j2 index 574561f08..9590aa411 100644 --- a/roles/prepare_configs/templates/agent-config.yaml.j2 +++ b/roles/prepare_configs/templates/agent-config.yaml.j2 @@ -9,6 +9,14 @@ hosts: {% for item in range( env.cluster.nodes.control.ip | length ) %} - hostname: "{{ env.cluster.nodes.control.hostname[item] }}" role: master +{% if installation_type | lower == 'lpar' %} +{%- set control_node_hostname = env.cluster.nodes.control.vm_name[item] -%} +{%- set control_node_vars = lookup('file', inventory_dir + '/host_vars/' + control_node_hostname + '.yaml') | from_yaml -%} +{%- if control_node_vars.lpar is defined and control_node_vars.lpar.storage_group_1 is defined and control_node_vars.lpar.storage_group_1.type | lower == 'fcp' %} + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.{{ control_node_vars.lpar.storage_group_1.dev_num }}-fc-{{ control_node_vars.lpar.storage_group_1.storage_wwpn[0] }}-lun-{{ control_node_vars.lpar.storage_group_1.lun_name }} +{% endif %} +{% endif %} interfaces: - name: eth0 macAddress: "{{ env.cluster.nodes.control.mac[item] }}" @@ -33,12 +41,20 @@ hosts: - destination: 0.0.0.0/0 next-hop-address: "{{ env.bastion.networking.gateway }}" next-hop-interface: eth0 - table-id: 254 + table-id: 254 {% endfor %} {% if env.cluster.nodes.compute.ip is defined %} {% for item in range( env.cluster.nodes.compute.ip | length ) %} - hostname: "{{ env.cluster.nodes.compute.hostname[item] }}" role: worker +{% if installation_type | lower == 'lpar' %} +{% set compute_node_hostname = env.cluster.nodes.compute.vm_name[item] %} +{% set compute_node_vars = lookup('file', inventory_dir + '/host_vars/' + compute_node_hostname + '.yaml') | from_yaml %} +{% if compute_node_vars.lpar is defined and compute_node_vars.lpar.storage_group_1 is defined and compute_node_vars.lpar.storage_group_1.type | lower == 'fcp' %} + rootDeviceHints: + deviceName: /dev/disk/by-path/ccw-0.0.{{ compute_node_vars.lpar.storage_group_1.dev_num }}-fc-{{ compute_node_vars.lpar.storage_group_1.storage_wwpn[0] }}-lun-{{ compute_node_vars.lpar.storage_group_1.lun_name }} +{% endif %} +{% endif %} interfaces: - name: eth0 macAddress: "{{ env.cluster.nodes.compute.mac[item] }}" @@ -63,7 +79,7 @@ hosts: - destination: 0.0.0.0/0 next-hop-address: "{{ env.bastion.networking.gateway }}" next-hop-interface: eth0 - table-id: 254 + table-id: 254 {% endfor %} {% endif %} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/roles/ssh_agent/tasks/main.yaml b/roles/ssh_agent/tasks/main.yaml index 49981ed29..b633bd82e 100644 --- a/roles/ssh_agent/tasks/main.yaml +++ b/roles/ssh_agent/tasks/main.yaml @@ -4,15 +4,18 @@ path: ~/.bash_profile state: touch mode: '0644' + become: false - name: Add ansible SSH key to ssh-agent tags: ssh_agent, ssh - lineinfile: + ansible.builtin.lineinfile: line: "eval $(ssh-agent) && ssh-add ~/.ssh/{{ env.ansible_key_name }}" path: ~/.bash_profile + become: false register: ssh_agent_setup - name: Print results from setting up SSH agent tags: ssh_agent, ssh - debug: + ansible.builtin.debug: var: ssh_agent_setup + become: false