~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/altoros/gosigma/clientimpl.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 ALTOROS
 
2
// Licensed under the AGPLv3, see LICENSE file for details.
 
3
 
 
4
package gosigma
 
5
 
 
6
import (
 
7
        "bufio"
 
8
        "bytes"
 
9
        "errors"
 
10
        "fmt"
 
11
        "io"
 
12
        "net/url"
 
13
        "os"
 
14
        "strings"
 
15
        "time"
 
16
 
 
17
        "github.com/altoros/gosigma/data"
 
18
)
 
19
 
 
20
func (c Client) getServers(rqspec RequestSpec) ([]data.Server, error) {
 
21
        u := c.endpoint + "servers"
 
22
        if rqspec == RequestDetail {
 
23
                u += "/detail"
 
24
        }
 
25
 
 
26
        r, err := c.https.Get(u, url.Values{"limit": {"0"}})
 
27
        if err != nil {
 
28
                return nil, err
 
29
        }
 
30
        defer r.Body.Close()
 
31
 
 
32
        if err := r.VerifyJSON(200); err != nil {
 
33
                return nil, NewError(r, err)
 
34
        }
 
35
 
 
36
        return data.ReadServers(r.Body)
 
37
}
 
38
 
 
39
func (c Client) getServer(uuid string) (*data.Server, error) {
 
40
        uuid = strings.TrimSpace(uuid)
 
41
        if uuid == "" {
 
42
                return nil, errEmptyUUID
 
43
        }
 
44
 
 
45
        u := c.endpoint + "servers/" + uuid + "/"
 
46
 
 
47
        r, err := c.https.Get(u, nil)
 
48
        if err != nil {
 
49
                return nil, err
 
50
        }
 
51
        defer r.Body.Close()
 
52
 
 
53
        if err := r.VerifyJSON(200); err != nil {
 
54
                return nil, NewError(r, err)
 
55
        }
 
56
 
 
57
        return data.ReadServer(r.Body)
 
58
}
 
59
 
 
60
func (c Client) startServer(uuid string, avoid []string) error {
 
61
        uuid = strings.TrimSpace(uuid)
 
62
        if uuid == "" {
 
63
                return errEmptyUUID
 
64
        }
 
65
 
 
66
        u := c.endpoint + "servers/" + uuid + "/action/"
 
67
 
 
68
        var qq = make(url.Values)
 
69
        qq["do"] = []string{"start"}
 
70
 
 
71
        if len(avoid) > 0 {
 
72
                qq["avoid"] = []string{strings.Join(avoid, ",")}
 
73
        }
 
74
 
 
75
        r, err := c.https.Post(u, qq, nil)
 
76
        if err != nil {
 
77
                return err
 
78
        }
 
79
        defer r.Body.Close()
 
80
 
 
81
        if err := r.VerifyJSON(202); err != nil {
 
82
                return NewError(r, err)
 
83
        }
 
84
 
 
85
        return nil
 
86
}
 
87
 
 
88
func (c Client) stopServer(uuid string) error {
 
89
        uuid = strings.TrimSpace(uuid)
 
90
        if uuid == "" {
 
91
                return errEmptyUUID
 
92
        }
 
93
 
 
94
        u := c.endpoint + "servers/" + uuid + "/action/"
 
95
 
 
96
        var qq = make(url.Values)
 
97
        qq["do"] = []string{"stop"}
 
98
 
 
99
        r, err := c.https.Post(u, qq, nil)
 
100
        if err != nil {
 
101
                return err
 
102
        }
 
103
        defer r.Body.Close()
 
104
 
 
105
        if err := r.VerifyJSON(202); err != nil {
 
106
                return NewError(r, err)
 
107
        }
 
108
 
 
109
        return nil
 
110
}
 
111
 
 
112
func (c Client) removeServer(uuid, recurse string) error {
 
113
        uuid = strings.TrimSpace(uuid)
 
114
        if uuid == "" {
 
115
                return errEmptyUUID
 
116
        }
 
117
 
 
118
        u := c.endpoint + "servers/" + uuid + "/"
 
119
 
 
120
        var qq url.Values
 
121
        recurse = strings.TrimSpace(recurse)
 
122
        if recurse != "" {
 
123
                qq = make(url.Values)
 
124
                qq["recurse"] = []string{recurse}
 
125
        }
 
126
 
 
127
        r, err := c.https.Delete(u, qq, nil)
 
128
        if err != nil {
 
129
                return err
 
130
        }
 
131
        defer r.Body.Close()
 
132
 
 
133
        if err := r.VerifyCode(204); err != nil {
 
134
                return NewError(r, err)
 
135
        }
 
136
 
 
137
        return nil
 
138
}
 
