|
| 1 | +import logging |
| 2 | + |
| 3 | +from ecsclient.client import Client |
| 4 | + |
| 5 | +from coldfront.core.utils.common import import_from_settings |
| 6 | + |
| 7 | +ECS_CLIENT_VERSION = import_from_settings('ECS_CLIENT_VERSION', '3') |
| 8 | +ECS_USER = import_from_settings('ECS_USER') |
| 9 | +ECS_PASS = import_from_settings('ECS_PASS') |
| 10 | + |
| 11 | +logger = logging.getLogger(__name__) |
| 12 | + |
| 13 | + |
| 14 | +class ECSResourceManager(): |
| 15 | + """Class for managing objects related to an ECS cluster.""" |
| 16 | + |
| 17 | + def __init__(self, resource, username=ECS_USER, password=ECS_PASS): |
| 18 | + self.resource = resource |
| 19 | + self.url = resource.resourceattribute_set.get(resource_attribute_type__name='url').value |
| 20 | + self._username = username |
| 21 | + self._password = password |
| 22 | + self.client = self.connect() |
| 23 | + |
| 24 | + |
| 25 | + def connect(self): |
| 26 | + client = Client( |
| 27 | + ECS_CLIENT_VERSION, |
| 28 | + username=self._username, |
| 29 | + password=self._password, |
| 30 | + token_endpoint=f'{self.url}:4443/login', |
| 31 | + ecs_endpoint=f'{self.url}:4443' |
| 32 | + ) |
| 33 | + return client |
| 34 | + |
| 35 | + def generate_token(self, username, password): |
| 36 | + """Generate a token for ECS API access.""" |
| 37 | + |
| 38 | + def create_allocation_bucket(self, lab_name, block_limit_tb): |
| 39 | + """Create a quota for a tenant.""" |
| 40 | + bucket_name = f"lab-{lab_name}-bucket" |
| 41 | + block_limit_gb = block_limit_tb * 1024 |
| 42 | + notification_limit_gb = int(block_limit_gb * 0.9) |
| 43 | + try: |
| 44 | + self.client.bucket.create(bucket_name, namespace=lab_name, |
| 45 | + replication_group='', filesystem_enabled=False, |
| 46 | + head_type=None, stale_allowed=None, |
| 47 | + metadata=None, encryption_enabled=False |
| 48 | + ) |
| 49 | + except Exception as e: |
| 50 | + logger.exception("Error creating bucket %s: %s", bucket_name, str(e)) |
| 51 | + raise |
| 52 | + self.client.bucket.set_quota( |
| 53 | + bucket_name, |
| 54 | + block_size=block_limit_gb, |
| 55 | + notification_size=notification_limit_gb, |
| 56 | + ) |
| 57 | + |
| 58 | + def change_bucket_quota(self, bucket_name, namespace_name, new_block_size_tb): |
| 59 | + """Change a quota for a tenant.""" |
| 60 | + # possibly use this in create_allocation_bucket as well |
| 61 | + new_block_size_gb = new_block_size_tb * 1024 |
| 62 | + new_notification_size_gb = int(new_block_size_gb * 0.9) |
| 63 | + |
| 64 | + self.client.bucket.set_quota( |
| 65 | + bucket_name, |
| 66 | + namespace=namespace_name, |
| 67 | + block_size=new_block_size_gb, |
| 68 | + notification_size=new_notification_size_gb |
| 69 | + ) |
| 70 | + |
| 71 | + def delete_allocation_bucket(self, bucket_name, namespace_name): |
| 72 | + """Delete a quota for a tenant.""" |
| 73 | + self.client.bucket.delete(bucket_name, namespace=namespace_name) |
| 74 | + |
| 75 | + def update_resource_usage_data(self): |
| 76 | + """Get system usage data and update the corresponding resource records.""" |
| 77 | + capacity_dict = self.client.capacity.get_cluster_capacity() |
| 78 | + allocated_tb = capacity_dict['totalProvisioned_gb'] / 1024 |
| 79 | + free_tb = capacity_dict['totalFree_gb'] / 1024 |
| 80 | + capacity_tb = allocated_tb + free_tb |
| 81 | + tb_dict = {'allocated_tb': allocated_tb, 'free_tb': free_tb, 'capacity_tb': capacity_tb} |
| 82 | + for k, v in tb_dict.items(): |
| 83 | + logger.info("ECS Capacity %s: %.2f TB", k, v) |
| 84 | + attribute = self.resource.resourceattribute_set.get(resource_attribute_type__name=k) |
| 85 | + attribute.value = v |
| 86 | + attribute.save() |
| 87 | + return capacity_dict |
| 88 | + |
| 89 | + def update_bucket_allocation_usage_data(self, allocation, bucket_name, namespace_name): |
| 90 | + """Get bucket usage data and update the corresponding allocation records.""" |
| 91 | + # for getting bucket stats: |
| 92 | + bucket_stats = self.client.billing.get_bucket_billing_info( |
| 93 | + bucket_name, namespace_name, sizeunit='KB') |
| 94 | + total_size_tb = bucket_stats['total_size'] / (1024 * 1024 * 1024) |
| 95 | + total_size_bytes = bucket_stats['total_size'] * 1024 |
| 96 | + # update usage in bytes |
| 97 | + quota_bytes_attr = allocation.allocationattribute_set.get( |
| 98 | + allocation_attribute_type__name='Quota_In_Bytes') |
| 99 | + quota_bytes_attr.usage = total_size_bytes |
| 100 | + quota_bytes_attr.save() |
| 101 | + # update usage in TB |
| 102 | + quota_tb_attr = allocation.allocationattribute_set.get( |
| 103 | + allocation_attribute_type__name='Storage Quota (TB)' |
| 104 | + ) |
| 105 | + quota_tb_attr.usage = total_size_tb |
| 106 | + quota_tb_attr.save() |
0 commit comments