-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add move_vm_from_on_prem_to_aws playbook and corresponding roles #95
Changes from all commits
e928a05
42abee2
df4fd7e
bed1f84
3e55e8b
36d2216
b419c73
06fb898
323d0c9
0245bb9
7a5eddd
6ce9958
e46f8c6
57d40f0
b7112a8
adc7d30
09e68f6
db70365
4f34046
376986c
9c7f86d
8afe2fe
ecb43f6
fd9a487
584e607
1c39b43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
``` |
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: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like there are some variables missing here. How does the user set the security groups, keypair, subnet, etc.? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not set those because they are optional, but if we want add all the variables that the role accepts I can do that. |
||
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 }}" |
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 |
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 |
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 }}" |
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 }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize if I've missed it, but could you please point me to where the playbook variables section is located?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here https://github.com/redhat-cop/cloud.aws_ops/pull/95/files#diff-3a382ac08ed4e75c0e95cbbabd59acfc9e5c8d543f4882cb588ee93f0ad0029fR10. To avoid content duplication I referenced the variable roles which are also the ones required by the playbook.