diff --git a/inventory/service/group_vars/puppet.yaml b/inventory/service/group_vars/puppet.yaml
index 68409237f7..37eab8292a 100644
--- a/inventory/service/group_vars/puppet.yaml
+++ b/inventory/service/group_vars/puppet.yaml
@@ -11,6 +11,3 @@ mgmt_hieradata: /etc/ansible/hosts
 mgmt_puppet_module_dir: /etc/puppet/modules
 puppet_hieradata_link_dest: /opt/system-config/hieradata
 puppet_nolog_sync: '{{ silence_synchronize }}'
-
-ansible_roles:
-  - puppet
diff --git a/playbooks/remote_puppet_afs.yaml b/playbooks/remote_puppet_afs.yaml
index eed1ea92d3..6f98aa5014 100644
--- a/playbooks/remote_puppet_afs.yaml
+++ b/playbooks/remote_puppet_afs.yaml
@@ -1,8 +1,14 @@
+- hosts: 'localhost:!disabled'
+  name: Install puppet role/modules
+  strategy: linear
+  roles:
+    - puppet-setup-ansible
+
 - hosts: "afs:afsdb:!disabled"
   name: "AFS: run puppet on the AFS servers"
   strategy: free
   roles:
-    - run-puppet
+    - puppet-run
 
 - hosts: "mirror-update:!disabled"
   name: "Create key for remote vos release"
diff --git a/playbooks/remote_puppet_else.yaml b/playbooks/remote_puppet_else.yaml
index 36b2bdc1c0..aaff2c7b20 100644
--- a/playbooks/remote_puppet_else.yaml
+++ b/playbooks/remote_puppet_else.yaml
@@ -1,5 +1,11 @@
+- hosts: 'localhost:!disabled'
+  name: Install puppet role/modules
+  strategy: linear
+  roles:
+    - puppet-setup-ansible
+
 - hosts: 'puppet:!review:!afs:!afsdb:!puppetmaster*:!nb*:!codesearch:!eavesdrop:!disabled'
   name: "Puppet-else: run puppet on all other servers"
   strategy: free
   roles:
-    - run-puppet
+    - puppet-run
diff --git a/playbooks/roles/install-ansible-roles/tasks/main.yaml b/playbooks/roles/install-ansible-roles/tasks/main.yaml
index 9a2d5c2e8f..1662a5e394 100644
--- a/playbooks/roles/install-ansible-roles/tasks/main.yaml
+++ b/playbooks/roles/install-ansible-roles/tasks/main.yaml
@@ -3,8 +3,6 @@
     repo: '{{ ansible_role_src_root }}/src/opendev.org/opendev/ansible-role-{{ ansible_role }}'
     dest: '/etc/ansible/roles/{{ ansible_role }}'
     force: yes
-  delegate_to: localhost
-  run_once: true
   loop: '{{ ansible_roles }}'
   loop_control:
     loop_var: ansible_role
diff --git a/playbooks/roles/puppet-run/README.rst b/playbooks/roles/puppet-run/README.rst
new file mode 100644
index 0000000000..54753d634e
--- /dev/null
+++ b/playbooks/roles/puppet-run/README.rst
@@ -0,0 +1,13 @@
+Run puppet on remote servers
+
+Omnibus role that takes care of installing puppet and then running
+puppet. Uses include_role so that the installation of the puppet role
+can run as the first task, then the puppet role can be used in a
+following task.
+
+This role should run after ``puppet-setup-ansible``
+
+.. zuul:rolevar:: manifest
+   :default: manifests/site.pp
+
+   Puppet manifest file to run.
diff --git a/playbooks/roles/run-puppet/tasks/main.yaml b/playbooks/roles/puppet-run/tasks/main.yaml
similarity index 54%
rename from playbooks/roles/run-puppet/tasks/main.yaml
rename to playbooks/roles/puppet-run/tasks/main.yaml
index 9573186f6a..9b4b4285ba 100644
--- a/playbooks/roles/run-puppet/tasks/main.yaml
+++ b/playbooks/roles/puppet-run/tasks/main.yaml
@@ -1,19 +1,9 @@
 # Use include_role instead of roles: so that we can late-bind the roles list
 - include_role:
     name: iptables
-- include_role:
-    name: install-ansible-roles
 - include_role:
     name: puppet-install
 - include_role:
     name: disable-puppet-agent
