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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ hotstack_overrides.yaml
images/*.qcow2
images/.*-build/
images/*.d/
*.gz.b64
*.tar.gz
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ repos:
language: system
files: ^scenarios/sno-nxsw/poap\.py$
pass_filenames: false
- id: networking-lab-poap-md5sums
name: Format networking-lab POAP scripts with md5sum management
entry: scenarios/networking-lab/manage-poap-md5sums.sh
language: system
files: ^scenarios/networking-lab/.*-poap\.py$
pass_filenames: false

- repo: https://github.com/ansible/ansible-lint
rev: v6.22.2
Expand Down
37 changes: 37 additions & 0 deletions 03-redfish_vbmc_podman.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Install RedFish Virtual BMC (Podman)
hosts: localhost
gather_facts: true
strategy: linear
pre_tasks:
- name: Load stack output vars from file
ansible.builtin.include_vars:
file: "{{ hotstack_work_dir | default(playbook_dir) }}/{{ stack_name }}-outputs.yaml"
name: stack_outputs

- name: Add controller-0 to the Ansible inventory
ansible.builtin.add_host: "{{ stack_outputs.controller_ansible_host }}"

roles:
- role: redfish_vbmc_podman
when:
- stack_outputs.sushy_emulator_uuids | default({}) | length > 0
delegate_to: controller-0
vars:
redfish_vbmc_podman_instances_uuids: "{{ stack_outputs.sushy_emulator_uuids.values() }}"
redfish_vbmc_podman_os_cloud: default
34 changes: 34 additions & 0 deletions 04-install_devstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Install Devstack
hosts: localhost
gather_facts: true
strategy: linear
pre_tasks:
- name: Load stack output vars from file
ansible.builtin.include_vars:
file: "{{ hotstack_work_dir | default(playbook_dir) }}/{{ stack_name }}-outputs.yaml"
name: stack_outputs

- name: Add controller-0 to the Ansible inventory
ansible.builtin.add_host: "{{ stack_outputs.controller_ansible_host }}"

roles:
- role: devstack_installer
vars:
devstack_ansible_host: "{{ stack_outputs.devstack_ansible_host }}"
devstack_netplan_config: "{{ stack_outputs.devstack_netplan_config }}"
39 changes: 39 additions & 0 deletions 05-hotloop-stages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Run HotLoop Stages
hosts: localhost
gather_facts: true
strategy: linear
pre_tasks:
- name: Load stack output vars from file
ansible.builtin.include_vars:
file: "{{ hotstack_work_dir | default(playbook_dir) }}/{{ stack_name }}-outputs.yaml"
name: stack_outputs

- name: Add controller-0 to the Ansible inventory
ansible.builtin.add_host: "{{ stack_outputs.controller_ansible_host }}"

- name: "Load automation vars - store in variable: automation"
ansible.builtin.include_vars:
file: "{{ automation_vars_file }}"
name: automation

roles:
- role: hotloop
delegate_to: controller-0
vars:
work_dir: "{{ scenario_dir }}/{{ scenario }}"
30 changes: 30 additions & 0 deletions bootstrap_devstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Bootstrap virtual infrastructure on Openstack cloud
ansible.builtin.import_playbook: 01-infra.yml

- name: Bootstrap controller node
ansible.builtin.import_playbook: 02-bootstrap_controller.yml

- name: Deploy RedFish Virtual BMC (Podman)
ansible.builtin.import_playbook: 03-redfish_vbmc_podman.yml

- name: Install DevStack
ansible.builtin.import_playbook: 04-install_devstack.yml

- name: Run HotLoop Stages
ansible.builtin.import_playbook: 05-hotloop-stages.yml
1 change: 1 addition & 0 deletions roles/controller/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ nfs_exports:
- path: "{{ nova_console_recorder_nfs_path }}"
mode: '0777' # World writable for container access

controller_install_openstack_client: false
hotstack_cloud_secrets:
auth_url: http://cloud.example.com:5000
application_credential_id: app_credential_id
Expand Down
36 changes: 36 additions & 0 deletions roles/controller/tasks/install_openstack_client.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Create virtualenv for OpenStack client
become: true
ansible.builtin.pip:
name:
- python-openstackclient
- python-ironicclient
- python-heatclient
virtualenv: /opt/openstackclient-venv
virtualenv_command: python3 -m venv

- name: Create wrapper script in /usr/local/bin
become: true
ansible.builtin.copy:
content: |
#!/bin/bash
exec /opt/openstackclient-venv/bin/openstack "$@"
dest: /usr/local/bin/openstack
mode: '0755'
owner: root
group: root
4 changes: 4 additions & 0 deletions roles/controller/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,7 @@
[data_dir, 'ironic_nodes.yaml']
| ansible.builtin.path_join
}}

- name: Install OpenStack client
when: controller_install_openstack_client | bool
ansible.builtin.include_tasks: install_openstack_client.yml
149 changes: 149 additions & 0 deletions roles/devstack_installer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Devstack Installer Role

This role installs and configures DevStack. The actual devstack configuration is provided by a `local.conf.j2` template that is deployed to the devstack node via the Heat template's cloud-init, then fetched and rendered by Ansible on the controller.

## Requirements

- **Ubuntu 24.04 (Noble)** target system (required for DevStack compatibility)
- User `stack` with sudo privileges and home directory at `/opt/stack`
- SSH access configured (the heat template adds both controller and dataplane SSH keys)
- Accessible via SSH (potentially through a jump host)
- Network interface configured (typically via heat template cloud-init)
- `local.conf.j2` template deployed to `/etc/hotstack/local.conf.j2` via Heat template cloud-init

## SSH Key Configuration

The heat template creates the stack user with both `controller_ssh_pub_key` and `dataplane_ssh_pub_key`, allowing access from Ansible (using controller key) and other systems (using dataplane key).

## Execution Flow

The role performs the following steps:

1. **System Update**: Updates all packages to latest versions (if `devstack_update_packages` is true)
2. **Reboot if needed**: Checks for `/var/run/reboot-required` and reboots if kernel/core packages were updated
3. **Wait for system**: Waits for system to come back online (up to 5 minutes)
4. **Install dependencies**: Installs git, python3, and python3-pip
5. **Verify network**: Checks that the trunk interface is UP
6. **Ensure permissions**: Sets correct ownership on `/opt/stack` directory
7. **Prepare Ironic**: Creates empty `/opt/stack/data/ironic/hardware_info` (nodes enrolled separately after installation)
8. **Clone devstack**: Clones the devstack repository
9. **Fetch template**: Retrieves `/etc/hotstack/local.conf.j2` from devstack node to Ansible controller
10. **Render config**: Processes the Jinja2 template on the Ansible controller with any runtime variables
11. **Deploy config**: Copies the rendered `local.conf` to `/opt/stack/devstack/local.conf`
12. **Run stack.sh**: Executes devstack installation as the `stack` user (output saved to `/opt/stack/stack.sh.log`)

## Role Variables

Available variables are listed below, along with default values (see `defaults/main.yml`):

```yaml
# DevStack repository configuration
devstack_repo_url: https://opendev.org/openstack/devstack
devstack_branch: master

# Network interface for physical bridge (should match heat template netplan config)
# The heat template uses MAC matching to create a predictable name
devstack_public_interface: trunk0

# System updates (set to false to skip for faster iterations during development)
devstack_update_packages: true
```

**Note**: DevStack is always installed to `/opt/stack/devstack` as per DevStack convention.

## Physical Switch Configuration

Physical network switches for networking-generic-switch are configured via the `local.conf` template using DevStack's `[[post-config|...]]` mechanism. Scenarios should include switch configurations in their `local.conf.j2` template.

Example:

```ini
[[post-config|/etc/neutron/plugins/ml2/ml2_conf_genericswitch.ini]]
[genericswitch:leaf01]
device_type = netmiko_cisco_nxos
ip = 192.168.32.13
username = admin
password = password
ngs_mac_address = 22:57:f8:dd:03:01
ngs_physical_networks = public
```

## Enrolling Ironic Nodes

This role creates an empty `hardware_info` file so DevStack completes without auto-enrolling nodes. After DevStack installation, enroll baremetal nodes using the Heat stack's `ironic_nodes` output:

```bash
# Get the nodes YAML from Heat stack output
openstack stack output show <stack_name> ironic_nodes -f yaml -c output_value > nodes.yaml

# Enroll nodes in Ironic
openstack baremetal create nodes.yaml
```

The Heat stack output provides the node definitions in the exact format expected by `openstack baremetal create`, including all driver info, properties, and port configurations.

## Example Playbook

```yaml
- name: Install Devstack
hosts: devstack
gather_facts: true
roles:
- role: devstack_installer
```

## Scenario Structure

Each scenario should provide its own `local.conf.j2` template alongside the Heat template:

```
scenarios/
networking-lab/
devstack-nxsw-vxlan/
heat_template.yaml # Includes local.conf.j2 via get_file
local.conf.j2 # Devstack configuration template
bootstrap_vars.yml
```

### Heat Template Integration

The Heat template deploys the `local.conf.j2` template via cloud-init:

```yaml
devstack-write-files:
type: OS::Heat::CloudConfig
properties:
cloud_config:
write_files:
- path: /etc/hotstack/local.conf.j2
content:
get_file: local.conf.j2
owner: root:root
permissions: '0644'
```

### Template Variables

The `local.conf.j2` template supports Jinja2 templating for dynamic configuration. Variables can be added as needed to customize DevStack behavior at runtime (e.g., testing different branches, Gerrit patches, or configuration values).

## Features

- **Template deployment via Heat**: `local.conf.j2` is co-located with the Heat template and deployed via cloud-init
- **Controller-side templating**: Template is fetched and rendered on the Ansible controller for runtime flexibility
- **No path resolution issues**: Works with scenarios in any location (no absolute vs relative path concerns)
- **Dynamic configuration**: Supports Jinja2 variables for testing branches, patches, and configurations
- **Network configuration**: Handled by heat template (cloud-init netplan)
- **Package updates**: Updates all packages before installation (dist-upgrade)
- **Automatic reboot**: Reboots if kernel or core packages are updated
- **Hardware deployment support**: Creates empty `hardware_info` for `IRONIC_IS_HARDWARE=True` (nodes enrolled separately using Heat stack output)
- **Idempotent**: Can be re-run safely (checks for .stack.sh.complete marker)
- **Detailed logging**: stack.sh output saved to `/opt/stack/stack.sh.log` for troubleshooting
- **SSH access**: Via jump host through controller using ProxyJump

## License

Apache 2.0

## Author Information

This role was created as part of the HotStack project.
Loading