Dell Infrastructure-as-a-code: Using Terraform to create and map PowerFlex 4.5 block volumes.

Ambar Hassani
6 min readMar 12, 2024

This blog is part of the Dell Infrastructure-as-a-code saga series.

In my previous article, we had observed a terraform method to create volumes on PowerFlex 4.5 Software Defined Storage. But why limit the terraforming abilities to just create volumes when you can extend the routines to even map them to the PowerFlex Software Defined Client.

In this blog, we will do exactly that. I have a PowerFlex 4.5 Software Defined Storage cluster and a ubuntu 20.04 machine configured with the PowerFlex 4.5 Software Defined client.

The task is to:

  • Create a block volume in PowerFlex 4.5 Software Defined Storage
  • Map it to the ubuntu machine’s software defined client (SDC ID: 21f358a600000000)

Let’s start!

Initial state capture. This is the current state of the volumes as seen in the ubuntu machine which is configured as a software defined client consuming block volumes from the PowerFlex 4.5 Software Defined cluster

#OUTPUT OF QUERYING THE POWERFLEX 4.5 METADATA MANAGERS

root@powerflex45-sdc-ubuntu-20-04-c1:/home/ubuntu# /opt/emc/scaleio/sdc/bin/drv_cfg --query_mdms
Retrieved 1 mdm(s)
MDM-ID a8a3d256f187e00f SDC ID 79aa06f600000006 INSTALLATION ID 587e0fff6d43b027 IPs [0]-10.204.111.85 [1]-10.204.111.86 [2]-10.204.111.87

#Current Volume status
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 40.4M 1 loop /snap/snapd/20671
loop1 7:1 0 67.2M 1 loop /snap/lxd/21835
loop2 7:2 0 63.9M 1 loop /snap/core20/2105
loop3 7:3 0 40.9M 1 loop
loop4 7:4 0 63.5M 1 loop
loop5 7:5 0 91.9M 1 loop /snap/lxd/24061
loop6 7:6 0 63.9M 1 loop /snap/core20/2182
loop7 7:7 0 39.1M 1 loop /snap/snapd/21184
sda 8:0 0 32G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 1.5G 0 part /boot
└─sda3 8:3 0 30.5G 0 part
└─ubuntu--vg-ubuntu--lv 253:0 0 15.3G 0 lvm /
sr0 11:0 1 1.2G 0 rom

variables.tf

variable "username" {
type = string
description = "Stores the username of PowerFlex host."
default = "admin"
}

variable "password" {
type = string
description = "Stores the password of PowerFlex host."
default = "XXXXXXXX"
}

variable "endpoint" {
type = string
description = "Stores the endpoint of PowerFlex host. eg: https://10.1.1.1:443, here 443 is port where API requests are getting accepted"
default = "https://powerflex45-equinix.edub.csc"
}

main.tf

terraform {
required_providers {
powerflex = {
version = "1.3.0"
source = "registry.terraform.io/dell/powerflex"
}
}
}
provider "powerflex" {
username = var.username
password = var.password
endpoint = var.endpoint
insecure = true
timeout = 120
}

resource "powerflex_volume" "volumes" {
count = 1
name = "dell-equinix-${count.index}"
protection_domain_name = "default"
storage_pool_name = "default"
size = 16
use_rm_cache = true
volume_type = "ThinProvisioned"
access_mode = "ReadWrite"
}

resource "time_sleep" "wait_for_volume" {
create_duration = "20s"
depends_on = [powerflex_volume.volumes]
}

resource "powerflex_sdc_volumes_mapping" "mapping-test" {
depends_on = [time_sleep.wait_for_volume]
# SDC name
id = "21f358a600000000"
volume_list = [
{
volume_name = "dell-equinix-0"
access_mode = "ReadOnly"
limit_iops = 120
limit_bw_in_mbps = 25
}
]
}

output "volumeid" {
value = [for volume in powerflex_volume.volumes : volume.id]
description = "PowerFlex Volume ID"
}

Now let’s execute the terraform templates

terraform init && terraform plan && terraform apply -auto-approve

As one can see from the terraform output, that our volume has been created and mapped

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of dell/powerflex from the dependency lock file
- Reusing previous version of hashicorp/time from the dependency lock file
- Using previously-installed dell/powerflex v1.3.0
- Using previously-installed hashicorp/time v0.11.1

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# powerflex_sdc_volumes_mapping.mapping-test will be created
+ resource "powerflex_sdc_volumes_mapping" "mapping-test" {
+ id = "79aa06f600000006"
+ name = (known after apply)
+ volume_list = [
+ {
+ access_mode = "ReadOnly"
+ limit_bw_in_mbps = 25
+ limit_iops = 120
+ volume_id = (known after apply)
+ volume_name = "dell-equinix-0"
},
]
}

