generated from ansible-collections/collection_template
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #95 from alinabuzachis/move_vm_from_on_prem_to_aws
Add move_vm_from_on_prem_to_aws playbook and corresponding roles
- Loading branch information
Showing
12 changed files
with
549 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# cloud.aws_ops.move_vm_from_on_prem_to_aws playbooks | ||
|
||
A playbook to migrate an existing on prem VM running on KVM hypervisor to AWS. | ||
|
||
## Requirements | ||
|
||
This playbook uses the ``cloud.aws_ops.clone_on_prem_vm`` role to clone an existing VM on prem using the KVM hypervisor and the ``cloud.aws_ops.import_image_and_run_aws_instance`` role to import a local .raw image into an Amazon machine image (AMI) and run an AWS EC2 instance. For a complete list of requirements, see [clone_on_prem_vm](../clone_on_prem_vm/README.md#Requirements) and [import_image_and_run_aws_instance](../roles/import_image_and_run_aws_instance/REAME.md#Requirements), respectively. | ||
|
||
|
||
## Playbook Variables | ||
|
||
For a full list of accepted variables see: [clone_on_prem_vm](../clone_on_prem_vm/README.md#Role-Variables) and respectively [import_image_and_run_aws_instance](../roles/import_image_and_run_aws_instance/REAME.md#Role-Variables). | ||
|
||
## Example Usage | ||
|
||
Create a `credentials.yml` file with the folling contents: | ||
|
||
```yaml | ||
aws_access_key: "xxxxxxxxxxxxxxxxxxxx" | ||
aws_secret_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | ||
aws_region: "us-east-1" | ||
``` | ||
Create an `inventory.yml` file with information about the host running the KVM hypervisor. | ||
|
||
```yaml | ||
--- | ||
all: | ||
hosts: | ||
kvm: | ||
ansible_host: myhost | ||
ansible_user: myuser | ||
ansible_ssh_private_key_file: /path/to/private_key | ||
groups: mygroup | ||
``` | ||
|
||
All the variables defined in section ``Playbook Variables`` can be defined inside the ``vars.yml`` file. | ||
|
||
Run the playbook: | ||
|
||
```shell | ||
ansible-playbook cloud.aws_ops.move_vm_from_on_prem_to_aws.move_vm_from_on_prem_to_aws -e "@credentials.yml" -e "@vars.yml" -i inventory.yml | ||
``` |
36 changes: 36 additions & 0 deletions
36
playbooks/move_vm_from_on_prem_to_aws/move_vm_from_on_prem_to_aws.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
- name: A playbook to migrate an existing on prem VM running on KVM hypervisor to AWS | ||
hosts: localhost | ||
gather_facts: false | ||
|
||
module_defaults: | ||
group/aws: | ||
aws_access_key: "{{ aws_access_key | default(omit) }}" | ||
aws_secret_key: "{{ aws_secret_key | default(omit) }}" | ||
security_token: "{{ security_token | default(omit) }}" | ||
region: "{{ aws_region | default('us-east-1') }}" | ||
|
||
tasks: | ||
- name: Import 'cloud.aws_ops.clone_on_prem_vm' role | ||
ansible.builtin.import_role: | ||
name: cloud.aws_ops.clone_on_prem_vm | ||
vars: | ||
clone_on_prem_vm_source_vm_name: "{{ clone_on_prem_vm_source_vm_name }}" | ||
clone_on_prem_vm_image_name: "{{ clone_on_prem_vm_image_name }}" | ||
clone_on_prem_vm_uri: "{{ clone_on_prem_vm_uri }}" | ||
clone_on_prem_vm_local_image_path: "{{ clone_on_prem_vm_local_image_path }}" | ||
clone_on_prem_vm_overwrite: "{{ clone_on_prem_vm_overwrite }}" | ||
delegate_to: kvm | ||
|
||
- name: Import 'cloud.aws_ops.import_image_and_run_aws_instance' role | ||
ansible.builtin.import_role: | ||
name: cloud.aws_ops.import_image_and_run_aws_instance | ||
vars: | ||
import_image_and_run_aws_instance_bucket_name: "{{ import_image_and_run_aws_instance_bucket_name }}" | ||
import_image_and_run_aws_instance_image_path: "{{ clone_on_prem_vm_raw_image_path }}" | ||
import_image_and_run_aws_instance_instance_name: "{{ import_image_and_run_aws_instance_instance_name }}" | ||
import_image_and_run_aws_instance_instance_type: "{{ import_image_and_run_aws_instance_instance_type }}" | ||
import_image_and_run_aws_instance_import_image_task_name: "{{ import_image_and_run_aws_instance_import_image_task_name }}" | ||
import_image_and_run_aws_instances_keypair_name: "{{ import_image_and_run_aws_instances_keypair_name }}" | ||
import_image_and_run_aws_instance_security_groups: "{{ import_image_and_run_aws_instance_security_groups }}" | ||
import_image_and_run_aws_instance_vpc_subnet_id: "{{ import_image_and_run_aws_instance_vpc_subnet_id }}" | ||
import_image_and_run_aws_instance_volumes: "{{ import_image_and_run_aws_instance_volumes }}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
clone_on_prem_vm | ||
================ | ||
|
||
A role to clone an existing on prem VM using the KVM hypervisor. The role sets the **clone_on_prem_vm_raw_image_path** variable containing the path where the image was saved on localhost. This role requires privilege escalation because the .qcow2 file created by ``virt-clone`` is owned by root and ``qemu-img convert`` requires access to convert it to .raw. | ||
|
||
Requirements | ||
------------ | ||
|
||
**qemu** and **qemu-img** packages installed. | ||
|
||
Role Variables | ||
-------------- | ||
|
||
* **clone_on_prem_vm_source_vm_name**: (Required) The name of the on-prem VM you want to clone. | ||
* **clone_on_prem_vm_image_name**: (Optional) The name you want to call the cloned image. If not set, the **clone_on_prem_vm_source_vm_name** will be used with a _-clone_ suffix. | ||
* **clone_on_prem_vm_overwrite**: (Optional) Whether to overwrite or not an already existing on prem VM clone. Default: true. | ||
* **clone_on_prem_vm_local_image_path**: (Optional) The path where you would like to save the image. If the path does not exists on localhost, the role will create it. If this parameter is not set, the role will save the image in a _~/tmp_ folder. | ||
* **clone_on_prem_vm_uri**: (Optional) Libvirt connection uri. Default: "qemu:///system". | ||
|
||
Dependencies | ||
------------ | ||
|
||
N/A | ||
|
||
Example Playbook | ||
---------------- | ||
|
||
Create an `inventory.yml` file with information about the host running the KVM hypervisor. | ||
|
||
```yaml | ||
--- | ||
all: | ||
hosts: | ||
kvm: | ||
ansible_host: myhost | ||
ansible_user: myuser | ||
ansible_ssh_private_key_file: /path/to/private_key | ||
groups: mygroup | ||
``` | ||
All the variables defined in section ``Playbook Variables`` can be defined inside the ``vars.yml`` file. | ||
Create a ``playbook.yml`` file like this: | ||
``` | ||
--- | ||
- hosts: kvm | ||
gather_facts: true | ||
|
||
tasks: | ||
- name: Import 'cloud.aws_ops.clone_on_prem_vm' role | ||
ansible.builtin.import_role: | ||
name: cloud.aws_ops.clone_on_prem_vm | ||
vars: | ||
clone_on_prem_vm_source_vm_name: "{{ clone_on_prem_vm_source_vm_name }}" | ||
clone_on_prem_vm_image_name: "{{ clone_on_prem_vm_image_name }}" | ||
clone_on_prem_vm_local_image_path: "{{ clone_on_prem_vm_local_image_path }}" | ||
clone_on_prem_vm_uri: "{{ clone_on_prem_vm_uri }}" | ||
``` | ||
Run the playbook: | ||
```shell | ||
ansible-playbook playbook.yml -i inventory.yml -e "@vars.yml" | ||
``` | ||
|
||
License | ||
------- | ||
|
||
GNU General Public License v3.0 or later | ||
|
||
See [LICENCE](https://github.com/ansible-collections/cloud.aws_ops/blob/main/LICENSE) to see the full text. | ||
|
||
Author Information | ||
------------------ | ||
|
||
- Ansible Cloud Content Team |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--- | ||
clone_on_prem_vm_uri: "qemu:///system" | ||
clone_on_prem_vm_overwrite: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
- name: Delete temporary directory | ||
ansible.builtin.file: | ||
state: absent | ||
path: "{{ clone_on_prem_vm__tmpdir.path }}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
--- | ||
- name: Fail when 'clone_on_prem_vm_source_vm_name' is undefined | ||
ansible.builtin.fail: | ||
msg: The name of the VM you want to clone must be defined as clone_on_prem_vm_source_vm_name | ||
when: clone_on_prem_vm_source_vm_name is undefined | ||
|
||
- name: Gather package facts | ||
ansible.builtin.package_facts: | ||
manager: auto | ||
register: package_facts | ||
|
||
- name: qemu is not installed | ||
debug: | ||
msg: "qemu is not installed" | ||
when: "'qemu' not in package_facts.ansible_facts.packages" | ||
|
||
- name: qemu-img is not installed | ||
debug: | ||
msg: "qemu-img is not installed" | ||
when: "'qemu-img' not in package_facts.ansible_facts.packages" | ||
|
||
- name: Create temporary directory to create the clone in | ||
ansible.builtin.tempfile: | ||
state: directory | ||
suffix: .storage | ||
register: clone_on_prem_vm__tmpdir | ||
notify: | ||
- "Delete temporary directory" | ||
|
||
- name: Get information about the on prem VM | ||
community.libvirt.virt: | ||
command: info | ||
name: "{{ clone_on_prem_vm_source_vm_name }}" | ||
uri: "{{ clone_on_prem_vm_uri }}" | ||
register: clone_on_prem_vm__vm_info | ||
|
||
- name: Fail when on prem VM does not exist | ||
ansible.builtin.fail: | ||
msg: "The on prem VM {{ clone_on_prem_vm_source_vm_name }} does not exist." | ||
when: clone_on_prem_vm_source_vm_name not in clone_on_prem_vm__vm_info | ||
|
||
- name: Fail when on prem VM's state is destroyed | ||
ansible.builtin.fail: | ||
msg: "The VM {{ clone_on_prem_vm_source_vm_name }} has been destroyed." | ||
when: clone_on_prem_vm__vm_info[clone_on_prem_vm_source_vm_name].state == "destroyed" | ||
|
||
- name: Set 'clone_on_prem_vm_image_name' varible | ||
ansible.builtin.set_fact: | ||
clone_on_prem_vm_image_name: "{{ clone_on_prem_vm_source_vm_name }}-clone" | ||
when: clone_on_prem_vm_image_name is undefined | ||
|
||
- name: Check if domain exists | ||
community.libvirt.virt: | ||
name: "{{ clone_on_prem_vm_image_name }}" | ||
command: info | ||
uri: "{{ clone_on_prem_vm_uri }}" | ||
register: clone_on_prem_vm__domain_info | ||
|
||
- name: Fail when a domain already exists | ||
ansible.builtin.fail: | ||
msg: "A domain {{ clone_on_prem_vm_image_name }} already exists. Please undefine it first or set clone_on_prem_vm_overwrite: true." | ||
when: clone_on_prem_vm_image_name in clone_on_prem_vm__domain_info and clone_on_prem_vm_overwrite is false | ||
|
||
- name: Undefine domain | ||
community.libvirt.virt: | ||
name: "{{ clone_on_prem_vm_image_name }}" | ||
command: undefine | ||
when: clone_on_prem_vm_image_name in clone_on_prem_vm__domain_info and clone_on_prem_vm_overwrite is true | ||
|
||
- name: Ensure on prem VM is paused | ||
community.libvirt.virt: | ||
state: paused | ||
name: "{{ clone_on_prem_vm_source_vm_name }}" | ||
uri: "{{ clone_on_prem_vm_uri }}" | ||
when: clone_on_prem_vm__vm_info[clone_on_prem_vm_source_vm_name].state == "running" | ||
|
||
- name: Set 'clone_on_prem_vm__clone_path' and 'clone_on_prem_vm__raw_image_path' | ||
ansible.builtin.set_fact: | ||
clone_on_prem_vm__clone_path: "{{ clone_on_prem_vm__tmpdir.path }}/{{ clone_on_prem_vm_image_name }}.qcow2" | ||
clone_on_prem_vm__raw_image_path: "{{ clone_on_prem_vm__tmpdir.path }}/{{ clone_on_prem_vm_image_name }}.raw" | ||
|
||
- name: Cloning {{ clone_on_prem_vm_source_vm_name }} on prem VM | ||
ansible.builtin.command: | | ||
virt-clone --original {{ clone_on_prem_vm_source_vm_name }} \ | ||
--name {{ clone_on_prem_vm_image_name }} \ | ||
--file {{ clone_on_prem_vm__clone_path }} | ||
environment: | ||
LIBVIRT_DEFAULT_URI: "{{ clone_on_prem_vm_uri }}" | ||
|
||
- name: Get information about the clone | ||
ansible.builtin.stat: | ||
path: "{{ clone_on_prem_vm__clone_path }}" | ||
register: clone_on_prem_vm__clone_info | ||
|
||
# Privilege escalation is needed because the .qcow2 file is owned by root | ||
# when default hypervisor is used | ||
- name: Convert qcow2 to raw using qemu-img with privilege escalation | ||
ansible.builtin.command: | | ||
qemu-img convert -f qcow2 -O raw \ | ||
{{ clone_on_prem_vm__clone_path }} \ | ||
{{ clone_on_prem_vm__raw_image_path }} | ||
become: true | ||
become_method: sudo | ||
environment: | ||
LIBVIRT_DEFAULT_URI: "{{ clone_on_prem_vm_uri }}" | ||
when: clone_on_prem_vm__clone_info.stat.exists and clone_on_prem_vm__clone_info.stat.pw_name == "root" | ||
|
||
- name: Convert qcow2 to raw using qemu-img | ||
ansible.builtin.command: | | ||
qemu-img convert -f qcow2 -O raw \ | ||
{{ clone_on_prem_vm__clone_path }} \ | ||
{{ clone_on_prem_vm__raw_image_path }} | ||
environment: | ||
LIBVIRT_DEFAULT_URI: "{{ clone_on_prem_vm_uri }}" | ||
when: clone_on_prem_vm__clone_info.stat.exists and clone_on_prem_vm__clone_info.stat.pw_name != "root" | ||
|
||
- name: Create temporary directory to localhost when clone_on_prem_vm_local_image_path is not set | ||
ansible.builtin.tempfile: | ||
state: directory | ||
suffix: .storage | ||
register: clone_on_prem_vm__dir_localhost | ||
when: clone_on_prem_vm_local_image_path is undefined | ||
delegate_to: localhost | ||
|
||
- name: Create directory if it does not exist | ||
ansible.builtin.file: | ||
path: "{{ clone_on_prem_vm_local_image_path }}" | ||
state: directory | ||
mode: 0775 | ||
recurse: yes | ||
register: clone_on_prem_vm__dir_localhost | ||
when: clone_on_prem_vm_local_image_path is defined | ||
delegate_to: localhost | ||
|
||
- name: Fetch the converted RAW image to localhost | ||
ansible.builtin.fetch: | ||
src: "{{ clone_on_prem_vm__raw_image_path }}" | ||
dest: "{{ clone_on_prem_vm__dir_localhost.path }}" | ||
validate_checksum: true | ||
register: clone_on_prem_vm_fetch_to_localhost | ||
|
||
- name: Set 'clone_on_prem_vm_raw_image_path' | ||
ansible.builtin.set_fact: | ||
clone_on_prem_vm_raw_image_path: "{{ clone_on_prem_vm_fetch_to_localhost.dest }}" |
Oops, something went wrong.