139
 
 
140
func (c Client) createServer(components Components) ([]data.Server, error) {
 
141
        // serialize
 
142
        rr, err := components.marshal()
 
143
        if err != nil {
 
144
                return nil, err
 
145
        }
 
146
 
 
147
        // run request
 
148
        u := c.endpoint + "servers/"
 
149
        r, err := c.https.Post(u, nil, rr)
 
150
        if err != nil {
 
151
                return nil, err
 
152
        }
 
153
        defer r.Body.Close()
 
154
 
 
155
        if err := r.VerifyJSON(201); err != nil {
 
156
                return nil, NewError(r, err)
 
157
        }
 
158
 
 
159
        return data.ReadServers(r.Body)
 
160
}
 
161
 
 
162
func (c Client) getDrives(rqspec RequestSpec, libspec LibrarySpec) ([]data.Drive, error) {
 
163
        u := c.endpoint
 
164
        if libspec == LibraryMedia {
 
165
                u += "libdrives"
 
166
        } else {
 
167
                u += "drives"
 
168
        }
 
169
        if rqspec == RequestDetail {
 
170
                u += "/detail"
 
171
        }
 
172
 
 
173
        r, err := c.https.Get(u, url.Values{"limit": {"0"}})
 
174
        if err != nil {
 
175
                return nil, err
 
176
        }
 
177
        defer r.Body.Close()
 
178
 
 
179
        if err := r.VerifyJSON(200); err != nil {
 
180
                return nil, NewError(r, err)
 
181
        }
 
182
 
 
183
        return data.ReadDrives(r.Body)
 
184
}
 
185
 
 
186
func (c Client) getDrive(uuid string, libspec LibrarySpec) (*data.Drive, error) {
 
187
        uuid = strings.TrimSpace(uuid)
 
188
        if uuid == "" {
 
189
                return nil, errEmptyUUID
 
190
        }
 
191
 
 
192
        u := c.endpoint
 
193
        if libspec == LibraryMedia {
 
194
                u += "libdrives/"
 
195
        } else {
 
196
                u += "drives/"
 
197
        }
 
198
        u += uuid + "/"
 
199
 
 
200
        r, err := c.https.Get(u, nil)
 
201
        if err != nil {
 
202
                return nil, err
 
203
        }
 
204
        defer r.Body.Close()
 
205
 
 
206
        if err := r.VerifyJSON(200); err != nil {
 
207
                return nil, NewError(r, err)
 
208
        }
 
209
 
 
210
        return data.ReadDrive(r.Body)
 
211
}
 
212
 
 
213
func (c Client) cloneDrive(uuid string, libspec LibrarySpec, params CloneParams, avoid []string) (*data.Drive, error) {
 
214
        uuid = strings.TrimSpace(uuid)
 
215
        if uuid == "" {
 
216
                return nil, errEmptyUUID
 
217
        }
 
218
 
 
219
        u := c.endpoint
 
220
        if libspec == LibraryMedia {
 
221
                u += "libdrives/"
 
222
        } else {
 
223
                u += "drives/"
 
224
        }
 
225
        u += uuid + "/action/"
 
226
 
 
227
        var qq = make(url.Values)
 
228
        qq["do"] = []string{"clone"}
 
229
 
 
230
        if len(avoid) > 0 {
 
231
                qq["avoid"] = []string{strings.Join(avoid, ",")}
 
232
        }
 
233
 
 
234
        rr, err := params.makeJSONReader()
 
235
        if err != nil {
 
236
                return nil, err
 
237
        }
 
238
 
 
239
        r, err := c.https.Post(u, qq, rr)
 
240
        if err != nil {
 
241
                return nil, err
 
242
        }
 
243
        defer r.Body.Close()
 
244
 
 
245
        if err := r.VerifyJSON(202); err != nil {
 
246
                return nil, NewError(r, err)
 
247
        }
 
248
 
 
249
        objs, err := data.ReadDrives(r.Body)
 
250
 
 
251
        if err != nil {
 
252
                return nil, err
 
253
        }
 
254
 
 
255
        if len(objs) == 0 {
 
256
                return nil, errors.New("no object was returned from server")
 
257
        }
 
258
 
 
259
        if libspec == LibraryMedia {
 
260
                // fix CloudSigma API result, disk has URI pointed to libdrive - must be drives
 
261
                uuid := objs[0].Resource.UUID
 
262
                objs[0].Resource = *data.MakeDriveResource(uuid)
 
263
        }
 
264
 
 
265
        return &objs[0], nil
 
266
}
 
267
 
 
268
func (c *Client) removeDrive(uuid string, libspec LibrarySpec) error {
 
269
        uuid = strings.TrimSpace(uuid)
 
270
        if uuid == "" {
 
271
                return errEmptyUUID
 
272
        }
 
273
 
 
274
        u := c.endpoint
 
275
        if libspec == LibraryMedia {
 
276
                u += "libdrives/"
 
277
        } else {
 
278
                u += "drives/"
 
279
        }
 
280
        u += uuid + "/"
 
281
 
 
282
        r, err := c.https.Delete(u, nil, nil)
 
283
        if err != nil {
 
284
                return err
 
285
        }
 
286
        defer r.Body.Close()
 
287
 
 
288
        if err := r.VerifyCode(204); err != nil {
 
289
                return NewError(r, err)
 
290
        }
 
291
 
 
292
        return nil
 
293
}
 