-
-- name: Run puppet module install
-  delegate_to: localhost
-  run_once: true
-  command:
-    cmd: bash install_modules.sh
-    chdir: /etc/puppet
-
 - include_role:
     name: puppet
diff --git a/playbooks/roles/puppet-setup-ansible/README.rst b/playbooks/roles/puppet-setup-ansible/README.rst
new file mode 100644
index 0000000000..eb94dff6a5
--- /dev/null
+++ b/playbooks/roles/puppet-setup-ansible/README.rst
@@ -0,0 +1,5 @@
+Setup Ansible on this host to run puppet on remote hosts.
+
+Import the ansible-roles-puppet role for running puppet on remote
+hosts and bring in the repository of required puppet modules.
+
diff --git a/playbooks/roles/puppet-setup-ansible/tasks/main.yaml b/playbooks/roles/puppet-setup-ansible/tasks/main.yaml
new file mode 100644
index 0000000000..dea701c0cb
--- /dev/null
+++ b/playbooks/roles/puppet-setup-ansible/tasks/main.yaml
@@ -0,0 +1,10 @@
+- include_role:
+    name: install-ansible-roles
+  vars:
+    ansible_roles:
+      - puppet
+
+- name: Run puppet module install on bridge
+  command:
+    cmd: bash install_modules.sh
+    chdir: /etc/puppet
diff --git a/playbooks/roles/run-puppet/README.rst b/playbooks/roles/run-puppet/README.rst
deleted file mode 100644
index b0a8bc5cb8..0000000000
--- a/playbooks/roles/run-puppet/README.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-Run puppet on remote servers
-
-Omnibus role that takes care of installing the puppet role,
-installing puppet and then running puppet. Uses include_role
-so that the installation of the puppet role can run as the
-first task, then the puppet role can be used in a following
-task.
-
-.. zuul:rolevar:: manifest
-   :default: manifests/site.pp
-
-   Puppet manifest file to run.
diff --git a/playbooks/service-codesearch.yaml b/playbooks/service-codesearch.yaml
index 27b2e4507d..fb6e7d9167 100644
--- a/playbooks/service-codesearch.yaml
+++ b/playbooks/service-codesearch.yaml
@@ -1,3 +1,9 @@
+- hosts: 'localhost:!disabled'
+  name: Install puppet role/modules
+  strategy: linear
+  roles:
+    - puppet-setup-ansible
+
 - hosts: 'codesearch:!disabled'
   name: "codesearch: run puppet on codesearch"
   strategy: free
@@ -5,5 +11,5 @@
     - iptables
     - sync-project-config
     - pip3
-    - name: run-puppet
+    - name: puppet-run
       manifest: /opt/system-config/production/manifests/codesearch.pp
diff --git a/playbooks/service-eavesdrop.yaml b/playbooks/service-eavesdrop.yaml
index 8be03a3139..124a82eae8 100644
--- a/playbooks/service-eavesdrop.yaml
+++ b/playbooks/service-eavesdrop.yaml
@@ -1,3 +1,9 @@
+- hosts: 'localhost:!disabled'
+  name: Install puppet role/modules
+  strategy: linear
+  roles:
+    - puppet-setup-ansible
+
 - hosts: 'eavesdrop:!disabled'
   name: "eavesdrop: run puppet on eavesdrop"
   strategy: free
@@ -8,5 +14,5 @@
     - install-docker
     - accessbot
     - gerritbot
-    - name: run-puppet
+    - name: puppet-run
       manifest: /opt/system-config/production/manifests/eavesdrop.pp
diff --git a/playbooks/service-nodepool.yaml b/playbooks/service-nodepool.yaml
index 51f5178fa2..87b6125044 100644
--- a/playbooks/service-nodepool.yaml
+++ b/playbooks/service-nodepool.yaml
@@ -8,6 +8,12 @@
     - configure-openstacksdk
     - nodepool-builder
 
+- hosts: 'localhost:!disabled'
+  name: Install puppet role/modules
+  strategy: linear
+  roles:
+    - puppet-setup-ansible
+
 - hosts: 'nb03.openstack.org:!disabled'
   name: "run puppet on all older servers"
   strategy: free
@@ -16,7 +22,7 @@
     - nodepool-base-legacy
     - configure-openstacksdk
     - configure-kubectl
-    - run-puppet
+    - puppet-run
 
 - hosts: nodepool-launcher:!disabled
   name: "Configure nodepool launchers"