Dell Infrastructure-as-a-code: Terraforming with PowerFlex 4.5 Software Defined Storage

Ambar Hassani
9 min readJan 23, 2024

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

A short callout from Jeff Clarke in Dell Technologies World explains the noteworthiness of Dell’s PowerFlex platform.

“PowerFlex is probably my favorite product because its 100% our IP. It’s a software defined infrastructure product that is unmatched in the industry, there is nothing else like it. Its ability to scale compute and storage independently is unmatched. The ability to run file, block, hypervisors, bare metal all on a single platform — there is nothing else that does what this software defined infrastructure does. It has a uniqueness, particularly to where the marketplace is going and can help customers solve complex problems in this multi-cloud world.” — Jeff Clarke @ Dell Technologies World

In this blog, we will demonstrate a short-and-sweet exhibit of how traditional storage admins or DevOps personnel can use Terraform to work with Dell PowerFlex 4.5. Augmenting the PowerFlex value-proposition with the mightiness of Terraform simply creates magic for Scalable infrastructure whether it’s on-premises or in public cloud.

While this is just one capability (creating volumes), a range of others are embedded in the Terraform provider… Docs overview | dell/powerflex | Terraform | Terraform Registry

Enough said., let’s experience this practically.

To begin, I have 5 volumes from other use-cases that are already present on my PowerFlex 4.5 cluster (one of the names is obfuscated due to sensitivity)

I have created a variables.tf file with the below content

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

variable "password" {
type = string
description = "Stores the password of PowerFlex host."
value = "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"
value = "https://powerflex45-equinix.edub.csc"
}

Next, I have created a main.tf file with the below content

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 = 4
name = "dell-iac-test-${count.index}"
protection_domain_name = "default"
storage_pool_name = "default"
size = 8
use_rm_cache = true
volume_type = "ThinProvisioned"
access_mode = "ReadWrite"
}

Let’s execute the terraform template

Terraform init

terraform init

Initializing the backend...

Initializing provider plugins...
- Finding dell/powerflex versions matching "1.3.0"...
- Installing dell/powerflex v1.3.0...
- Installed dell/powerflex v1.3.0 (signed by a HashiCorp partner, key ID 9D39F0BFFE9C2292)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

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 plan

 terraform plan

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_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-iac-test-0"
+ protection_domain_id = (known after apply)
+ protection_domain_name = "default"
+ remove_mode = "ONLY_ME"
+ size = 8
+ size_in_kb = 8388608
+ storage_pool_id = (known after apply)
+ storage_pool_name = "default"
+ use_rm_cache = true
+ volume_type = "ThinProvisioned"
}

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

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

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

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

Terraform apply -auto-approve

 terraform apply -auto-approve

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_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-iac-test-0"
+ protection_domain_id = (known after apply)
+ protection_domain_name = "default"
+ remove_mode = "ONLY_ME"
+ size = 8
+ size_in_kb = 8388608
+ storage_pool_id = (known after apply)
+ storage_pool_name = "default"
+ use_rm_cache = true
+ volume_type = "ThinProvisioned"
}

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

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

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

