diff --git a/extra_playbooks/files/get_cinder_pvs.sh b/extra_playbooks/files/get_cinder_pvs.sh
new file mode 100644
index 0000000000000000000000000000000000000000..73a088ebc907fbedd0274abdff22fc85addeb05b
--- /dev/null
+++ b/extra_playbooks/files/get_cinder_pvs.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+kubectl get pv -o go-template --template='{{ range .items }}{{ $metadata := .metadata }}{{ with $value := index .metadata.annotations "pv.kubernetes.io/provisioned-by" }}{{ if eq $value "kubernetes.io/cinder" }}{{printf "%s\n" $metadata.name}}{{ end }}{{ end }}{{ end }}'
diff --git a/extra_playbooks/migrate_openstack_provider.yml b/extra_playbooks/migrate_openstack_provider.yml
new file mode 100644
index 0000000000000000000000000000000000000000..114e4cf0c7d532323b4c71872903808c18792a3b
--- /dev/null
+++ b/extra_playbooks/migrate_openstack_provider.yml
@@ -0,0 +1,28 @@
+---
+- hosts: kube-node:kube-master
+  tasks:
+    - name: Remove old cloud provider config
+      file:
+        path: "{{ item }}"
+        state: absent
+      with_items:
+        - /etc/kubernetes/cloud_config
+- hosts: kube-master[0]
+  tasks:
+    - name: Include kubespray-default variables
+      include_vars: ../roles/kubespray-defaults/defaults/main.yaml
+    - name: Copy get_cinder_pvs.sh to master
+      copy:
+        src: get_cinder_pvs.sh
+        dest: /tmp
+        mode: u+rwx
+    - name: Get PVs provisioned by in-tree cloud provider
+      command: /tmp/get_cinder_pvs.sh
+      register: pvs
+    - name: Remove get_cinder_pvs.sh
+      file:
+        path: /tmp/get_cinder_pvs.sh
+        state: absent
+    - name: Rewrite the "pv.kubernetes.io/provisioned-by" annotation
+      command: "{{ bin_dir }}/kubectl annotate --overwrite pv {{ item }} pv.kubernetes.io/provisioned-by=cinder.csi.openstack.org"
+      loop: "{{ pvs.stdout_lines | list }}"