How we moved a Catalyst 9K OT fleet from 17.12.x to 17.15.x with an Ansible install-mode playbook -- zero outages, zero late-night cutovers.
The client had 13 Catalyst 9K switches running an older IOS-XE 17.12 train that the engineering team had been wary of touching for over a year. Past upgrades had been bundle-mode TFTP affairs done at 2 a.m. with verbal rollback plans. They needed a repeatable process before scaling further.
install-add.yml / install-activate.yml / install-commit.yml / install-remove.yml) covering the full IOS-XE install-mode lifecycle.install_commit.py using paramiko invoke_shell(), because install commit requires enable-mode plus an interactive session under the active AAA exec authorization chain.install-remove.yml pass to clean inactive bundles -- intentionally not folded into the upgrade run.install activate alone -- not install activate file ... -- once the image is added.write memory before install add, not after.show install summary -- the difference between "activated" and "committed".13 switches upgraded across two maintenance windows, no outages, no rollbacks invoked. The playbook now lives in the client's automation repo and has been re-used for two subsequent point-release upgrades by their own staff.