generated from ansible-collections/collection_template
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Alina Buzachis <[email protected]>
- Loading branch information
1 parent
ba9c4b5
commit 7fa9b60
Showing
19 changed files
with
568 additions
and
258 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# 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 | ||
|
||
VM Import requires a role to perform certain operations on your behalf. You must create a service role named vmimport with a trust relationship policy document that allows VM Import to assume the role, and you must attach an IAM policy to the role. | ||
|
||
AWS User Account with the following permissions: | ||
* s3:GetBucketLocation | ||
* s3:GetObject | ||
* s3:ListBucket | ||
* s3:GetBucketLocation | ||
* s3:GetObject | ||
* s3:ListBucket | ||
* s3:PutObject | ||
* s3:GetBucketAcl | ||
* ec2:ModifySnapshotAttribute | ||
* ec2:CopySnapshot | ||
* ec2:RegisterImage | ||
* ec2:Describe* | ||
* ec2:RunInstances | ||
|
||
(Optional) To import resources encrypted using an AWS KMS key from AWS Key Management Service, add the following permissions: | ||
* kms:CreateGrant | ||
* kms:Decrypt | ||
* kms:DescribeKey | ||
* kms:Encrypt | ||
* kms:GenerateDataKey* | ||
* kms:ReEncrypt* | ||
|
||
## Playbook Variables | ||
|
||
### Needed for the cloud.aws_ops.clone_on_prem_vm role | ||
|
||
* **on_prem_source_vm_name** (str): (Required) The name of the on-prem VM you want to clone. | ||
* **on_prem_vm_clone_name** (str): (Optional) The name you want to call the cloned image. If not set, the the **on_prem_vm_clone_name** will be used with a _-clone_ suffix. | ||
* **uri** (str): (Optional) Libvirt connection uri. Default: "qemu:///system". | ||
* **overwrite_clone** (bool): (Optional) Weather to overwrite or not an already existing on prem VM clone. Default: true. | ||
|
||
### Needed for the cloud.aws_ops.clone_on_prem_vm role | ||
|
||
* **aws_access_key** (str): (Required) AWS access key ID for user account with the above permissions | ||
* **aws_secret_key** (str): (Required) AWS secret access key for user account with the above permissions | ||
* **aws_region** (str): (Required) AWS region in which to run the EC2 instance | ||
* **security_token** (str): (Optional) Security token for AWS session authentication | ||
* **s3_bucket_name** (str): (Required) The name of the S3 bucket name where you want to upload the .raw image. It must exist in the region the instance is created. | ||
* **import_task_name** (str): (Required) The name you want to assign to the AWS EC2 import image task. | ||
* **image_path** (str): (Required) The path where the .raw image is stored. | ||
* **instance_name** (str): (Required) The name of the EC2 instance you want to create using the imported AMI. | ||
* **instance_type** (str): (Optional) The EC2 instance type you want to use. Default: "t2.micro". | ||
* **keypair_name** (str): (Optional) The name of the SSH access key to assign to the EC2 instance. It must exist in the region the instance is created. If not set, your default AWS account keypair will be used. | ||
* **security_groups** (list): (Optional) A list of security group IDs or names to assiciate to the EC2 instance. | ||
* **vpc_subnet_id** (str): (Optional) The subnet ID in which to launch the EC2 instance instance (VPC). If none is provided, M(amazon.aws.ec2_instance) will chose the default zone of the default VPC. | ||
* **instance_volumes** (dict): (Optional) A dictionary of a block device mappings, by default this will always use the AMI root device so the **instance_volumes** option is primarily for adding more storage. A mapping contains the (optional) keys _device_name_, _ebs.volume_type_, _ebs.volume_size_, _ebs.kms_key_id_, _ebs.iops_, and _ebs.delete_on_termination_. | ||
|
||
* **kvm_host** (str): Information about the host running the KVM hypervisr that are dynamically added to the inventory. | ||
* **name**: This is a user-defined name for the host you are adding to the inventory. | ||
* **ansible_host**: This variable specifies the hostname or IP address of the host you are adding to the inventory. | ||
* **ansible_user**: This variable specifies the SSH username that Ansible should use when connecting to the host. | ||
* **ansible_ssh_private_key_file** This variable specifies the path to the SSH private key file that Ansible should use for authentication when connecting to the host. | ||
* **groups** This variable enabled you to assign the newly added host to one or more groups in the inventory. | ||
|
||
## Example Usage | ||
|
||
Create a `credentials.yaml` file with the folling contents: | ||
|
||
```yaml | ||
aws_access_key: "xxxxxxxxxxxxxxxxxxxx" | ||
aws_secret_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | ||
aws_region: "us-east-1" | ||
``` | ||
To migrate an existing on prem VM running on KVM hypervisor to AWS, run: | ||
```bash | ||
ansible-playbook move_vm_from_on_prem_to_aws.yml -e "@credentials.yaml" | ||
``` |
42 changes: 42 additions & 0 deletions
42
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,42 @@ | ||
- name: A playbook to migrate an existing on prem VM running on KVM hypervisor to AWS | ||
hosts: localhost | ||
gather_facts: false | ||
|
||
vars_files: | ||
- vars/main.yml | ||
|
||
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: Add host to inventory | ||
ansible.builtin.add_host: | ||
name: "{{ kvm_host.name }}" | ||
ansible_host: "{{ kvm_host.ip }}" | ||
ansible_user: "{{ kvm_host.ansible_user }}" | ||
ansible_ssh_common_args: -o "UserKnownHostsFile=/dev/null" -o StrictHostKeyChecking=no -i {{ kvm_host.ansible_ssh_private_key_file }} | ||
groups: "{{ kvm_host.groups }}" | ||
|
||
- 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: "{{ on_prem_source_vm_name }}" | ||
clone_on_prem_vm_dest_vm_name: "{{ on_prem_vm_clone_name }}" | ||
clone_on_prem_vm_uri: "{{ uri }}" | ||
clone_on_prem_vm_local_image_path: "{{ local_image_path }}" | ||
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: "{{ s3_bucket_name }}" | ||
import_image_and_run_aws_instance_image_path: "{{ clone_on_prem_vm_local_image_path }}" | ||
import_image_and_run_aws_instance_instance_name: "{{ instance_name }}" | ||
import_image_and_run_aws_instance_instance_type: "{{ instance_type }}" | ||
import_image_and_run_aws_instance_import_image_task_name: "{{ import_task_name }}" |
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,14 @@ | ||
on_prem_source_vm_name: "ubuntu-guest" | ||
on_prem_vm_clone_name: "ubuntu-guest-clone" | ||
s3_bucket_name: "clone-vm-s3-bucket" | ||
instance_name: "ubuntu-vm-clone" | ||
local_image_path: "~/images" | ||
import_task_name: "import-clone" | ||
instance_type: "t2.micro" | ||
uri: "qemu:///system" | ||
kvm_host: | ||
name: kvm | ||
ip: 192.168.1.117 | ||
ansible_user: vagrant | ||
ansible_ssh_private_key_file: ~/.ssh/id_rsa.pub | ||
groups: "libvirt" |
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,69 @@ | ||
Role Name | ||
========= | ||
|
||
A role to clone an existing on prem VM using the KVM hypervisor. The role sets the **clone_on_prem_vm_local_image_path** variable containing the path where the image was saved on localhost. | ||
|
||
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**: The name you want to call the cloned image. If not set, the the **clone_on_prem_vm_source_vm_name** will be used with a _-clone_ suffix. | ||
* **clone_on_prem_vm_overwrite**: Weather to overwrite or not an already existing on prem VM clone. Default: true. | ||
* **clone_on_prem_vm_local_image_path**: 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**: Libvirt connection uri. Default: "qemu:///system". | ||
|
||
Dependencies | ||
------------ | ||
|
||
N/A | ||
|
||
Example Playbook | ||
---------------- | ||
|
||
- hosts: localhost | ||
gather_facts: false | ||
|
||
vars: | ||
on_prem_source_vm_name: "ubuntu-guest" | ||
on_prem_vm_image_name: "ubuntu-guest-image" | ||
local_image_path: "~/images/" | ||
kvm_host: | ||
name: kvm | ||
ip: 192.168.1.117 | ||
ansible_user: vagrant | ||
ansible_ssh_private_key_file: ~/.ssh/id_rsa.pub | ||
|
||
tasks: | ||
- name: Add host to inventory | ||
ansible.builtin.add_host: | ||
name: "{{ kvm_host.name }}" | ||
ansible_host: "{{ kvm_host.ip }}" | ||
ansible_user: "{{ kvm_host.ansible_user }}" | ||
ansible_ssh_common_args: -o "UserKnownHostsFile=/dev/null" -o StrictHostKeyChecking=no -i {{ kvm_host.ansible_ssh_private_key_file }} | ||
groups: "libvirt" | ||
|
||
- 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: "{{ on_prem_source_vm_name }}" | ||
clone_on_prem_vm_dest_image_name: "{{ on_prem_vm_image_name }}" | ||
clone_on_prem_vm_local_image_path: "{{ local_image_path }}" | ||
delegate_to: kvm | ||
|
||
License | ||
------- | ||
|
||
GNU General Public License v3.0 or later | ||
|
||
See [LICENCE](https://github.com/ansible-collections/cloud.azure_roles/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,141 @@ | ||
--- | ||
- 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_dest_vm_name }}.qcow2" | ||
clone_on_prem_vm__raw_image_path: "{{ clone_on_prem_vm__tmpdir.path }}/{{ clone_on_prem_vm_dest_vm_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 | ||
|
||
# Priviledge 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 priviledge 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 localcolhost 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 }}" | ||
flat: yes | ||
fail_on_missing: yes | ||
validate_checksum: true | ||
register: clone_on_prem_vm_fetch_to_localhost | ||
|
||
- name: Set 'clone_on_prem_vm_local_image_path' | ||
ansible.builtin.set_fact: | ||
clone_on_prem_vm_local_image_path: "{{ clone_on_prem_vm_fetch_to_localhost.dest }}" |
Oops, something went wrong.