amazon-web-servicesamazon-ec2ansibleamazon-ebs

How to get real EBS device name for formatting and mounting in Ansible


I am trying to use Ansible to build, attach, format and mount a EBS volume to an EC2 instance. When I build and attach the volume, the name does not match in the instance. How do I get the correct name?

I have tried to change the device_name to match what AWS is setting it to, but that gives me a "...not a valid EBS device name." error.

Here is what I am trying:

---
- name: Get instance ID
  ec2_metadata_facts:
- debug:
    msg: "Adding EBS to {{ ansible_ec2_instance_id }}"
- name: Create EBS
  delegate_to: 127.0.0.1
  run_once: true
  ec2_vol:
    instance: "{{ ansible_ec2_instance_id }}"
    volume_size: '5'
    region: 'us-east-1'
    delete_on_termination: yes
    name: 'wbt_opt_drive'
  register: ec2_vol
- name: Printing the volume information
  debug: var=ec2_vol

The volume information returns this:

"device": "/dev/sdf"

If I try to add a file system, /dev/sdf does not exist. Checking the instance this is what I get running lsblk

nvme1n1     259:1    0    8G  0 disk 
└─nvme1n1p1 259:2    0    8G  0 part /
nvme2n1     259:3    0    5G  0 disk 

If I change my task to use the device_name AWS is defaulting to:

---
- name: Get instance ID
  ec2_metadata_facts:
- debug:
    msg: "Adding EBS to {{ ansible_ec2_instance_id }}"
- name: Create EBS
  delegate_to: 127.0.0.1
  run_once: true
  ec2_vol:
    instance: "{{ ansible_ec2_instance_id }}"
    volume_size: '5'
    region: 'us-east-1'
    delete_on_termination: yes
    name: 'wbt_opt_drive'
    device_name: '/dev/nvme2n1'
  register: ec2_vol
- name: Printing the volume information
  debug: var=ec2_vol

I get this error:

/dev/nvme2n1 is not a valid EBS device name.

From the docs, I understand what AWS is doing (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html / https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html)

But I want to make this dynamic for all types of instances I might want to create. Is there a way to get the real endpoint from the device mount point that is returned or from the ID?


Solution

  • I found a good solution on https://flowciety.de/en/development-notes-en/ansible-and-aws/

    In case the link breaks I'll summarise their solution here.

    # Per question assume that result of ebs_create is registered to `ec2_vol`
    
    - name: Get Linux device for EBS Volume
      ansible.builtin.shell:
        cmd: "lsblk -o PATH,SERIAL | grep {{ ec2_vol.volume_id | replace('-', '') }} | cut -d ' ' -f 1"
      register: lsblk
    
    - name: Store EBS volume device name
      ansible.builtin.set_fact:
        ebs_volume_device_name: "{{ lsblk.stdout }}"
    

    IMPORTANT: Do not use this device name for automatically mounting the device on system startup (e.g. in /etc/fstab). Per the docs the mapping of volumes to NVMe devices is non-deterministic for EBS devices attached on system startup. Instead once you format the device you should either set a and use a label LABEL or extract and use the UUID as this should not change regardless of NVMe registration order.

    Alt: Getting name from existing volume (from same link as above)

    - name: Get EC2 volume details
      delegate_to: localhost
      amazon.aws.ec2_vol_info:
        filters:
          "tag:Name": "some-data"  # Assume unique volume name
      register: ec2_vol_info
    
    - name: Get Linux device for EBS Volume
      ansible.builtin.shell:
        cmd: "lsblk -o PATH,SERIAL | grep {{ ec2_vol_info.volumes[0].id | replace('-', '') }} | cut -d ' ' -f 1"
      register: lsblk
    
    # ...