--- /dev/null
+---
+# "any_errors_fatal: true" makes sure the run stops if any problems happen.
+# This gives you the ability to flash backed up firmwares or diagnose
+# problems without the playbook cleaning up after itself or causing more damage.
+
+- hosts: all
+ any_errors_fatal: true
+ strategy: free
+ roles:
+ - secrets
+ - firmware
+ become: true
--- /dev/null
+---
+# Defaults should be overridden in the secrets repo in each machine type's
+# group_vars file
+latest_bios_version: null
+latest_bmc_version: null
+
+flashrom_location: "http://download.flashrom.org/releases/flashrom-0.9.9.tar.bz2"
+
+firmware_update_path: "/home/{{ ansible_user }}/firmware-update"
--- /dev/null
+---
+- include: mira/bios.yml
+ tags:
+ - bios
+ when: '"mira" in ansible_hostname'
+
+- include: mira/bmc.yml
+ tags:
+ - bmc
+ when: '"mira" in ansible_hostname'
+
+# This won't get run if a previous playbook fails. So if a backup of a BIOS is
+# needed to restore, it'll still be there
+- name: Clean up firmware update directory
+ file:
+ path: "{{ firmware_update_path }}"
+ state: absent
+ tags:
+ - always
--- /dev/null
+---
+# This file is only called when current_bios_version
+# and latest_bios_version do not match
+
+- name: Install packages for CentOS/RHEL
+ yum:
+ name: "{{ item }}"
+ state: latest
+ with_items:
+ - pciutils-devel
+ - zlib-devel
+ - libftdi-devel
+ - libusb-devel
+ - make
+ - gcc
+ when: ansible_pkg_mgr == "yum"
+
+- name: Install packages for Ubuntu
+ apt:
+ name: "{{ item }}"
+ state: latest
+ with_items:
+ - flashrom
+ when: ansible_pkg_mgr == "apt"
+
+# Flashrom has to be built on CentOS so we add an extra dir for it
+# This is equivalent to 'mkdir -p'
+- name: Create BIOS update working directory structure
+ file:
+ path: "{{ firmware_update_path }}/bios-update/flashrom"
+ state: directory
+
+# This file must be the already-extracted binary blob from the Supermicro
+# firmware archive. Naming scheme is PPPPPY.MDD
+# PPPPP = Project name; Y = Year; M = Month; DD = Day
+# We rename it to 'new-bios' here so the playbook can consume a universal name
+- name: Download BIOS binary
+ get_url:
+ url: "{{ bios_location }}"
+ dest: "{{ firmware_update_path }}/bios-update/new-bios"
+
+# There is flashrom RPM in any trusted repositories so we have to compile it
+- name: Download flashrom archive (CentOS)
+ get_url:
+ url: "{{ flashrom_location }}"
+ dest: "{{ firmware_update_path }}/bios-update/flashrom.tar.bz2"
+ validate_certs: no
+ when: ansible_pkg_mgr == "yum"
+
+# The flashrom tarballs extract to a directory with its version number by default
+# '--strip-components 1' gets rid of that dir so the playbook can run with any
+# flashrom version
+- name: Extract flashrom (CentOS)
+ shell: "tar -xjf {{ firmware_update_path }}/bios-update/flashrom.tar.bz2 --directory {{ firmware_update_path }}/bios-update/flashrom --strip-components 1"
+ when: ansible_pkg_mgr == "yum"
+
+- name: Compile flashrom (CentOS)
+ shell: "cd {{ firmware_update_path }}/bios-update/flashrom && make"
+ when: ansible_pkg_mgr == "yum"
+
+- name: Back up existing BIOS (CentOS)
+ shell: "cd {{ firmware_update_path }}/bios-update && flashrom/flashrom --programmer internal --read BIOS.bak"
+ when: ansible_pkg_mgr == "yum"
+
+- name: Flash new BIOS (CentOS)
+ shell: "cd {{ firmware_update_path }}/bios-update && flashrom/flashrom --programmer internal --write new-bios"
+ when: ansible_pkg_mgr == "yum"
+
+- name: Back up existing BIOS (Ubuntu)
+ shell: "flashrom -p internal:Supermicro:X8SIL --read {{ firmware_update_path }}/bios-update/BIOS.bak"
+ when: ansible_pkg_mgr == "apt"
+
+- name: Flash new BIOS (Ubuntu)
+ shell: "flashrom -p internal:Supermicro:X8SIL --write {{ firmware_update_path }}/bios-update/new-bios"
+ when: ansible_pkg_mgr == "apt"
--- /dev/null
+---
+- name: Determine current BIOS firmware version
+ shell: dmidecode --type bios | grep Version | awk '{ print $2 }'
+ register: current_bios_version
+ changed_when: False
+
+- name: Determine if BIOS update is needed
+ set_fact:
+ need_bios_update: true
+ when: current_bios_version.stdout != latest_bios_version
+
+- name: Include BIOS update logic
+ include: roles/firmware/tasks/mira/bios-update.yml
+ when: need_bios_update is defined and need_bios_update == true
--- /dev/null
+---
+# This file is only called when current_bmc_version
+# and latest_bmc_version do not match
+
+- name: Install unzip
+ package:
+ name: unzip
+ state: latest
+
+- name: Create BMC update working directory structure
+ file:
+ path: "{{ firmware_update_path }}/bmc-update"
+ state: directory
+
+# Download the archive and rename to something the playbook can consume
+- name: Download BMC archive
+ get_url:
+ url: "{{ bmc_location }}"
+ dest: "{{ firmware_update_path }}/bmc-update/bmc.zip"
+ force: yes
+
+- name: Extract IPMI archive
+ shell: "cd {{ firmware_update_path }}/bmc-update && unzip bmc.zip"
+
+- name: Flash new BMC (Takes around 5 minutes)
+ shell: "cd {{ firmware_update_path }}/bmc-update/Linux* && chmod +x lUpdate && ./lUpdate -f ../*.bin -i kcs -r y"
+ register: bmc_flash_output
+
+# Print output of flash script
+- debug: var=bmc_flash_output.stdout_lines|last
--- /dev/null
+---
+- name: Install ipmitool
+ package:
+ name: ipmitool
+ state: latest
+
+- name: Enable IPMI kernel modules
+ modprobe:
+ name: "{{ item }}"
+ state: present
+ with_items:
+ - ipmi_devintf
+ - ipmi_si
+
+- name: Determine current BMC firmware version
+ shell: ipmitool mc info | grep "Firmware Revision" | awk '{ print $4 }'
+ register: current_bmc_version
+ changed_when: False
+
+- name: Determine if BMC update is needed
+ set_fact:
+ need_bmc_update: true
+ when: current_bmc_version.stdout != latest_bmc_version
+
+- name: Include BMC update logic
+ include: roles/firmware/tasks/mira/bmc-update.yml
+ when: need_bmc_update is defined and need_bmc_update == true