Plan: 4 to add, 0 to change, 0 to destroy.
powerflex_volume.volumes[1]: Creating...
powerflex_volume.volumes[3]: Creating...
powerflex_volume.volumes[0]: Creating...
powerflex_volume.volumes[2]: Creating...
powerflex_volume.volumes[1]: Creation complete after 0s [id=64f9770c00000007]
powerflex_volume.volumes[2]: Creation complete after 0s [id=6

SUCCESS!!!!

4 volumes created in less than 10 seconds. Power of IaC and PowerFlex 4.5 SDS. Well, no surprises., we could have 40 volumes instead of 4 in a fast and efficient manner!!!

Let’s verify the volume creation in PowerFlex 4.5 manager web UI.

Notice 4 volumes with the prefix dell-iac-test-xxxx 8GB each and created at the same time.

To destroy

terraform destroy -auto-approve
powerflex_volume.volumes[0]: Refreshing state... [id=64f9770f0000000a]
powerflex_volume.volumes[1]: Refreshing state... [id=64f9770c00000007]
powerflex_volume.volumes[2]: Refreshing state... [id=64f9770e00000009]
powerflex_volume.volumes[3]: Refreshing state... [id=64f9770d00000008]

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

Terraform will perform the following actions:

# powerflex_volume.volumes[0] will be destroyed
- resource "powerflex_volume" "volumes" {
- access_mode = "ReadWrite" -> null
- capacity_unit = "GB" -> null
- compression_method = "NotApplicable" -> null
- id = "64f9770f0000000a" -> null
- name = "dell-iac-test-0" -> null
- protection_domain_id = "552851a800000000" -> null
- protection_domain_name = "default" -> null
- remove_mode = "ONLY_ME" -> null
- size = 8 -> null
- size_in_kb = 8388608 -> null
- storage_pool_id = "8824b04700000000" -> null
- storage_pool_name = "default" -> null
- use_rm_cache = true -> null
- volume_type = "ThinProvisioned" -> null
}

# powerflex_volume.volumes[1] will be destroyed
- resource "powerflex_volume" "volumes" {
- access_mode = "ReadWrite" -> null
- capacity_unit = "GB" -> null
- compression_method = "NotApplicable" -> null
- id = "64f9770c00000007" -> null
- name = "dell-iac-test-1" -> null
- protection_domain_id = "552851a800000000" -> null
- protection_domain_name = "default" -> null
- remove_mode = "ONLY_ME" -> null
- size = 8 -> null
- size_in_kb = 8388608 -> null
- storage_pool_id = "8824b04700000000" -> null
- storage_pool_name = "default" -> null
- use_rm_cache = true -> null
- volume_type = "ThinProvisioned" -> null
}

# powerflex_volume.volumes[2] will be destroyed
- resource "powerflex_volume" "volumes" {
- access_mode = "ReadWrite" -> null
- capacity_unit = "GB" -> null
- compression_method = "NotApplicable" -> null
- id = "64f9770e00000009" -> null
- name = "dell-iac-test-2" -> null
- protection_domain_id = "552851a800000000" -> null
- protection_domain_name = "default" -> null
- remove_mode = "ONLY_ME" -> null
- size = 8 -> null
- size_in_kb = 8388608 -> null
- storage_pool_id = "8824b04700000000" -> null
- storage_pool_name = "default" -> null
- use_rm_cache = true -> null
- volume_type = "ThinProvisioned" -> null
}

# powerflex_volume.volumes[3] will be destroyed
- resource "powerflex_volume" "volumes" {
- access_mode = "ReadWrite" -> null
- capacity_unit = "GB" -> null
- compression_method = "NotApplicable" -> null
- id = "64f9770d00000008" -> null
- name = "dell-iac-test-3" -> null
- protection_domain_id = "552851a800000000" -> null
- protection_domain_name = "default" -> null
- remove_mode = "ONLY_ME" -> null
- size = 8 -> null
- size_in_kb = 8388608 -> null
- storage_pool_id = "8824b04700000000" -> null
- storage_pool_name = "default" -> null
- use_rm_cache = true -> null
- volume_type = "ThinProvisioned" -> null
}

Plan: 0 to add, 0 to change, 4 to destroy.
powerflex_volume.volumes[2]: Destroying... [id=64f9770e00000009]
powerflex_volume.volumes[1]: Destroying... [id=64f9770c00000007]
powerflex_volume.volumes[3]: Destroying... [id=64f9770d00000008]
powerflex_volume.volumes[0]: Destroying... [id=64f9770f0000000a]
powerflex_volume.volumes[1]: Destruction complete after 0s
powerflex_volume.volumes[0]: Destruction complete after 0s
powerflex_volume.volumes[2]: Destruction complete after 0s
powerflex_volume.volumes[3]: Destruction complete after 0s

Destroy complete! Resources: 4 destroyed.

Fast and swift!

Let’s verify…. Indeed, back to square-one

Needless to say, that when you have a powerful platform like PowerFlex 4.5 running on-premises or in the cloud (APEX Block storage for public cloud) combined with IaC Terraform., cool things can happen. Just imagine extending Terraform deployments via Github actions or a GitOps pipeline where the Terraform template for PowerFlex SDS is executed as a container via ArgoCD or Flux.

Hopefully, I will spare some time soon to build out the above schematic in the lab. For now., you can read on how it can be done given it’s all Terraform.

Happy Terraform’ing & PowerFlex’ing

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