294
 
 
295
func (c Client) getJob(uuid string) (*data.Job, error) {
 
296
        uuid = strings.TrimSpace(uuid)
 
297
        if uuid == "" {
 
298
                return nil, errEmptyUUID
 
299
        }
 
300
 
 
301
        u := c.endpoint + "jobs/" + uuid + "/"
 
302
 
 
303
        r, err := c.https.Get(u, nil)
 
304
        if err != nil {
 
305
                return nil, err
 
306
        }
 
307
        defer r.Body.Close()
 
308
 
 
309
        if err := r.VerifyJSON(200); err != nil {
 
310
                return nil, NewError(r, err)
 
311
        }
 
312
 
 
313
        return data.ReadJob(r.Body)
 
314
}
 
315
 
 
316
func (c Client) readContext() (*data.Context, error) {
 
317
 
 
318
        const (
 
319
                DEVICE  = "/dev/ttyS1"
 
320
                REQUEST = "<\n\n>"
 
321
                EOT     = '\x04'
 
322
        )
 
323
 
 
324
        logger := c.logger
 
325
 
 
326
        // open server ctx device
 
327
        f, err := os.OpenFile(DEVICE, os.O_RDWR, 0)
 
328
        if err != nil {
 
329
                return nil, fmt.Errorf("error OpenFile: %s", err)
 
330
        }
 
331
        defer f.Close()
 
332
 
 
333
        // schedule timeout, if defined
 
334
        readWriteTimeout := c.GetReadWriteTimeout()
 
335
        if readWriteTimeout > 0 {
 
336
                timer := time.AfterFunc(readWriteTimeout, func() {
 
337
                        f.Close()
 
338
                })
 
339
                defer timer.Stop()
 
340
        }
 
341
 
 
342
        // writing request to service
 
343
        n, err := f.WriteString(REQUEST)
 
344
        if err != nil {
 
345
                return nil, fmt.Errorf("error WriteString: %s", err)
 
346
        }
 
347
 
 
348
        // check the request was written
 
349
        if n != len(REQUEST) {
 
350
                return nil, fmt.Errorf("invalid write length %d, wants %d", n, len(REQUEST))
 
351
        }
 
352
 
 
353
        // prepare buffered I/O object
 
354
        r := bufio.NewReader(f)
 
355
 
 
356
        // read until End-Of-Transfer (EOT) symbol or EOF
 
357
        bb, err := r.ReadBytes(EOT)
 
358
        if err != nil && err != io.EOF {
 
359
                return nil, fmt.Errorf("error ReadBytes: %s", err)
 
360
        }
 
361
 
 
362
        // if EOT was read, truncate it
 
363
        if len(bb) > 0 {
 
364
                if last := len(bb) - 1; bb[last] == EOT {
 
365
                        bb = bb[:last]
 
366
                }
 
367
        }
 
368
 
 
369
        // log server context as raw content
 
370
        if logger != nil {
 
371
                logger.Logf("")
 
372
                logger.Logf("server context:\n%s", string(bb))
 
373
                logger.Logf("")
 
374
        }
 
375
 
 
376
        // prepare reader around raw content
 
377
        rr := bytes.NewReader(bb)
 
378
 
 
379
        // parse server context JSON to the data.Context object
 
380
        return data.ReadContext(rr)
 
381
}
 
382
 
 
383
func (c Client) resizeDrive(obj data.Drive, newSize uint64) (*data.Drive, error) {
 
384
 
 
385
        // prepare endpoint URL
 
386
        u := c.endpoint + "drives/" + obj.UUID + "/action/"
 
387
 
 
388
        // prepare request query params
 
389
        var qq = make(url.Values)
 
390
        qq["do"] = []string{"resize"}
 
391
 
 
392
        // prepare request body
 
393
        obj.Size = newSize
 
394
        rr, err := data.WriteDrive(&obj)
 
395
        if err != nil {
 
396
                return nil, err
 
397
        }
 
398
 
 
399
        // do request
 
400
        r, err := c.https.Post(u, qq, rr)
 
401
        if err != nil {
 
402
                return nil, err
 
403
        }
 
404
        defer r.Body.Close()
 
405
 
 
406
        // verify reply
 
407
        if err := r.VerifyJSON(202); err != nil {
 
408
                return nil, NewError(r, err)
 
409
        }
 
410
 
 
411
        // read and parse reply body
 
412
        objs, err := data.ReadDrives(r.Body)
 
413
 
 
414
        if err != nil {
 
415
                return nil, err
 
416
        }
 
417
 
 
418
        // verify reply body content
 
419
        if len(objs) == 0 {
 
420
                return nil, errors.New("no object was returned from server")
 
421
        }
 
422
 
 
423
        // return result
 
424
        return &objs[0], nil
 
425
}