Skip to content

Instantly share code, notes, and snippets.

@hemna
Last active February 28, 2022 13:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hemna/b85d6a7c7b5193e526ff45c088b596f4 to your computer and use it in GitHub Desktop.
Save hemna/b85d6a7c7b5193e526ff45c088b596f4 to your computer and use it in GitHub Desktop.
Cinder capacity and utilization factors
def calculate_capacity_factors(total_capacity, free_capacity, provisioned_capacity,
thin_provisioning_support, max_over_subscription_ratio,
reserved_percentage, thin):
"""Create the various factors of the a particular backend.
Based off of definition of terms:
https://specs.openstack.org/openstack/cinder-specs/specs/queens/provisioning-improvements.html
total_capacity - The reported total capacity in the backend.
free_capacity - The free space/capacity as reported by the backend.
reserved_capacity - The amount of space reserved from the total_capacity as
as reported by the backend.
total_reserved_available_capacity - The total capacity minus reserved capacity
max_over_subscription_ratio - as reported by the backend
total_available_capacity - The total capacity available to cinder calculated from
total_reserved_available_capacity for thick provisioning OR
thin:
total_reserved_available_capacity and max_over_subscription_ratio
provisioned_capacity - as reported by backend or volume manager (allocated_capacity_gb)
calculated_free_capacity - total_available_capacity - provisioned_capacity
virtual_free_capacity - The calculated free capacity available to cinder to allocate new
storage.
For thin:
calculated_free_capacity
For thick:
the reported free_capacity can be less than the calculated
Capacity, so we use free_capacity - reserved_capacity.
free_capacity - reserved_capacity
free_percent - the percentage of the total_available_capacity is left over.
provisioned_ratio - The ratio of provisioned storage to total_available_capacity
"""
total = float(total_capacity)
reserved = float(reserved_percentage) / 100
reserved_capacity = math.floor(total * reserved)
total_avail = total - reserved_capacity
if thin and thin_provisioning_support:
total_available_capacity = total_avail * max_over_subscription_ratio
calculated_free = total_available_capacity - provisioned_capacity
virtual_free = calculated_free
provisioned_ratio = provisioned_capacity / total_available_capacity
else:
# Calculate how much free space is left after taking into
# account the reserved space.
total_available_capacity = total_avail
calculated_free = total_available_capacity - provisioned_capacity
virtual_free = free_capacity - reserved_capacity
# Some backends may report less free space than what cinder
# has calculated should be free.
# And calculated free, so we use the reported free instead.
if virtual_free < calculated_free:
virtual_free = free_capacity
max_over_subscription_ratio = None
provisioned_ratio = provisioned_capacity / total_available_capacity
free_percent = (virtual_free / total_available_capacity) * 100
return {
"total_capacity": total,
"free_capacity": free_capacity,
"reserved_capacity": reserved_capacity,
"total_reserved_available_capacity": total - reserved_capacity,
"max_over_subscription_ratio": max_over_subscription_ratio,
"total_available_capacity": total_available_capacity,
"provisioned_capacity": provisioned_capacity,
"calculated_free_capacity": calculated_free,
"virtual_free_capacity": virtual_free,
"free_percent": free_percent,
"provisioned_ratio": provisioned_ratio,
"provisioned_type": "thin" if thin else "thick"
}
@hemna
Copy link
Author

hemna commented Feb 25, 2022

#!/bin/env python
#
# This script uses the rich library to make output easier to read.
# pip install rich
#
from rich.console import Console
import math

c = Console()

def calculate_capacity_factors(total_capacity, free_capacity, provisioned_capacity,
                               thin_provisioning_support, max_over_subscription_ratio,
                               reserved_percentage, thin):
    """Create the various factors of the a particular backend.

    Based off of definition of terms:
        https://specs.openstack.org/openstack/cinder-specs/specs/queens/provisioning-improvements.html


    total_capacity - The reported total capacity in the backend.
    free_capacity - The free space/capacity as reported by the backend.
    reserved_capacity - The amount of space reserved from the total_capacity as
                        as reported by the backend.
    total_reserved_available_capacity - The total capacity minus reserved capacity
    max_over_subscription_ratio - as reported by the backend
    total_available_capacity - The total capacity available to cinder calculated from
                               total_reserved_available_capacity for thick provisioning OR
                               thin:
                               total_reserved_available_capacity and max_over_subscription_ratio
    provisioned_capacity - as reported by backend or volume manager (allocated_capacity_gb)
    calculated_free_capacity - total_available_capacity - provisioned_capacity
    virtual_free_capacity - The calculated free capacity available to cinder to allocate new
                            storage.
                            For thin:
                                calculated_free_capacity
                            For thick:
                                the reported free_capacity can be less than the calculated
                                Capacity, so we use free_capacity - reserved_capacity.
                                free_capacity - reserved_capacity
    free_percent - the percentage of the total_available_capacity is left over.
    provisioned_ratio - The ratio of provisioned storage to total_available_capacity

    """

    total = float(total_capacity)
    reserved = float(reserved_percentage) / 100
    reserved_capacity = math.floor(total * reserved)
    total_avail = total - reserved_capacity

    if thin and thin_provisioning_support:
        total_available_capacity = total_avail * max_over_subscription_ratio
        calculated_free = total_available_capacity - provisioned_capacity
        virtual_free = calculated_free
        provisioned_ratio = provisioned_capacity / total_available_capacity

    else:
        # Calculate how much free space is left after taking into
        # account the reserved space.
        total_available_capacity = total_avail
        calculated_free = total_available_capacity - provisioned_capacity
        virtual_free = free_capacity - reserved_capacity

        # Some backends may report less free space than what cinder
        # has calculated should be free.
        # And calculated free, so we use the reported free instead.
        if virtual_free < calculated_free:
            virtual_free = free_capacity
        max_over_subscription_ratio = None

    provisioned_ratio = provisioned_capacity / total_available_capacity
    free_percent = (virtual_free / total_available_capacity) * 100

    return {
        "total_capacity": total,
        "free_capacity": free_capacity,
        "reserved_capacity": reserved_capacity,
        "total_reserved_available_capacity": total - reserved_capacity,
        "max_over_subscription_ratio": max_over_subscription_ratio,
        "total_available_capacity": total_available_capacity,
        "provisioned_capacity": provisioned_capacity,
        "calculated_free_capacity": calculated_free,
        "virtual_free_capacity": virtual_free,
        "free_percent": free_percent,
        "provisioned_ratio": provisioned_ratio,
        "provisioned_type": "thin" if thin else "thick"
    }



