From 0a711211eadf33cbdf0953fe28bc8abdd69a8d5b Mon Sep 17 00:00:00 2001 From: happystacker Date: Thu, 17 Sep 2026 07:29:21 +0000 Subject: [PATCH 1/3] Storage: Add Dell PowerFlex backend support --- .../backends/dellpowerflex/__init__.py | 4 + .../storage/backends/dellpowerflex/backend.py | 190 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py create mode 100644 sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py diff --git a/sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py new file mode 100644 index 000000000..e993c72a4 --- /dev/null +++ b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2026 - Canonical Ltd +# SPDX-License-Identifier: Apache-2.0 + +"""Dell PowerFlex backend for Sunbeam storage.""" diff --git a/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py new file mode 100644 index 000000000..6730803bb --- /dev/null +++ b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py @@ -0,0 +1,190 @@ +# SPDX-FileCopyrightText: 2025 - Canonical Ltd +# SPDX-License-Identifier: Apache-2.0 + +"""Dell PowerFlex backend implementation using base step classes.""" + +import logging +from enum import StrEnum +from typing import Annotated, Literal + +from pydantic import Field +from rich.console import Console + +from sunbeam.core.manifest import StorageBackendConfig +from sunbeam.storage.base import StorageBackendBase +from sunbeam.storage.models import SecretDictField + +LOG = logging.getLogger(__name__) +console = Console() + + +class Protocol(StrEnum): + """Enumeration of valid PowerFlex protocol types.""" + + SCALEIO = "scaleio" + NVME_TCP = "nvme-tcp" + + +class PowerFlexConfig(StorageBackendConfig): + """Configuration model for Dell PowerFlex backend. + + This model includes the essential configuration options for deploying + a Dell PowerFlex backend. Additional configuration can be managed dynamically + through the charm configuration system. + """ + + # Mandatory connection parameters + san_ip: Annotated[ + str, Field(description="IP address of the PowerFlex Gateway server") + ] + san_login: Annotated[ + str, + Field(description="Username for PowerFlex Gateway with administrative privileges"), + SecretDictField(field="san-login"), + ] + san_password: Annotated[ + str, + Field(description="Password for PowerFlex Gateway authentication"), + SecretDictField(field="san-password"), + ] + powerflex_storage_pools: Annotated[ + str, + Field( + description="Comma-separated list of storage pools in format " + "protection_domain_name:storage_pool_name" + ), + ] + + # Protocol selection + protocol: Annotated[ + Literal["scaleio", "nvme-tcp"], + Field( + description="Dell PowerFlex protocol selector: scaleio (PowerFlexDriver) or nvme-tcp (PowerFlexNVMeDriver)" + ), + ] = "scaleio" + + # PowerFlex Gateway configuration + powerflex_rest_server_port: Annotated[ + int | None, + Field(description="Secured port to use when connecting to PowerFlex Manager"), + ] = 443 + + # Storage management + powerflex_max_over_subscription_ratio: Annotated[ + float | None, + Field( + description="Maximum oversubscription ratio allowed" + ), + ] = 10.0 + + # Volume management + powerflex_round_volume_capacity: Annotated[ + bool | None, + Field( + description="Round volume sizes up to 8GB boundaries. " + "PowerFlex OS requires volumes to be sized in multiples of 8GB" + ), + ] = True + + # Advanced configuration + powerflex_allow_non_padded_volumes: Annotated[ + bool | None, + Field( + description="Allow volumes to be created in Storage Pools when zero padding " + "is disabled. Should not be enabled if multiple tenants use volumes " + "from a shared Storage Pool" + ), + ] = None + powerflex_allow_migration_during_rebuild: Annotated[ + bool | None, + Field(description="Allow volume migration during rebuild operation"), + ] = None + + # REST API timeouts + rest_api_connect_timeout: Annotated[ + int | None, + Field(description="Connection timeout value (in seconds) for REST calls"), + ] = 30 + rest_api_read_timeout: Annotated[ + int | None, + Field(description="Read timeout value (in seconds) for REST calls"), + ] = 30 + + # Image cache configuration + powerflex_max_image_cache_vtree_size: Annotated[ + int | None, + Field( + description="Maximum size of the vTree associated with an entry in the " + "image volume cache" + ), + ] = 0 + + # Performance options + use_multipath_for_image_xfer: Annotated[ + bool | None, + Field(description="Enable multipathing for image transfer operations"), + ] = None + + # Replication configuration + replication_device: Annotated[ + str | None, + Field( + description="Specific replication configuration settings. Must be set under " + "the form of backend_id:powerflex_repl, san_ip: , " + "san_login: , san_password: " + ), + ] = None + + # SSL and security + driver_ssl_cert: Annotated[ + str | None, Field(description="PEM-encoded SSL certificate to use for HTTPS connections") + ] = None + + # Standard Cinder options + backend_availability_zone: Annotated[ + str | None, + Field(description="Availability zone to associate with this backend"), + ] = None + volume_backend_name: Annotated[ + str | None, + Field(description="Name that Cinder will report for this backend"), + ] = None + + +class PowerFlexBackend(StorageBackendBase): + """Dell PowerFlex backend implementation.""" + + backend_type = "dellpowerflex" + display_name = "Dell PowerFlex" + generally_available = True + + @property + def charm_name(self) -> str: + """Return the charm name for this backend.""" + return "cinder-volume-dellpowerflex" + + @property + def charm_channel(self) -> str: + """Return the charm channel for this backend.""" + #return "latest/edge" + return "2026.1/edge" + + @property + def charm_revision(self) -> str | None: + """Return the charm revision for this backend.""" + return None + + @property + def charm_base(self) -> str: + """Return the charm base for this backend.""" + return "ubuntu@24.04" + + @property + def supports_ha(self) -> bool: + """Return whether this backend supports HA deployments.""" + return True + + def config_type(self) -> type[StorageBackendConfig]: + """Return the configuration class for Dell PowerFlex backend.""" + return PowerFlexConfig + From 042e4c58b353de00400734117cc3845acbff2a31 Mon Sep 17 00:00:00 2001 From: happystacker Date: Thu, 17 Sep 2026 07:29:21 +0000 Subject: [PATCH 2/3] Storage: Add Dell PowerFlex backend support --- .../backends/dellpowerflex/__init__.py | 4 + .../storage/backends/dellpowerflex/backend.py | 189 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py create mode 100644 sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py diff --git a/sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py new file mode 100644 index 000000000..e993c72a4 --- /dev/null +++ b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/__init__.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2026 - Canonical Ltd +# SPDX-License-Identifier: Apache-2.0 + +"""Dell PowerFlex backend for Sunbeam storage.""" diff --git a/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py new file mode 100644 index 000000000..7c3a83b1a --- /dev/null +++ b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py @@ -0,0 +1,189 @@ +# SPDX-FileCopyrightText: 2025 - Canonical Ltd +# SPDX-License-Identifier: Apache-2.0 + +"""Dell PowerFlex backend implementation using base step classes.""" + +import logging +from enum import StrEnum +from typing import Annotated, Literal + +from pydantic import Field +from rich.console import Console + +from sunbeam.core.manifest import StorageBackendConfig +from sunbeam.storage.base import StorageBackendBase +from sunbeam.storage.models import SecretDictField + +LOG = logging.getLogger(__name__) +console = Console() + + +class Protocol(StrEnum): + """Enumeration of valid PowerFlex protocol types.""" + + SCALEIO = "scaleio" + NVME_TCP = "nvme-tcp" + + +class PowerFlexConfig(StorageBackendConfig): + """Configuration model for Dell PowerFlex backend. + + This model includes the essential configuration options for deploying + a Dell PowerFlex backend. Additional configuration can be managed dynamically + through the charm configuration system. + """ + + # Mandatory connection parameters + san_ip: Annotated[ + str, Field(description="IP address of the PowerFlex Gateway server") + ] + san_login: Annotated[ + str, + Field( + description="Username for PowerFlex Gateway with administrative privileges" + ), + SecretDictField(field="san-login"), + ] + san_password: Annotated[ + str, + Field(description="Password for PowerFlex Gateway authentication"), + SecretDictField(field="san-password"), + ] + powerflex_storage_pools: Annotated[ + str, + Field( + description="Comma-separated list of storage pools in format " + "protection_domain_name:storage_pool_name" + ), + ] + + # Protocol selection + protocol: Annotated[ + Literal["scaleio", "nvme-tcp"], + Field( + description="Dell PowerFlex protocol selector: scaleio (PowerFlexDriver) or nvme-tcp (PowerFlexNVMeDriver)" + ), + ] = "scaleio" + + # PowerFlex Gateway configuration + powerflex_rest_server_port: Annotated[ + int | None, + Field(description="Secured port to use when connecting to PowerFlex Manager"), + ] = 443 + + # Storage management + powerflex_max_over_subscription_ratio: Annotated[ + float | None, + Field(description="Maximum oversubscription ratio allowed"), + ] = 10.0 + + # Volume management + powerflex_round_volume_capacity: Annotated[ + bool | None, + Field( + description="Round volume sizes up to 8GB boundaries. " + "PowerFlex OS requires volumes to be sized in multiples of 8GB" + ), + ] = True + + # Advanced configuration + powerflex_allow_non_padded_volumes: Annotated[ + bool | None, + Field( + description="Allow volumes to be created in Storage Pools when zero padding " + "is disabled. Should not be enabled if multiple tenants use volumes " + "from a shared Storage Pool" + ), + ] = None + powerflex_allow_migration_during_rebuild: Annotated[ + bool | None, + Field(description="Allow volume migration during rebuild operation"), + ] = None + + # REST API timeouts + rest_api_connect_timeout: Annotated[ + int | None, + Field(description="Connection timeout value (in seconds) for REST calls"), + ] = 30 + rest_api_read_timeout: Annotated[ + int | None, + Field(description="Read timeout value (in seconds) for REST calls"), + ] = 30 + + # Image cache configuration + powerflex_max_image_cache_vtree_size: Annotated[ + int | None, + Field( + description="Maximum size of the vTree associated with an entry in the " + "image volume cache" + ), + ] = 0 + + # Performance options + use_multipath_for_image_xfer: Annotated[ + bool | None, + Field(description="Enable multipathing for image transfer operations"), + ] = None + + # Replication configuration + replication_device: Annotated[ + str | None, + Field( + description="Specific replication configuration settings. Must be set under " + "the form of backend_id:powerflex_repl, san_ip: , " + "san_login: , san_password: " + ), + ] = None + + # SSL and security + driver_ssl_cert: Annotated[ + str | None, + Field(description="PEM-encoded SSL certificate to use for HTTPS connections") + ] = None + + # Standard Cinder options + backend_availability_zone: Annotated[ + str | None, + Field(description="Availability zone to associate with this backend"), + ] = None + volume_backend_name: Annotated[ + str | None, + Field(description="Name that Cinder will report for this backend"), + ] = None + + +class PowerFlexBackend(StorageBackendBase): + """Dell PowerFlex backend implementation.""" + + backend_type = "dellpowerflex" + display_name = "Dell PowerFlex" + generally_available = True + + @property + def charm_name(self) -> str: + """Return the charm name for this backend.""" + return "cinder-volume-dellpowerflex" + + @property + def charm_channel(self) -> str: + """Return the charm channel for this backend.""" + return "latest/stable" + + @property + def charm_revision(self) -> str | None: + """Return the charm revision for this backend.""" + return None + + @property + def charm_base(self) -> str: + """Return the charm base for this backend.""" + return "ubuntu@24.04" + + @property + def supports_ha(self) -> bool: + """Return whether this backend supports HA deployments.""" + return True + + def config_type(self) -> type[StorageBackendConfig]: + """Return the configuration class for Dell PowerFlex backend.""" + return PowerFlexConfig From 3bef9999695f1d6167504d47374ae0cecf2c5398 Mon Sep 17 00:00:00 2001 From: happystacker Date: Thu, 17 Sep 2026 07:29:21 +0000 Subject: [PATCH 3/3] Storage: Add Dell PowerFlex backend support --- .../sunbeam/storage/backends/dellpowerflex/backend.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py index 7c3a83b1a..2b0984b63 100644 --- a/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py +++ b/sunbeam-python/sunbeam/storage/backends/dellpowerflex/backend.py @@ -74,7 +74,9 @@ class PowerFlexConfig(StorageBackendConfig): # Storage management powerflex_max_over_subscription_ratio: Annotated[ float | None, - Field(description="Maximum oversubscription ratio allowed"), + Field( + description="Maximum oversubscription ratio allowed" + ), ] = 10.0 # Volume management