# powerflex_volume.volumes[0] will be created
+ resource "powerflex_volume" "volumes" {
+ access_mode = "ReadWrite"
+ capacity_unit = "GB"
+ compression_method = (known after apply)
+ id = (known after apply)
+ name = "dell-equinix-0"
+ protection_domain_id = (known after apply)
+ protection_domain_name = "default"
+ remove_mode = "ONLY_ME"
+ size = 16
+ size_in_kb = 16777216
+ storage_pool_id = (known after apply)
+ storage_pool_name = "default"
+ use_rm_cache = true
+ volume_type = "ThinProvisioned"
}

# time_sleep.wait_for_volume will be created
+ resource "time_sleep" "wait_for_volume" {
+ create_duration = "20s"
+ id = (known after apply)
}

Plan: 3 to add, 0 to change, 0 to destroy.

Changes to Outputs:
+ volumeid = [
+ (known after apply),
]

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# powerflex_sdc_volumes_mapping.mapping-test will be created
+ resource "powerflex_sdc_volumes_mapping" "mapping-test" {
+ id = "79aa06f600000006"
+ name = (known after apply)
+ volume_list = [
+ {
+ access_mode = "ReadOnly"
+ limit_bw_in_mbps = 25
+ limit_iops = 120
+ volume_id = (known after apply)
+ volume_name = "dell-equinix-0"
},
]
}

# powerflex_volume.volumes[0] will be created
+ resource "powerflex_volume" "volumes" {
+ access_mode = "ReadWrite"
+ capacity_unit = "GB"
+ compression_method = (known after apply)
+ id = (known after apply)
+ name = "dell-equinix-0"
+ protection_domain_id = (known after apply)
+ protection_domain_name = "default"
+ remove_mode = "ONLY_ME"
+ size = 16
+ size_in_kb = 16777216
+ storage_pool_id = (known after apply)
+ storage_pool_name = "default"
+ use_rm_cache = true
+ volume_type = "ThinProvisioned"
}

# time_sleep.wait_for_volume will be created
+ resource "time_sleep" "wait_for_volume" {
+ create_duration = "20s"
+ id = (known after apply)
}

Plan: 3 to add, 0 to change, 0 to destroy.

Changes to Outputs:
+ volumeid = [
+ (known after apply),
]
powerflex_volume.volumes[0]: Creating...
powerflex_volume.volumes[0]: Creation complete after 0s [id=a5a5e49800000003]
time_sleep.wait_for_volume: Creating...
time_sleep.wait_for_volume: Still creating... [10s elapsed]
time_sleep.wait_for_volume: Still creating... [20s elapsed]
time_sleep.wait_for_volume: Creation complete after 20s [id=2024-03-12T06:28:35Z]
powerflex_sdc_volumes_mapping.mapping-test: Creating...
powerflex_sdc_volumes_mapping.mapping-test: Creation complete after 0s [id=79aa06f600000006]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

volumeid = [
"a5a5e49800000003",
]

Let’s verify this in the client ubuntu machine

lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 40.4M 1 loop /snap/snapd/20671
loop1 7:1 0 67.2M 1 loop /snap/lxd/21835
loop2 7:2 0 63.9M 1 loop /snap/core20/2105
loop3 7:3 0 40.9M 1 loop
loop4 7:4 0 63.5M 1 loop
loop5 7:5 0 91.9M 1 loop /snap/lxd/24061
loop6 7:6 0 63.9M 1 loop /snap/core20/2182
loop7 7:7 0 39.1M 1 loop /snap/snapd/21184
sda 8:0 0 32G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 1.5G 0 part /boot
└─sda3 8:3 0 30.5G 0 part
└─ubuntu--vg-ubuntu--lv 253:0 0 15.3G 0 lvm /
sr0 11:0 1 1.2G 0 rom
scinib 252:16 0 16G 1 disk

The scinib volume of 16G is a result of the above terraform execution.

From here on, it’s the routine of creating filesystem on “/dev/scinib” and consuming the volume.

cheers

Ambar@thecloudgarage

#iwork4dell

--

--

Ambar Hassani

24+ years of blended experience of technology & people leadership, startup management and disruptive acceleration/adoption of next-gen technologies