|
8 | 8 |
|
9 | 9 | __metaclass__ = type
|
10 | 10 |
|
| 11 | +from ansible.module_utils.basic import AnsibleModule |
11 | 12 | from ..module_utils.typed_classes import (
|
12 | 13 | TypedVirtualDiskFromAnsible,
|
13 | 14 | TypedVirtualDiskToAnsible,
|
| 15 | + TypedTaskTag, |
14 | 16 | )
|
15 | 17 | from typing import Dict, List, Any, Optional
|
16 | 18 |
|
17 | 19 | from .rest_client import RestClient
|
18 | 20 | from ..module_utils.utils import PayloadMapper
|
| 21 | +from ..module_utils import errors |
| 22 | + |
| 23 | +REQUEST_TIMEOUT_TIME = 3600 |
19 | 24 |
|
20 | 25 |
|
21 | 26 | class VirtualDisk(PayloadMapper):
|
@@ -43,21 +48,20 @@ def from_ansible(cls, ansible_data: TypedVirtualDiskFromAnsible) -> VirtualDisk:
|
43 | 48 |
|
44 | 49 | @classmethod
|
45 | 50 | def from_hypercore(cls, hypercore_data: Dict[Any, Any]) -> VirtualDisk:
|
46 |
| - return cls( |
47 |
| - name=hypercore_data["name"], |
48 |
| - uuid=hypercore_data["uuid"], |
49 |
| - block_size=hypercore_data["blockSize"], |
50 |
| - size=hypercore_data["capacityBytes"], |
51 |
| - # allocated_size=hypercore_data["totalAllocationBytes"], |
52 |
| - replication_factor=hypercore_data["replicationFactor"], |
53 |
| - ) |
| 51 | + try: |
| 52 | + return cls( |
| 53 | + name=hypercore_data["name"], |
| 54 | + uuid=hypercore_data["uuid"], |
| 55 | + block_size=hypercore_data["blockSize"], |
| 56 | + size=hypercore_data["capacityBytes"], |
| 57 | + # allocated_size=hypercore_data["totalAllocationBytes"], |
| 58 | + replication_factor=hypercore_data["replicationFactor"], |
| 59 | + ) |
| 60 | + except KeyError as e: |
| 61 | + raise errors.MissingValueHypercore(e) |
54 | 62 |
|
55 | 63 | def to_hypercore(self) -> Dict[Any, Any]:
|
56 | 64 | raise NotImplementedError()
|
57 |
| - # return dict( |
58 |
| - # searchDomains=self.search_domains, |
59 |
| - # serverIPs=self.server_ips, |
60 |
| - # ) |
61 | 65 |
|
62 | 66 | def to_ansible(self) -> TypedVirtualDiskToAnsible:
|
63 | 67 | return dict(
|
@@ -93,14 +97,79 @@ def __eq__(self, other: object) -> bool:
|
93 | 97 | # virtual_disk = VirtualDisk.from_hypercore(hypercore_dict)
|
94 | 98 | # return virtual_disk
|
95 | 99 |
|
| 100 | + @classmethod |
| 101 | + def get_by_name( |
| 102 | + cls, rest_client: RestClient, name: str, must_exist: bool = False |
| 103 | + ) -> Optional[VirtualDisk]: |
| 104 | + result = rest_client.list_records("/rest/v1/VirtualDisk", query=dict(name=name)) |
| 105 | + if not isinstance(result, list): |
| 106 | + raise errors.ScaleComputingError( |
| 107 | + "Virtual disk API return value is not a list." |
| 108 | + ) |
| 109 | + elif must_exist and (not result or not result[0]): |
| 110 | + raise errors.ScaleComputingError( |
| 111 | + f"Virtual disk with name {name} does not exist." |
| 112 | + ) |
| 113 | + elif not result or not result[0]: |
| 114 | + return None |
| 115 | + elif len(result) > 1: |
| 116 | + raise errors.ScaleComputingError( |
| 117 | + f"Virtual disk {name} has multiple instances and is not unique." |
| 118 | + ) |
| 119 | + return cls.from_hypercore(result[0]) |
| 120 | + |
96 | 121 | @classmethod
|
97 | 122 | def get_state(
|
98 | 123 | cls, rest_client: RestClient, query: Dict[Any, Any]
|
99 | 124 | ) -> List[TypedVirtualDiskToAnsible]:
|
100 | 125 | state = [
|
101 |
| - VirtualDisk.from_hypercore(hypercore_data=hypercore_dict).to_ansible() |
| 126 | + cls.from_hypercore(hypercore_data=hypercore_dict).to_ansible() |
102 | 127 | for hypercore_dict in rest_client.list_records(
|
103 | 128 | "/rest/v1/VirtualDisk", query
|
104 | 129 | )
|
105 | 130 | ]
|
106 | 131 | return state
|
| 132 | + |
| 133 | + # Uploads a disk file (qcow2, vmdk, vhd); Hypercore creates virtual disk from uploaded file. |
| 134 | + # Filename and filesize need to be send as parameters in PUT request. |
| 135 | + @staticmethod |
| 136 | + def send_upload_request( |
| 137 | + rest_client: RestClient, file_size: int, module: AnsibleModule |
| 138 | + ) -> TypedTaskTag: |
| 139 | + if ( |
| 140 | + file_size is None |
| 141 | + or not module.params["name"] |
| 142 | + or not module.params["source"] |
| 143 | + ): |
| 144 | + raise errors.ScaleComputingError( |
| 145 | + "Missing some virtual disk file values inside upload request." |
| 146 | + ) |
| 147 | + try: |
| 148 | + with open(module.params["source"], "rb") as source_file: |
| 149 | + task = rest_client.put_record( |
| 150 | + endpoint="/rest/v1/VirtualDisk/upload", |
| 151 | + payload=None, |
| 152 | + check_mode=False, |
| 153 | + query=dict(filename=module.params["name"], filesize=file_size), |
| 154 | + timeout=REQUEST_TIMEOUT_TIME, |
| 155 | + binary_data=source_file, |
| 156 | + headers={ |
| 157 | + "Content-Type": "application/octet-stream", |
| 158 | + "Accept": "application/json", |
| 159 | + "Content-Length": file_size, |
| 160 | + }, |
| 161 | + ) |
| 162 | + except FileNotFoundError: |
| 163 | + raise errors.ScaleComputingError( |
| 164 | + f"Disk file {module.params['source']} not found." |
| 165 | + ) |
| 166 | + return task |
| 167 | + |
| 168 | + def send_delete_request(self, rest_client: RestClient) -> TypedTaskTag: |
| 169 | + if not self.uuid: |
| 170 | + raise errors.ScaleComputingError( |
| 171 | + "Missing virtual disk UUID inside delete request." |
| 172 | + ) |
| 173 | + return rest_client.delete_record( |
| 174 | + f"/rest/v1/VirtualDisk/{self.uuid}", check_mode=False |
| 175 | + ) |
0 commit comments