1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package client
19
20 import (
21 "context"
22 "encoding/json"
23 "fmt"
24 "net/url"
25 "strconv"
26
27 "github.com/google/go-querystring/query"
28
29 "github.com/LINBIT/golinstor/clonestatus"
30 "github.com/LINBIT/golinstor/devicelayerkind"
31 )
32
33
34 type ResourceDefinitionService struct {
35 client *Client
36 }
37
38
39 type ResourceDefinition struct {
40 Name string `json:"name,omitempty"`
41
42 ExternalName string `json:"external_name,omitempty"`
43
44 Props map[string]string `json:"props,omitempty"`
45 Flags []string `json:"flags,omitempty"`
46 LayerData []ResourceDefinitionLayer `json:"layer_data,omitempty"`
47
48 Uuid string `json:"uuid,omitempty"`
49
50 ResourceGroupName string `json:"resource_group_name,omitempty"`
51 }
52
53
54 type ResourceDefinitionCreate struct {
55
56 DrbdPort int32 `json:"drbd_port,omitempty"`
57
58 DrbdSecret string `json:"drbd_secret,omitempty"`
59 DrbdTransportType string `json:"drbd_transport_type,omitempty"`
60 ResourceDefinition ResourceDefinition `json:"resource_definition"`
61 }
62
63
64 type ResourceDefinitionLayer struct {
65 Type devicelayerkind.DeviceLayerKind `json:"type,omitempty"`
66 Data *DrbdResourceDefinitionLayer `json:"data,omitempty"`
67 }
68
69
70 type DrbdResourceDefinitionLayer struct {
71 ResourceNameSuffix string `json:"resource_name_suffix,omitempty"`
72 PeerSlots int32 `json:"peer_slots,omitempty"`
73 AlStripes int64 `json:"al_stripes,omitempty"`
74
75 Port int32 `json:"port,omitempty"`
76 TransportType string `json:"transport_type,omitempty"`
77
78 Secret string `json:"secret,omitempty"`
79 Down bool `json:"down,omitempty"`
80 }
81
82
83 type VolumeDefinitionCreate struct {
84 VolumeDefinition VolumeDefinition `json:"volume_definition"`
85 DrbdMinorNumber int32 `json:"drbd_minor_number,omitempty"`
86 }
87
88
89 type VolumeDefinition struct {
90 VolumeNumber *int32 `json:"volume_number,omitempty"`
91
92 SizeKib uint64 `json:"size_kib"`
93
94 Props map[string]string `json:"props,omitempty"`
95 Flags []string `json:"flags,omitempty"`
96 LayerData []VolumeDefinitionLayer `json:"layer_data,omitempty"`
97
98 Uuid string `json:"uuid,omitempty"`
99 }
100
101 type VolumeDefinitionModify struct {
102 SizeKib uint64 `json:"size_kib,omitempty"`
103 GenericPropsModify
104
105 Flags []string `json:"flags,omitempty"`
106 }
107
108
109 type VolumeDefinitionLayer struct {
110 Type devicelayerkind.DeviceLayerKind `json:"type"`
111 Data OneOfDrbdVolumeDefinition `json:"data,omitempty"`
112 }
113
114
115 type DrbdVolumeDefinition struct {
116 ResourceNameSuffix string `json:"resource_name_suffix,omitempty"`
117 VolumeNumber int32 `json:"volume_number,omitempty"`
118 MinorNumber int32 `json:"minor_number,omitempty"`
119 }
120
121 type ResourceDefinitionCloneRequest struct {
122 Name string `json:"name,omitempty"`
123 ExternalName string `json:"external_name,omitempty"`
124 }
125
126 type ResourceDefinitionCloneStarted struct {
127
128 Location string `json:"location"`
129
130 SourceName string `json:"source_name"`
131
132 CloneName string `json:"clone_name"`
133 Messages *[]ApiCallRc `json:"messages,omitempty"`
134 }
135
136 type ResourceDefinitionCloneStatus struct {
137 Status clonestatus.CloneStatus `json:"status"`
138 }
139
140 type ResourceDefinitionSyncStatus struct {
141 SyncedOnAll bool `json:"synced_on_all"`
142 }
143
144
145
146 type ResourceDefinitionWithVolumeDefinition struct {
147 ResourceDefinition
148 VolumeDefinitions []VolumeDefinition `json:"volume_definitions,omitempty"`
149 }
150
151 type RDGetAllRequest struct {
152
153 ResourceDefinitions []string `url:"resource_definitions,omitempty"`
154
155 Props []string `url:"props,omitempty"`
156 Offset int `url:"offset,omitempty"`
157 Limit int `url:"offset,omitempty"`
158
159 WithVolumeDefinitions bool `url:"with_volume_definitions,omitempty"`
160 }
161
162
163
164
165 type ResourceDefinitionProvider interface {
166
167 GetAll(ctx context.Context, request RDGetAllRequest) ([]ResourceDefinitionWithVolumeDefinition, error)
168
169 Get(ctx context.Context, resDefName string, opts ...*ListOpts) (ResourceDefinition, error)
170
171 Create(ctx context.Context, resDef ResourceDefinitionCreate) error
172
173 Modify(ctx context.Context, resDefName string, props GenericPropsModify) error
174
175 Delete(ctx context.Context, resDefName string) error
176
177 GetVolumeDefinitions(ctx context.Context, resDefName string, opts ...*ListOpts) ([]VolumeDefinition, error)
178
179 GetVolumeDefinition(ctx context.Context, resDefName string, volNr int, opts ...*ListOpts) (VolumeDefinition, error)
180
181 CreateVolumeDefinition(ctx context.Context, resDefName string, volDef VolumeDefinitionCreate) error
182
183 ModifyVolumeDefinition(ctx context.Context, resDefName string, volNr int, props VolumeDefinitionModify) error
184
185 DeleteVolumeDefinition(ctx context.Context, resDefName string, volNr int) error
186
187
188 GetPropsInfos(ctx context.Context, opts ...*ListOpts) ([]PropsInfo, error)
189
190
191 GetDRBDProxyPropsInfos(ctx context.Context, resDefName string, opts ...*ListOpts) ([]PropsInfo, error)
192
193
194 AttachExternalFile(ctx context.Context, resDefName string, filePath string) error
195
196
197
198 DetachExternalFile(ctx context.Context, resDefName string, filePath string) error
199
200 Clone(ctx context.Context, srcResDef string, request ResourceDefinitionCloneRequest) (ResourceDefinitionCloneStarted, error)
201
202 CloneStatus(ctx context.Context, srcResDef, targetResDef string) (ResourceDefinitionCloneStatus, error)
203
204 SyncStatus(ctx context.Context, resDef string) (ResourceDefinitionSyncStatus, error)
205 }
206
207 var _ ResourceDefinitionProvider = &ResourceDefinitionService{}
208
209
210 type resourceDefinitionLayerIn struct {
211 Type devicelayerkind.DeviceLayerKind `json:"type,omitempty"`
212 Data json.RawMessage `json:"data,omitempty"`
213 }
214
215
216 func (rd *ResourceDefinitionLayer) UnmarshalJSON(b []byte) error {
217 var rdIn resourceDefinitionLayerIn
218 if err := json.Unmarshal(b, &rdIn); err != nil {
219 return err
220 }
221
222 rd.Type = rdIn.Type
223 switch rd.Type {
224 case devicelayerkind.Drbd:
225 dst := new(DrbdResourceDefinitionLayer)
226 if rdIn.Data != nil {
227 if err := json.Unmarshal(rdIn.Data, &dst); err != nil {
228 return err
229 }
230 }
231 rd.Data = dst
232 case devicelayerkind.Luks, devicelayerkind.Storage, devicelayerkind.Nvme, devicelayerkind.Writecache, devicelayerkind.Cache, devicelayerkind.Exos:
233 default:
234 return fmt.Errorf("'%+v' is not a valid type to Unmarshal", rd.Type)
235 }
236
237 return nil
238 }
239
240
241 type volumeDefinitionLayerIn struct {
242 Type devicelayerkind.DeviceLayerKind `json:"type,omitempty"`
243 Data json.RawMessage `json:"data,omitempty"`
244 }
245
246
247 func (vd *VolumeDefinitionLayer) UnmarshalJSON(b []byte) error {
248 var vdIn volumeDefinitionLayerIn
249 if err := json.Unmarshal(b, &vdIn); err != nil {
250 return err
251 }
252
253 vd.Type = vdIn.Type
254 switch vd.Type {
255 case devicelayerkind.Drbd:
256 dst := new(DrbdVolumeDefinition)
257 if vdIn.Data != nil {
258 if err := json.Unmarshal(vdIn.Data, &dst); err != nil {
259 return err
260 }
261 }
262 vd.Data = dst
263 case devicelayerkind.Luks, devicelayerkind.Storage, devicelayerkind.Nvme, devicelayerkind.Writecache, devicelayerkind.Cache, devicelayerkind.Exos:
264 default:
265 return fmt.Errorf("'%+v' is not a valid type to Unmarshal", vd.Type)
266 }
267
268 return nil
269 }
270
271
272 type OneOfDrbdVolumeDefinition interface {
273 isOneOfDrbdVolumeDefinition()
274 }
275
276
277 func (d *DrbdVolumeDefinition) isOneOfDrbdVolumeDefinition() {}
278
279
280 func (n *ResourceDefinitionService) GetAll(ctx context.Context, request RDGetAllRequest) ([]ResourceDefinitionWithVolumeDefinition, error) {
281 val, err := query.Values(request)
282 if err != nil {
283 return nil, err
284 }
285
286 var resDefs []ResourceDefinitionWithVolumeDefinition
287 _, err = n.client.doGET(ctx, "/v1/resource-definitions?"+val.Encode(), &resDefs)
288 return resDefs, err
289 }
290
291
292 func (n *ResourceDefinitionService) Get(ctx context.Context, resDefName string, opts ...*ListOpts) (ResourceDefinition, error) {
293 var resDef ResourceDefinition
294 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resDefName, &resDef, opts...)
295 return resDef, err
296 }
297
298
299 func (n *ResourceDefinitionService) Create(ctx context.Context, resDef ResourceDefinitionCreate) error {
300 _, err := n.client.doPOST(ctx, "/v1/resource-definitions", resDef)
301 return err
302 }
303
304
305 func (n *ResourceDefinitionService) Modify(ctx context.Context, resDefName string, props GenericPropsModify) error {
306 _, err := n.client.doPUT(ctx, "/v1/resource-definitions/"+resDefName, props)
307 return err
308 }
309
310
311 func (n *ResourceDefinitionService) Delete(ctx context.Context, resDefName string) error {
312 _, err := n.client.doDELETE(ctx, "/v1/resource-definitions/"+resDefName, nil)
313 return err
314 }
315
316
317 func (n *ResourceDefinitionService) GetVolumeDefinitions(ctx context.Context, resDefName string, opts ...*ListOpts) ([]VolumeDefinition, error) {
318 var volDefs []VolumeDefinition
319 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resDefName+"/volume-definitions", &volDefs, opts...)
320 return volDefs, err
321 }
322
323
324 func (n *ResourceDefinitionService) GetVolumeDefinition(ctx context.Context, resDefName string, volNr int, opts ...*ListOpts) (VolumeDefinition, error) {
325 var volDef VolumeDefinition
326 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resDefName+"/volume-definitions/"+strconv.Itoa(volNr), &volDef, opts...)
327 return volDef, err
328 }
329
330
331 func (n *ResourceDefinitionService) CreateVolumeDefinition(ctx context.Context, resDefName string, volDef VolumeDefinitionCreate) error {
332 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resDefName+"/volume-definitions", volDef)
333 return err
334 }
335
336
337 func (n *ResourceDefinitionService) ModifyVolumeDefinition(ctx context.Context, resDefName string, volNr int, props VolumeDefinitionModify) error {
338 _, err := n.client.doPUT(ctx, "/v1/resource-definitions/"+resDefName+"/volume-definitions/"+strconv.Itoa(volNr), props)
339 return err
340 }
341
342
343 func (n *ResourceDefinitionService) DeleteVolumeDefinition(ctx context.Context, resDefName string, volNr int) error {
344 _, err := n.client.doDELETE(ctx, "/v1/resource-definitions/"+resDefName+"/volume-definitions/"+strconv.Itoa(volNr), nil)
345 return err
346 }
347
348
349
350 func (n *ResourceDefinitionService) GetPropsInfos(ctx context.Context, opts ...*ListOpts) ([]PropsInfo, error) {
351 var infos []PropsInfo
352 _, err := n.client.doGET(ctx, "/v1/resource-definitions/properties/info", &infos, opts...)
353 return infos, err
354 }
355
356
357
358 func (n *ResourceDefinitionService) GetDRBDProxyPropsInfos(ctx context.Context, resDefName string, opts ...*ListOpts) ([]PropsInfo, error) {
359 var infos []PropsInfo
360 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resDefName+"/drbd-proxy/properties/info", &infos, opts...)
361 return infos, err
362 }
363
364
365
366 func (n *ResourceDefinitionService) AttachExternalFile(ctx context.Context, resDefName string, filePath string) error {
367 _, err := n.client.doPOST(ctx, "/v1/resource-definitions/"+resDefName+"/files/"+url.QueryEscape(filePath), nil)
368 return err
369 }
370
371
372
373
374 func (n *ResourceDefinitionService) DetachExternalFile(ctx context.Context, resDefName string, filePath string) error {
375 _, err := n.client.doDELETE(ctx, "/v1/resource-definitions/"+resDefName+"/files/"+url.QueryEscape(filePath), nil)
376 return err
377 }
378
379
380 func (n *ResourceDefinitionService) Clone(ctx context.Context, srcResDef string, request ResourceDefinitionCloneRequest) (ResourceDefinitionCloneStarted, error) {
381 var resp ResourceDefinitionCloneStarted
382
383 req, err := n.client.newRequest("POST", "/v1/resource-definitions/"+srcResDef+"/clone", request)
384 if err != nil {
385 return ResourceDefinitionCloneStarted{}, err
386 }
387
388 _, err = n.client.do(ctx, req, &resp)
389 if err != nil {
390 return ResourceDefinitionCloneStarted{}, err
391 }
392
393 return resp, nil
394 }
395
396
397 func (n *ResourceDefinitionService) CloneStatus(ctx context.Context, srcResDef, targetResDef string) (ResourceDefinitionCloneStatus, error) {
398 var status ResourceDefinitionCloneStatus
399 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+srcResDef+"/clone/"+targetResDef, &status)
400 return status, err
401 }
402
403
404 func (n *ResourceDefinitionService) SyncStatus(ctx context.Context, resDef string) (ResourceDefinitionSyncStatus, error) {
405 var status ResourceDefinitionSyncStatus
406 _, err := n.client.doGET(ctx, "/v1/resource-definitions/"+resDef+"/sync-status", &status)
407 return status, err
408 }
409
View as plain text