github.com/LINBIT/golinstor@v0.52.0/client/resource.go (about) 1 // A REST client to interact with LINSTOR's REST API 2 // Copyright (C) LINBIT HA-Solutions GmbH 3 // All Rights Reserved. 4 // Author: Roland Kammerer <roland.kammerer@linbit.com> 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); you may 7 // not use this file except in compliance with the License. You may obtain 8 // a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 // License for the specific language governing permissions and limitations 16 // under the License. 17 18 package client 19 20 import ( 21 "context" 22 "encoding/json" 23 "fmt" 24 "strconv" 25 26 "github.com/google/go-querystring/query" 27 28 "github.com/LINBIT/golinstor/devicelayerkind" 29 "github.com/LINBIT/golinstor/snapshotshipstatus" 30 ) 31 32 // ResourceService is a struct which contains the pointer of the client 33 type ResourceService struct { 34 client *Client 35 } 36 37 // copy & paste from generated code 38 39 // Resource is a struct which holds the information of a resource 40 type Resource struct { 41 Name string `json:"name,omitempty"` 42 NodeName string `json:"node_name,omitempty"` 43 // A string to string property map. 44 Props map[string]string `json:"props,omitempty"` 45 Flags []string `json:"flags,omitempty"` 46 LayerObject *ResourceLayer `json:"layer_object,omitempty"` 47 State *ResourceState `json:"state,omitempty"` 48 // unique object id 49 Uuid string `json:"uuid,omitempty"` 50 // milliseconds since unix epoch in UTC 51 CreateTimestamp *TimeStampMs `json:"create_timestamp,omitempty"` 52 } 53 54 type ResourceWithVolumes struct { 55 Resource 56 // milliseconds since unix epoch in UTC 57 CreateTimestamp *TimeStampMs `json:"create_timestamp,omitempty"` 58 Volumes []Volume `json:"volumes,omitempty"` 59 // shared space name of the data storage pool of the first volume of 60 // the resource or empty if data storage pool is not shared 61 SharedName string `json:"shared_name,omitempty"` 62 } 63 64 type ResourceDefinitionModify struct { 65 // drbd port for resources 66 DrbdPort int32 `json:"drbd_port,omitempty"` 67 // drbd peer slot number 68 DrbdPeerSlots int32 `json:"drbd_peer_slots,omitempty"` 69 LayerStack []devicelayerkind.DeviceLayerKind `json:"layer_stack,omitempty"` 70 // change resource group to the given group name 71 ResourceGroup string `json:"resource_group,omitempty"` 72 GenericPropsModify 73 } 74 75 // ResourceCreate is a struct where the properties of a resource are stored to create it 76 type ResourceCreate struct { 77 Resource Resource `json:"resource,omitempty"` 78 LayerList []devicelayerkind.DeviceLayerKind `json:"layer_list,omitempty"` 79 DrbdNodeId int32 `json:"drbd_node_id,omitempty"` 80 } 81 82 // ResourceLayer is a struct to store layer-information abour a resource 83 type ResourceLayer struct { 84 Children []ResourceLayer `json:"children,omitempty"` 85 ResourceNameSuffix string `json:"resource_name_suffix,omitempty"` 86 Type devicelayerkind.DeviceLayerKind `json:"type,omitempty"` 87 Drbd *DrbdResource `json:"drbd,omitempty"` 88 Luks *LuksResource `json:"luks,omitempty"` 89 Storage *StorageResource `json:"storage,omitempty"` 90 Nvme *NvmeResource `json:"nvme,omitempty"` 91 Writecache *WritecacheResource `json:"writecache,omitempty"` 92 Cache *CacheResource `json:"cache,omitempty"` 93 BCache *BCacheResource `json:"bcache,omitempty"` 94 } 95 96 type WritecacheResource struct { 97 WritecacheVolumes []WritecacheVolume `json:"writecache_volumes,omitempty"` 98 } 99 100 type WritecacheVolume struct { 101 VolumeNumber int32 `json:"volume_number,omitempty"` 102 // block device path 103 DevicePath string `json:"device_path,omitempty"` 104 // block device path used as cache device 105 DevicePathCache string `json:"device_path_cache,omitempty"` 106 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 107 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 108 // String describing current volume state 109 DiskState string `json:"disk_state,omitempty"` 110 } 111 112 type BCacheResource struct { 113 BCacheVolumes []BCacheVolume `json:"bcache_volumes,omitempty"` 114 } 115 116 type BCacheVolume struct { 117 VolumeNumber int32 `json:"volume_number,omitempty"` 118 // block device path 119 DevicePath string `json:"device_path,omitempty"` 120 // block device path used as cache device 121 DevicePathCache string `json:"device_path_cache,omitempty"` 122 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 123 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 124 // String describing current volume state 125 DiskState string `json:"disk_state,omitempty"` 126 } 127 128 // DrbdResource is a struct used to give linstor drbd properties for a resource 129 type DrbdResource struct { 130 DrbdResourceDefinition DrbdResourceDefinitionLayer `json:"drbd_resource_definition,omitempty"` 131 NodeId int32 `json:"node_id,omitempty"` 132 PeerSlots int32 `json:"peer_slots,omitempty"` 133 AlStripes int32 `json:"al_stripes,omitempty"` 134 AlSize int64 `json:"al_size,omitempty"` 135 Flags []string `json:"flags,omitempty"` 136 DrbdVolumes []DrbdVolume `json:"drbd_volumes,omitempty"` 137 Connections map[string]DrbdConnection `json:"connections,omitempty"` 138 PromotionScore int32 `json:"promotion_score,omitempty"` 139 MayPromote bool `json:"may_promote,omitempty"` 140 } 141 142 // DrbdConnection is a struct representing the DRBD connection status 143 type DrbdConnection struct { 144 Connected bool `json:"connected,omitempty"` 145 // DRBD connection status 146 Message string `json:"message,omitempty"` 147 } 148 149 // DrbdVolume is a struct for linstor to get inormation about a drbd-volume 150 type DrbdVolume struct { 151 DrbdVolumeDefinition DrbdVolumeDefinition `json:"drbd_volume_definition,omitempty"` 152 // drbd device path e.g. '/dev/drbd1000' 153 DevicePath string `json:"device_path,omitempty"` 154 // block device used by drbd 155 BackingDevice string `json:"backing_device,omitempty"` 156 MetaDisk string `json:"meta_disk,omitempty"` 157 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 158 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 159 // String describing current volume state 160 DiskState string `json:"disk_state,omitempty"` 161 // Storage pool name used for external meta data; null for internal 162 ExtMetaStorPool string `json:"ext_meta_stor_pool,omitempty"` 163 } 164 165 // LuksResource is a struct to store storage-volumes for a luks-resource 166 type LuksResource struct { 167 StorageVolumes []LuksVolume `json:"storage_volumes,omitempty"` 168 } 169 170 // LuksVolume is a struct used for information about a luks-volume 171 type LuksVolume struct { 172 VolumeNumber int32 `json:"volume_number,omitempty"` 173 // block device path 174 DevicePath string `json:"device_path,omitempty"` 175 // block device used by luks 176 BackingDevice string `json:"backing_device,omitempty"` 177 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 178 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 179 // String describing current volume state 180 DiskState string `json:"disk_state,omitempty"` 181 Opened bool `json:"opened,omitempty"` 182 } 183 184 // StorageResource is a struct which contains the storage-volumes for a storage-resource 185 type StorageResource struct { 186 StorageVolumes []StorageVolume `json:"storage_volumes,omitempty"` 187 } 188 189 // StorageVolume is a struct to store standard poperties of a Volume 190 type StorageVolume struct { 191 VolumeNumber int32 `json:"volume_number,omitempty"` 192 // block device path 193 DevicePath string `json:"device_path,omitempty"` 194 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 195 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 196 // String describing current volume state 197 DiskState string `json:"disk_state,omitempty"` 198 } 199 200 type NvmeResource struct { 201 NvmeVolumes []NvmeVolume `json:"nvme_volumes,omitempty"` 202 } 203 204 type NvmeVolume struct { 205 VolumeNumber int32 `json:"volume_number,omitempty"` 206 // block device path 207 DevicePath string `json:"device_path,omitempty"` 208 // block device used by nvme 209 BackingDevice string `json:"backing_device,omitempty"` 210 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 211 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 212 // String describing current volume state 213 DiskState string `json:"disk_state,omitempty"` 214 } 215 216 // ResourceState is a struct for getting the status of a resource 217 type ResourceState struct { 218 InUse *bool `json:"in_use,omitempty"` 219 } 220 221 // Volume is a struct which holds the information about a linstor-volume 222 type Volume struct { 223 VolumeNumber int32 `json:"volume_number,omitempty"` 224 StoragePoolName string `json:"storage_pool_name,omitempty"` 225 ProviderKind ProviderKind `json:"provider_kind,omitempty"` 226 DevicePath string `json:"device_path,omitempty"` 227 AllocatedSizeKib int64 `json:"allocated_size_kib,omitempty"` 228 UsableSizeKib int64 `json:"usable_size_kib,omitempty"` 229 // A string to string property map. 230 Props map[string]string `json:"props,omitempty"` 231 Flags []string `json:"flags,omitempty"` 232 State VolumeState `json:"state,omitempty"` 233 LayerDataList []VolumeLayer `json:"layer_data_list,omitempty"` 234 // unique object id 235 Uuid string `json:"uuid,omitempty"` 236 Reports []ApiCallRc `json:"reports,omitempty"` 237 } 238 239 // VolumeLayer is a struct for storing the layer-properties of a linstor-volume 240 type VolumeLayer struct { 241 Type devicelayerkind.DeviceLayerKind `json:"type,omitempty"` 242 Data OneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume `json:"data,omitempty"` 243 } 244 245 // VolumeState is a struct which contains the disk-state for volume 246 type VolumeState struct { 247 DiskState string `json:"disk_state,omitempty"` 248 } 249 250 // AutoPlaceRequest is a struct to store the paramters for the linstor auto-place command 251 type AutoPlaceRequest struct { 252 DisklessOnRemaining bool `json:"diskless_on_remaining,omitempty"` 253 SelectFilter AutoSelectFilter `json:"select_filter,omitempty"` 254 LayerList []devicelayerkind.DeviceLayerKind `json:"layer_list,omitempty"` 255 } 256 257 // AutoSelectFilter is a struct used to have information about the auto-select function 258 type AutoSelectFilter struct { 259 PlaceCount int32 `json:"place_count,omitempty"` 260 AdditionalPlaceCount int32 `json:"additional_place_count,omitempty"` 261 NodeNameList []string `json:"node_name_list,omitempty"` 262 StoragePool string `json:"storage_pool,omitempty"` 263 StoragePoolList []string `json:"storage_pool_list,omitempty"` 264 StoragePoolDisklessList []string `json:"storage_pool_diskless_list,omitempty"` 265 NotPlaceWithRsc []string `json:"not_place_with_rsc,omitempty"` 266 NotPlaceWithRscRegex string `json:"not_place_with_rsc_regex,omitempty"` 267 ReplicasOnSame []string `json:"replicas_on_same,omitempty"` 268 ReplicasOnDifferent []string `json:"replicas_on_different,omitempty"` 269 LayerStack []string `json:"layer_stack,omitempty"` 270 ProviderList []string `json:"provider_list,omitempty"` 271 DisklessOnRemaining bool `json:"diskless_on_remaining,omitempty"` 272 DisklessType string `json:"diskless_type,omitempty"` 273 Overprovision *float64 `json:"overprovision,omitempty"` 274 } 275 276 // ResourceConnection is a struct which holds information about a connection between to nodes 277 type ResourceConnection struct { 278 // source node of the connection 279 NodeA string `json:"node_a,omitempty"` 280 // target node of the connection 281 NodeB string `json:"node_b,omitempty"` 282 // A string to string property map. 283 Props map[string]string `json:"props,omitempty"` 284 Flags []string `json:"flags,omitempty"` 285 Port int32 `json:"port,omitempty"` 286 } 287 288 // Snapshot is a struct for information about a snapshot 289 type Snapshot struct { 290 Name string `json:"name,omitempty"` 291 ResourceName string `json:"resource_name,omitempty"` 292 Nodes []string `json:"nodes,omitempty"` 293 // A string to string property map. 294 Props map[string]string `json:"props,omitempty"` 295 Flags []string `json:"flags,omitempty"` 296 VolumeDefinitions []SnapshotVolumeDefinition `json:"volume_definitions,omitempty"` 297 // unique object id 298 Uuid string `json:"uuid,omitempty"` 299 Snapshots []SnapshotNode `json:"snapshots,omitempty"` 300 } 301 302 // SnapshotNode Actual snapshot data from a node 303 type SnapshotNode struct { 304 // Snapshot name this snapshots belongs to 305 SnapshotName string `json:"snapshot_name,omitempty"` 306 // Node name where this snapshot was taken 307 NodeName string `json:"node_name,omitempty"` 308 // milliseconds since unix epoch in UTC 309 CreateTimestamp *TimeStampMs `json:"create_timestamp,omitempty"` 310 Flags []string `json:"flags,omitempty"` 311 // unique object id 312 Uuid string `json:"uuid,omitempty"` 313 // SnapshotVolumes holds per-volume information about snapshots on this node. 314 SnapshotVolumes []SnapshotVolumeNode `json:"snapshot_volumes,omitempty"` 315 } 316 317 type SnapshotVolumeNode struct { 318 // unique object id 319 Uuid string `json:"uuid,omitempty"` 320 // Volume number of the snapshot 321 VlmNr int32 `json:"vlm_nr,omitempty"` 322 // A string to string property map. 323 Props map[string]string `json:"props,omitempty"` 324 // Optional state for the given snapshot 325 State string `json:"state,omitempty"` 326 } 327 328 // SnapshotShipping struct for SnapshotShipping 329 type SnapshotShipping struct { 330 // Node where to ship the snapshot from 331 FromNode string `json:"from_node"` 332 // NetInterface of the source node 333 FromNic string `json:"from_nic,omitempty"` 334 // Node where to ship the snapshot 335 ToNode string `json:"to_node"` 336 // NetInterface of the destination node 337 ToNic string `json:"to_nic,omitempty"` 338 } 339 340 // SnapshotShippingStatus struct for SnapshotShippingStatus 341 type SnapshotShippingStatus struct { 342 Snapshot Snapshot `json:"snapshot,omitempty"` 343 FromNodeName string `json:"from_node_name,omitempty"` 344 ToNodeName string `json:"to_node_name,omitempty"` 345 Status snapshotshipstatus.SnapshotShipStatus `json:"status,omitempty"` 346 } 347 348 // SnapshotVolumeDefinition is a struct to store the properties of a volume from a snapshot 349 type SnapshotVolumeDefinition struct { 350 VolumeNumber int32 `json:"volume_number,omitempty"` 351 // Volume size in KiB 352 SizeKib uint64 `json:"size_kib,omitempty"` 353 } 354 355 // SnapshotRestore is a struct used to hold the information about where a Snapshot has to be restored 356 type SnapshotRestore struct { 357 // Resource where to restore the snapshot 358 ToResource string `json:"to_resource"` 359 // List of nodes where to place the restored snapshot 360 Nodes []string `json:"nodes,omitempty"` 361 } 362 363 type DrbdProxyModify struct { 364 // Compression type used by the proxy. 365 CompressionType string `json:"compression_type,omitempty"` 366 // A string to string property map. 367 CompressionProps map[string]string `json:"compression_props,omitempty"` 368 GenericPropsModify 369 } 370 371 // Candidate struct for Candidate 372 type Candidate struct { 373 StoragePool string `json:"storage_pool,omitempty"` 374 // maximum size in KiB 375 MaxVolumeSizeKib int64 `json:"max_volume_size_kib,omitempty"` 376 NodeNames []string `json:"node_names,omitempty"` 377 AllThin bool `json:"all_thin,omitempty"` 378 } 379 380 // MaxVolumeSizes struct for MaxVolumeSizes 381 type MaxVolumeSizes struct { 382 Candidates []Candidate `json:"candidates,omitempty"` 383 DefaultMaxOversubscriptionRatio float64 `json:"default_max_oversubscription_ratio,omitempty"` 384 } 385 386 type ResourceMakeAvailable struct { 387 LayerList []devicelayerkind.DeviceLayerKind `json:"layer_list,omitempty"` 388 // if true resource will be created as diskful even if diskless would be possible 389 Diskful bool `json:"diskful,omitempty"` 390 } 391 392 type ToggleDiskDiskfulProps struct { 393 LayerList []devicelayerkind.DeviceLayerKind `json:"layer_list,omitempty"` 394 } 395 396 // custom code 397 398 // ResourceProvider acts as an abstraction for an ResourceService. It can be 399 // swapped out for another ResourceService implementation, for example for 400 // testing. 401 type ResourceProvider interface { 402 // GetResourceView returns all resources in the cluster. Filters can be set via ListOpts. 403 GetResourceView(ctx context.Context, opts ...*ListOpts) ([]ResourceWithVolumes, error) 404 // GetAll returns all resources for a resource-definition 405 GetAll(ctx context.Context, resName string, opts ...*ListOpts) ([]Resource, error) 406 // Get returns information about a resource on a specific node 407 Get(ctx context.Context, resName, nodeName string, opts ...*ListOpts) (Resource, error) 408 // Create is used to create a resource on a node 409 Create(ctx context.Context, res ResourceCreate) error 410 // Modify gives the ability to modify a resource on a node 411 Modify(ctx context.Context, resName, nodeName string, props GenericPropsModify) error 412 // Delete deletes a resource on a specific node 413 Delete(ctx context.Context, resName, nodeName string) error 414 // GetVolumes lists als volumes of a resource 415 GetVolumes(ctx context.Context, resName, nodeName string, opts ...*ListOpts) ([]Volume, error) 416 // GetVolume returns information about a specific volume defined by it resource,node and volume-number 417 GetVolume(ctx context.Context, resName, nodeName string, volNr int, opts ...*ListOpts) (Volume, error) 418 // ModifyVolume modifies an existing volume with the given props 419 ModifyVolume(ctx context.Context, resName, nodeName string, volNr int, props GenericPropsModify) error 420 // Diskless toggles a resource on a node to diskless - the parameter disklesspool can be set if its needed 421 Diskless(ctx context.Context, resName, nodeName, disklessPoolName string) error 422 // Diskful toggles a resource to diskful - the parameter storagepool can be set if its needed 423 Diskful(ctx context.Context, resName, nodeName, storagePoolName string, props *ToggleDiskDiskfulProps) error 424 // Migrate mirgates a resource from one node to another node 425 Migrate(ctx context.Context, resName, fromNodeName, toNodeName, storagePoolName string) error 426 // Autoplace places a resource on your nodes autmatically 427 Autoplace(ctx context.Context, resName string, apr AutoPlaceRequest) error 428 // GetConnections lists all resource connections if no node-names are given- if two node-names are given it shows the connection between them 429 GetConnections(ctx context.Context, resName, nodeAName, nodeBName string, opts ...*ListOpts) ([]ResourceConnection, error) 430 // ModifyConnection allows to modify the connection between two nodes 431 ModifyConnection(ctx context.Context, resName, nodeAName, nodeBName string, props GenericPropsModify) error 432 // GetSnapshots lists all snapshots of a resource 433 GetSnapshots(ctx context.Context, resName string, opts ...*ListOpts) ([]Snapshot, error) 434 // GetSnapshotView gets information about all snapshots 435 GetSnapshotView(ctx context.Context, opts ...*ListOpts) ([]Snapshot, error) 436 // GetSnapshot returns information about a specific Snapshot by its name 437 GetSnapshot(ctx context.Context, resName, snapName string, opts ...*ListOpts) (Snapshot, error) 438 // CreateSnapshot creates a snapshot of a resource 439 CreateSnapshot(ctx context.Context, snapshot Snapshot) error 440 // DeleteSnapshot deletes a snapshot by its name. Specify nodes to only delete snapshots on specific nodes. 441 DeleteSnapshot(ctx context.Context, resName, snapName string, nodes ...string) error 442 // RestoreSnapshot restores a snapshot on a resource 443 RestoreSnapshot(ctx context.Context, origResName, snapName string, snapRestoreConf SnapshotRestore) error 444 // RestoreVolumeDefinitionSnapshot restores a volume-definition-snapshot on a resource 445 RestoreVolumeDefinitionSnapshot(ctx context.Context, origResName, snapName string, snapRestoreConf SnapshotRestore) error 446 // RollbackSnapshot rolls back a snapshot from a specific resource 447 RollbackSnapshot(ctx context.Context, resName, snapName string) error 448 // EnableSnapshotShipping enables snapshot shipping for a resource 449 EnableSnapshotShipping(ctx context.Context, resName string, ship SnapshotShipping) error 450 // ModifyDRBDProxy is used to modify drbd-proxy properties 451 ModifyDRBDProxy(ctx context.Context, resName string, props DrbdProxyModify) error 452 // EnableDRBDProxy is used to enable drbd-proxy with the rest-api call from the function enableDisableDRBDProxy 453 EnableDRBDProxy(ctx context.Context, resName, nodeAName, nodeBName string) error 454 // DisableDRBDProxy is used to disable drbd-proxy with the rest-api call from the function enableDisableDRBDProxy 455 DisableDRBDProxy(ctx context.Context, resName, nodeAName, nodeBName string) error 456 // QueryMaxVolumeSize finds the maximum size of a volume for a given filter 457 QueryMaxVolumeSize(ctx context.Context, filter AutoSelectFilter) (MaxVolumeSizes, error) 458 // GetSnapshotShippings gets a view of all snapshot shippings 459 GetSnapshotShippings(ctx context.Context, opts ...*ListOpts) ([]SnapshotShippingStatus, error) 460 // GetPropsInfos gets meta information about the properties that can be 461 // set on a resource. 462 GetPropsInfos(ctx context.Context, resName string, opts ...*ListOpts) ([]PropsInfo, error) 463 // GetVolumeDefinitionPropsInfos gets meta information about the 464 // properties that can be set on a volume definition. 465 GetVolumeDefinitionPropsInfos(ctx context.Context, resName string, opts ...*ListOpts) ([]PropsInfo, error) 466 // GetVolumePropsInfos gets meta information about the properties that 467 // can be set on a volume. 468 GetVolumePropsInfos(ctx context.Context, resName, nodeName string, opts ...*ListOpts) ([]PropsInfo, error) 469 // GetConnectionPropsInfos gets meta information about the properties 470 // that can be set on a connection. 471 GetConnectionPropsInfos(ctx context.Context, resName string, opts ...*ListOpts) ([]PropsInfo, error) 472 // Activate starts an inactive resource on a given node. 473 Activate(ctx context.Context, resName string, nodeName string) error 474 // Deactivate stops an active resource on given node. 475 Deactivate(ctx context.Context, resName string, nodeName string) error 476 // MakeAvailable adds a resource on a node if not already deployed. 477 // To use a specific storage pool add the StorPoolName property and use 478 // the storage pool name as value. If the StorPoolName property is not 479 // set, a storage pool will be chosen automatically using the 480 // auto-placer. 481 // To create a diskless resource you have to set the "DISKLESS" flag in 482 // the flags list. 483 MakeAvailable(ctx context.Context, resName, nodeName string, makeAvailable ResourceMakeAvailable) error 484 } 485 486 var _ ResourceProvider = &ResourceService{} 487 488 // volumeLayerIn is a struct for volume-layers 489 type volumeLayerIn struct { 490 Type devicelayerkind.DeviceLayerKind `json:"type,omitempty"` 491 Data json.RawMessage `json:"data,omitempty"` 492 } 493 494 // UnmarshalJSON fulfills the unmarshal interface for the VolumeLayer type 495 func (v *VolumeLayer) UnmarshalJSON(b []byte) error { 496 var vIn volumeLayerIn 497 if err := json.Unmarshal(b, &vIn); err != nil { 498 return err 499 } 500 501 v.Type = vIn.Type 502 switch v.Type { 503 case devicelayerkind.Drbd: 504 dst := new(DrbdVolume) 505 if vIn.Data != nil { 506 if err := json.Unmarshal(vIn.Data, &dst); err != nil { 507 return err 508 } 509 } 510 v.Data = dst 511 case devicelayerkind.Luks: 512 dst := new(LuksVolume) 513 if vIn.Data != nil { 514 if err := json.Unmarshal(vIn.Data, &dst); err != nil { 515 return err 516 } 517 } 518 v.Data = dst 519 case devicelayerkind.Storage: 520 dst := new(StorageVolume) 521 if vIn.Data != nil { 522 if err := json.Unmarshal(vIn.Data, &dst); err != nil { 523 return err 524 } 525 } 526 v.Data = dst 527 case devicelayerkind.Nvme: 528 dst := new(NvmeVolume) 529 if vIn.Data != nil { 530 if err := json.Unmarshal(vIn.Data, &dst); err != nil { 531 return err 532 } 533 } 534 v.Data = dst 535 case devicelayerkind.Writecache: 536 dst := new(WritecacheVolume) 537 if vIn.Data != nil { 538 if err := json.Unmarshal(vIn.Data, &dst); err != nil { 539 return err 540 } 541 } 542 v.Data = dst 543 case devicelayerkind.Cache: 544 case devicelayerkind.Exos: 545 default: 546 return fmt.Errorf("'%+v' is not a valid type to Unmarshal", v.Type) 547 } 548 549 return nil 550 } 551 552 // OneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolume is used to prevent that other types than drbd- luks- and storage-volume are used for a VolumeLayer 553 type OneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume interface { 554 isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() 555 } 556 557 // Functions which are used if type is a correct VolumeLayer 558 func (d *DrbdVolume) isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() { 559 } 560 func (d *LuksVolume) isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() { 561 } 562 func (d *StorageVolume) isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() { 563 } 564 func (d *NvmeVolume) isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() { 565 } 566 func (d *WritecacheVolume) isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() { 567 } 568 func (d *CacheVolume) isOneOfDrbdVolumeLuksVolumeStorageVolumeNvmeVolumeWritecacheVolumeCacheVolumeBCacheVolume() { 569 } 570 571 // GetResourceView returns all resources in the cluster. Filters can be set via ListOpts. 572 func (n *ResourceService) GetResourceView(ctx context.Context, opts ...*ListOpts) ([]ResourceWithVolumes, error) { 573 var reses []ResourceWithVolumes 574 _, err := n.client.doGET(ctx, "/v1/view/resources", &reses, opts...) 575 return reses, err 576 } 577 578 // GetAll returns all resources for a resource-definition 579 func (n *ResourceService) GetAll(ctx context.Context, resName string, opts ...*ListOpts) ([]Resource, error) { 580 var reses []Resource 581 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resources", &reses, opts...) 582 return reses, err 583 } 584 585 // Get returns information about a resource on a specific node 586 func (n *ResourceService) Get(ctx context.Context, resName, nodeName string, opts ...*ListOpts) (Resource, error) { 587 var res Resource 588 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName, &res, opts...) 589 return res, err 590 } 591 592 // Create is used to create a resource on a node 593 func (n *ResourceService) Create(ctx context.Context, res ResourceCreate) error { 594 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+res.Resource.Name+"/resources/"+res.Resource.NodeName, res) 595 return err 596 } 597 598 // Modify gives the ability to modify a resource on a node 599 func (n *ResourceService) Modify(ctx context.Context, resName, nodeName string, props GenericPropsModify) error { 600 _, err := n.client.doPUT(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName, props) 601 return err 602 } 603 604 // Delete deletes a resource on a specific node 605 func (n *ResourceService) Delete(ctx context.Context, resName, nodeName string) error { 606 _, err := n.client.doDELETE(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName, nil) 607 return err 608 } 609 610 func (n *ResourceService) Activate(ctx context.Context, resName, nodeName string) error { 611 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName+"/activate", nil) 612 return err 613 } 614 615 func (n *ResourceService) Deactivate(ctx context.Context, resName, nodeName string) error { 616 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName+"/deactivate", nil) 617 return err 618 } 619 620 // GetVolumes lists als volumes of a resource 621 func (n *ResourceService) GetVolumes(ctx context.Context, resName, nodeName string, opts ...*ListOpts) ([]Volume, error) { 622 var vols []Volume 623 624 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName+"/volumes", &vols, opts...) 625 return vols, err 626 } 627 628 // GetVolume returns information about a specific volume defined by it resource,node and volume-number 629 func (n *ResourceService) GetVolume(ctx context.Context, resName, nodeName string, volNr int, opts ...*ListOpts) (Volume, error) { 630 var vol Volume 631 632 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName+"/volumes/"+strconv.Itoa(volNr), &vol, opts...) 633 return vol, err 634 } 635 636 // ModifyVolume modifies an existing volume with the given props 637 func (n *ResourceService) ModifyVolume(ctx context.Context, resName, nodeName string, volNr int, props GenericPropsModify) error { 638 u := fmt.Sprintf("/v1/resource-definitions/%s/resources/%s/volumes/%d", resName, nodeName, volNr) 639 _, err := n.client.doPUT(ctx, u, props) 640 return err 641 } 642 643 // Diskless toggles a resource on a node to diskless - the parameter disklesspool can be set if its needed 644 func (n *ResourceService) Diskless(ctx context.Context, resName, nodeName, disklessPoolName string) error { 645 u := "/v1/resource-definitions/" + resName + "/resources/" + nodeName + "/toggle-disk/diskless" 646 if disklessPoolName != "" { 647 u += "/" + disklessPoolName 648 } 649 650 _, err := n.client.doPUT(ctx, u, nil) 651 return err 652 } 653 654 // Diskful toggles a resource to diskful - the parameter storagepool can be set if its needed 655 func (n *ResourceService) Diskful(ctx context.Context, resName, nodeName, storagePoolName string, props *ToggleDiskDiskfulProps) error { 656 u := "/v1/resource-definitions/" + resName + "/resources/" + nodeName + "/toggle-disk/diskful" 657 if storagePoolName != "" { 658 u += "/" + storagePoolName 659 } 660 _, err := n.client.doPUT(ctx, u, props) 661 return err 662 } 663 664 // Migrate mirgates a resource from one node to another node 665 func (n *ResourceService) Migrate(ctx context.Context, resName, fromNodeName, toNodeName, storagePoolName string) error { 666 u := "/v1/resource-definitions/" + resName + "/resources/" + toNodeName + "/migrate-disk/" + fromNodeName 667 if storagePoolName != "" { 668 u += "/" + storagePoolName 669 } 670 _, err := n.client.doPUT(ctx, u, nil) 671 return err 672 } 673 674 // Autoplace places a resource on your nodes autmatically 675 func (n *ResourceService) Autoplace(ctx context.Context, resName string, apr AutoPlaceRequest) error { 676 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resName+"/autoplace", apr) 677 return err 678 } 679 680 // GetConnections lists all resource connections if no node-names are given- if two node-names are given it shows the connection between them 681 func (n *ResourceService) GetConnections(ctx context.Context, resName, nodeAName, nodeBName string, opts ...*ListOpts) ([]ResourceConnection, error) { 682 var resConns []ResourceConnection 683 684 u := "/v1/resource-definitions/" + resName + "/resources-connections" 685 if nodeAName != "" && nodeBName != "" { 686 u += fmt.Sprintf("/%s/%s", nodeAName, nodeBName) 687 } 688 689 _, err := n.client.doGET(ctx, u, &resConns, opts...) 690 return resConns, err 691 } 692 693 // ModifyConnection allows to modify the connection between two nodes 694 func (n *ResourceService) ModifyConnection(ctx context.Context, resName, nodeAName, nodeBName string, props GenericPropsModify) error { 695 u := fmt.Sprintf("/v1/resource-definitions/%s/resource-connections/%s/%s", resName, nodeAName, nodeBName) 696 _, err := n.client.doPUT(ctx, u, props) 697 return err 698 } 699 700 // GetSnapshots lists all snapshots of a resource 701 func (n *ResourceService) GetSnapshots(ctx context.Context, resName string, opts ...*ListOpts) ([]Snapshot, error) { 702 var snaps []Snapshot 703 704 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/snapshots", &snaps, opts...) 705 return snaps, err 706 } 707 708 // GetSnapshotView gets information about all snapshots 709 func (r *ResourceService) GetSnapshotView(ctx context.Context, opts ...*ListOpts) ([]Snapshot, error) { 710 var snaps []Snapshot 711 _, err := r.client.doGET(ctx, "/v1/view/snapshots", &snaps, opts...) 712 return snaps, err 713 } 714 715 // GetSnapshot returns information about a specific Snapshot by its name 716 func (n *ResourceService) GetSnapshot(ctx context.Context, resName, snapName string, opts ...*ListOpts) (Snapshot, error) { 717 var snap Snapshot 718 719 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/snapshots/"+snapName, &snap, opts...) 720 return snap, err 721 } 722 723 // CreateSnapshot creates a snapshot of a resource 724 func (n *ResourceService) CreateSnapshot(ctx context.Context, snapshot Snapshot) error { 725 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+snapshot.ResourceName+"/snapshots", snapshot) 726 return err 727 } 728 729 // DeleteSnapshot deletes a snapshot by its name. Specify nodes to only delete snapshots on specific nodes. 730 func (n *ResourceService) DeleteSnapshot(ctx context.Context, resName, snapName string, nodes ...string) error { 731 vals, err := query.Values(struct { 732 Nodes []string `url:"nodes"` 733 }{Nodes: nodes}) 734 if err != nil { 735 return fmt.Errorf("failed to encode node names: %w", err) 736 } 737 738 _, err = n.client.doDELETE(ctx, "/v1/resource-definitions/"+resName+"/snapshots/"+snapName+"?"+vals.Encode(), nil) 739 return err 740 } 741 742 // RestoreSnapshot restores a snapshot on a resource 743 func (n *ResourceService) RestoreSnapshot(ctx context.Context, origResName, snapName string, snapRestoreConf SnapshotRestore) error { 744 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+origResName+"/snapshot-restore-resource/"+snapName, snapRestoreConf) 745 return err 746 } 747 748 // RestoreVolumeDefinitionSnapshot restores a volume-definition-snapshot on a resource 749 func (n *ResourceService) RestoreVolumeDefinitionSnapshot(ctx context.Context, origResName, snapName string, snapRestoreConf SnapshotRestore) error { 750 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+origResName+"/snapshot-restore-volume-definition/"+snapName, snapRestoreConf) 751 return err 752 } 753 754 // RollbackSnapshot rolls back a snapshot from a specific resource 755 func (n *ResourceService) RollbackSnapshot(ctx context.Context, resName, snapName string) error { 756 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resName+"/snapshot-rollback/"+snapName, nil) 757 return err 758 } 759 760 // EnableSnapshotShipping enables snapshot shipping for a resource 761 func (n *ResourceService) EnableSnapshotShipping(ctx context.Context, resName string, ship SnapshotShipping) error { 762 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resName+"/snapshot-shipping", ship) 763 return err 764 } 765 766 // ModifyDRBDProxy is used to modify drbd-proxy properties 767 func (n *ResourceService) ModifyDRBDProxy(ctx context.Context, resName string, props DrbdProxyModify) error { 768 _, err := n.client.doPUT(ctx, "/v1/resource-definitions/"+resName+"/drbd-proxy", props) 769 return err 770 } 771 772 // enableDisableDRBDProxy enables or disables drbd-proxy between two nodes 773 func (n *ResourceService) enableDisableDRBDProxy(ctx context.Context, what, resName, nodeAName, nodeBName string) error { 774 u := fmt.Sprintf("/v1/resource-definitions/%s/drbd-proxy/%s/%s/%s", resName, what, nodeAName, nodeBName) 775 _, err := n.client.doPOST(ctx, u, nil) 776 return err 777 } 778 779 // EnableDRBDProxy is used to enable drbd-proxy with the rest-api call from the function enableDisableDRBDProxy 780 func (n *ResourceService) EnableDRBDProxy(ctx context.Context, resName, nodeAName, nodeBName string) error { 781 return n.enableDisableDRBDProxy(ctx, "enable", resName, nodeAName, nodeBName) 782 } 783 784 // DisableDRBDProxy is used to disable drbd-proxy with the rest-api call from the function enableDisableDRBDProxy 785 func (n *ResourceService) DisableDRBDProxy(ctx context.Context, resName, nodeAName, nodeBName string) error { 786 return n.enableDisableDRBDProxy(ctx, "disable", resName, nodeAName, nodeBName) 787 } 788 789 // QueryMaxVolumeSize finds the maximum size of a volume for a given filter 790 func (n *ResourceService) QueryMaxVolumeSize(ctx context.Context, filter AutoSelectFilter) (MaxVolumeSizes, error) { 791 var sizes MaxVolumeSizes 792 _, err := n.client.doOPTIONS(ctx, "/v1/query-max-volume-size", &sizes, filter) 793 return sizes, err 794 } 795 796 // GetSnapshotShippings gets a view of all snapshot shippings 797 func (n *ResourceService) GetSnapshotShippings(ctx context.Context, opts ...*ListOpts) ([]SnapshotShippingStatus, error) { 798 var shippings []SnapshotShippingStatus 799 _, err := n.client.doGET(ctx, "/v1/view/snapshot-shippings", &shippings, opts...) 800 return shippings, err 801 } 802 803 // GetPropsInfos gets meta information about the properties that can be set on 804 // a resource. 805 func (n *ResourceService) GetPropsInfos(ctx context.Context, resName string, opts ...*ListOpts) ([]PropsInfo, error) { 806 var infos []PropsInfo 807 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resources/properties/info", &infos, opts...) 808 return infos, err 809 } 810 811 // GetVolumeDefinitionPropsInfos gets meta information about the properties 812 // that can be set on a volume definition. 813 func (n *ResourceService) GetVolumeDefinitionPropsInfos(ctx context.Context, resName string, opts ...*ListOpts) ([]PropsInfo, error) { 814 var infos []PropsInfo 815 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/volume-definitions/properties/info", &infos, opts...) 816 return infos, err 817 } 818 819 // GetVolumePropsInfos gets meta information about the properties that can be 820 // set on a volume. 821 func (n *ResourceService) GetVolumePropsInfos(ctx context.Context, resName, nodeName string, opts ...*ListOpts) ([]PropsInfo, error) { 822 var infos []PropsInfo 823 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resources/"+nodeName+"/volumes/properties/info", &infos, opts...) 824 return infos, err 825 } 826 827 // GetConnectionPropsInfos gets meta information about the properties that can 828 // be set on a connection. 829 func (n *ResourceService) GetConnectionPropsInfos(ctx context.Context, resName string, opts ...*ListOpts) ([]PropsInfo, error) { 830 var infos []PropsInfo 831 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resName+"/resource-connections/properties/info", &infos, opts...) 832 return infos, err 833 } 834 835 // MakeAvailable adds a resource on a node if not already deployed. 836 // To use a specific storage pool add the StorPoolName property and use the 837 // storage pool name as value. If the StorPoolName property is not set, a 838 // storage pool will be chosen automatically using the auto-placer. 839 // To create a diskless resource you have to set the "DISKLESS" flag in the 840 // flags list. 841 func (n *ResourceService) MakeAvailable(ctx context.Context, resName, nodeName string, makeAvailable ResourceMakeAvailable) error { 842 u := fmt.Sprintf("/v1/resource-definitions/%s/resources/%s/make-available", 843 resName, nodeName) 844 _, err := n.client.doPOST(ctx, u, makeAvailable) 845 return err 846 }