volume_stats = {'pools': [
    {'pool_name': 'pool1',
    'total_capacity_gb': 30.01,
    'free_capacity_gb': 28.01,
    'allocated_capacity_gb': 2.0,
    'provisioned_capacity_gb': 2.0,
    'max_over_subscription_ratio': '1.0',
    'thin_provisioning_support': False,
    'thick_provisioning_support': True,
    'reserved_percentage': 5},

    {'pool_name': 'pool_foo',
    'total_capacity_gb': 30.01,
    'free_capacity_gb': 8.01,
    'allocated_capacity_gb': 2.0,
    'provisioned_capacity_gb': 2.0,
    'max_over_subscription_ratio': '1.0',
    'thin_provisioning_support': False,
    'thick_provisioning_support': True,
    'reserved_percentage': 5},

    {'pool_name': 'pool2',
    'total_capacity_gb': 20.01,
    'free_capacity_gb': 18.01,
    'allocated_capacity_gb': 2.0,
    'provisioned_capacity_gb': 2.0,
    'max_over_subscription_ratio': '2.0',
    'thin_provisioning_support': True,
    'thick_provisioning_support': False,
    'reserved_percentage': 5},

    {'pool_name': 'pool3',
     'total_capacity_gb': 500,
    'free_capacity_gb': 200,
    'provisioned_capacity_gb': 7000,
    'max_over_subscription_ratio': 20,
    'reserved_percentage': 5,
    'thin_provisioning_support': True,
    'thick_provisioning_support': False,
    }
]}


with c.status("Walking pools") as status:
    for pool in volume_stats['pools']:
        status.update(f"Running pool {pool}")
        #c.print_json(data=pool)

        total = pool['total_capacity_gb']
        allocated = pool['provisioned_capacity_gb']
        reported_free = pool['free_capacity_gb']
        thin = pool['thin_provisioning_support']
        max_oversub = float(pool['max_over_subscription_ratio'])
        reserved = pool['reserved_percentage']

        capacity_factors = calculate_capacity_factors(
            total,
            reported_free,
            allocated,
            thin,
            max_oversub,
            reserved,
            thin,
        )

        capacity_factors['pool_name'] = pool['pool_name']
        c.print_json(data=capacity_factors)

@hemna
Copy link
Author

hemna commented Feb 25, 2022

The output

{
  "total_capacity": 30.01,
  "free_capacity": 28.01,
  "reserved_capacity": 1,
  "total_reserved_available_capacity": 29.01,
  "max_over_subscription_ratio": null,
  "total_available_capacity": 29.01,
  "provisioned_capacity": 2.0,
  "calculated_free_capacity": 27.01,
  "virtual_free_capacity": 27.01,
  "free_percent": 93.10582557738711,
  "provisioned_ratio": 0.06894174422612892,
  "provisioned_type": "thick",
  "pool_name": "pool1"
}
{
  "total_capacity": 30.01,
  "free_capacity": 8.01,
  "reserved_capacity": 1,
  "total_reserved_available_capacity": 29.01,
  "max_over_subscription_ratio": null,
  "total_available_capacity": 29.01,
  "provisioned_capacity": 2.0,
  "calculated_free_capacity": 27.01,
  "virtual_free_capacity": 8.01,
  "free_percent": 27.611168562564632,
  "provisioned_ratio": 0.06894174422612892,
  "provisioned_type": "thick",
  "pool_name": "pool_foo"
}
{
  "total_capacity": 20.01,
  "free_capacity": 18.01,
  "reserved_capacity": 1,
  "total_reserved_available_capacity": 19.01,
  "max_over_subscription_ratio": 2.0,
  "total_available_capacity": 38.02,
  "provisioned_capacity": 2.0,
  "calculated_free_capacity": 36.02,
  "virtual_free_capacity": 36.02,
  "free_percent": 94.73961073119412,
  "provisioned_ratio": 0.052603892688058915,
  "provisioned_type": "thin",
  "pool_name": "pool2"
}
{
  "total_capacity": 500.0,
  "free_capacity": 200,
  "reserved_capacity": 25,
  "total_reserved_available_capacity": 475.0,
  "max_over_subscription_ratio": 20.0,
  "total_available_capacity": 9500.0,
  "provisioned_capacity": 7000,
  "calculated_free_capacity": 2500.0,
  "virtual_free_capacity": 2500.0,
  "free_percent": 26.31578947368421,
  "provisioned_ratio": 0.7368421052631579,
  "provisioned_type": "thin",
  "pool_name": "pool3"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment