From c780172c682996f0456171b13a2913792c551118 Mon Sep 17 00:00:00 2001 From: cliedeman Date: Mon, 3 Sep 2018 15:34:11 +0200 Subject: [PATCH 01/18] Adding Nodebalancer rebuild --- nodebalancer.go | 7 +++--- nodebalancer_configs.go | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/nodebalancer.go b/nodebalancer.go index bc6fc0a07..22e6e60e3 100644 --- a/nodebalancer.go +++ b/nodebalancer.go @@ -44,9 +44,10 @@ type NodeBalancerTransfer struct { // NodeBalancerCreateOptions are the options permitted for CreateNodeBalancer type NodeBalancerCreateOptions struct { - Label *string `json:"label,omitempty"` - Region string `json:"region,omitempty"` - ClientConnThrottle *int `json:"client_conn_throttle,omitempty"` + Label *string `json:"label,omitempty"` + Region string `json:"region,omitempty"` + ClientConnThrottle *int `json:"client_conn_throttle,omitempty"` + Configs []*NodeBalancerConfigCreateOptions `json:"configs,omitempty"` } // NodeBalancerUpdateOptions are the options permitted for UpdateNodeBalancer diff --git a/nodebalancer_configs.go b/nodebalancer_configs.go index babbcb35f..d4538b396 100644 --- a/nodebalancer_configs.go +++ b/nodebalancer_configs.go @@ -103,6 +103,33 @@ type NodeBalancerConfigCreateOptions struct { SSLKey string `json:"ssl_key,omitempty"` } +// NodeBalancerConfigRebuildOptionsNode for a nodebalancer instance mapping +type NodeBalancerConfigRebuildOptionsNode struct { + Address *string `json:"address"` + Label *string `json:"label"` + Weight *int `json:"weight"` + Mode *string `json:"mode"` +} + +// NodeBalancerConfigRebuildOptions used by RebuildNodeBalancerConfig +type NodeBalancerConfigRebuildOptions struct { + Port int `json:"port"` + Protocol ConfigProtocol `json:"protocol,omitempty"` + Algorithm ConfigAlgorithm `json:"algorithm,omitempty"` + Stickiness ConfigStickiness `json:"stickiness,omitempty"` + Check ConfigCheck `json:"check,omitempty"` + CheckInterval int `json:"check_interval,omitempty"` + CheckAttempts int `json:"check_attempts,omitempty"` + CheckPath string `json:"check_path,omitempty"` + CheckBody string `json:"check_body,omitempty"` + CheckPassive *bool `json:"check_passive,omitempty"` + CheckTimeout int `json:"check_timeout,omitempty"` + CipherSuite ConfigCipher `json:"cipher_suite,omitempty"` + SSLCert string `json:"ssl_cert,omitempty"` + SSLKey string `json:"ssl_key,omitempty"` + Nodes []*NodeBalancerConfigRebuildOptionsNode `json:"nodes,omitempty"` +} + // NodeBalancerConfigUpdateOptions are permitted by UpdateNodeBalancerConfig type NodeBalancerConfigUpdateOptions NodeBalancerConfigCreateOptions @@ -264,3 +291,30 @@ func (c *Client) DeleteNodeBalancerConfig(ctx context.Context, nodebalancerID in _, err = coupleAPIErrors(c.R(ctx).Delete(e)) return err } + +// RebuildNodeBalancerConfig updates the NodeBalancer with the specified id +func (c *Client) RebuildNodeBalancerConfig(ctx context.Context, nodeBalancerID int, configID int, rebuildOpts NodeBalancerConfigRebuildOptions) (*NodeBalancer, error) { + var body string + e, err := c.NodeBalancerConfigs.endpointWithID(nodeBalancerID) + if err != nil { + return nil, err + } + e = fmt.Sprintf("%s/%d/rebuild", e, configID) + + req := c.R(ctx).SetResult(&NodeBalancer{}) + + if bodyData, err := json.Marshal(rebuildOpts); err == nil { + body = string(bodyData) + } else { + return nil, NewError(err) + } + + r, err := coupleAPIErrors(req. + SetBody(body). + Put(e)) + + if err != nil { + return nil, err + } + return r.Result().(*NodeBalancer).fixDates(), nil +} From 14df0566c96e8bdb3eaacea130d72d48c1f549a8 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Mon, 3 Sep 2018 13:50:59 -0400 Subject: [PATCH 02/18] devices are optional for InstanceConfigUpdateOptions --- instance_configs.go | 10 +++++----- waitfor.go | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/instance_configs.go b/instance_configs.go index 1a7adceb1..8da71ca5f 100644 --- a/instance_configs.go +++ b/instance_configs.go @@ -76,10 +76,10 @@ type InstanceConfigCreateOptions struct { // InstanceConfigUpdateOptions are InstanceConfig settings that can be used in updates type InstanceConfigUpdateOptions struct { - Label string `json:"label,omitempty"` - Comments string `json:"comments"` - Devices InstanceConfigDeviceMap `json:"devices"` - Helpers *InstanceConfigHelpers `json:"helpers,omitempty"` + Label string `json:"label,omitempty"` + Comments string `json:"comments"` + Devices *InstanceConfigDeviceMap `json:"devices,omitempty"` + Helpers *InstanceConfigHelpers `json:"helpers,omitempty"` // MemoryLimit 0 means unlimitted, this is not omitted MemoryLimit int `json:"memory_limit"` Kernel string `json:"kernel,omitempty"` @@ -111,7 +111,7 @@ func (i InstanceConfig) GetUpdateOptions() InstanceConfigUpdateOptions { return InstanceConfigUpdateOptions{ Label: i.Label, Comments: i.Comments, - Devices: *i.Devices, + Devices: i.Devices, Helpers: i.Helpers, MemoryLimit: i.MemoryLimit, Kernel: i.Kernel, diff --git a/waitfor.go b/waitfor.go index 420423da8..2203f76b1 100644 --- a/waitfor.go +++ b/waitfor.go @@ -226,6 +226,7 @@ func (client Client) WaitForEventFinished(ctx context.Context, id interface{}, e log.Printf("[INFO] %s %v action %s is finished", titledEntityType, id, action) return event, nil } + // TODO(displague) can we bump the ticker to TimeRemaining/2 (>=1) when non-nil? log.Printf("[INFO] %s %v action %s is %s", titledEntityType, id, action, event.Status) } case <-ctx.Done(): From 24611be5de3c8b78debf69847cb837e4be9c0815 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Mon, 3 Sep 2018 14:01:46 -0400 Subject: [PATCH 03/18] fix event parsing of time_remaining which may be int, string, or null --- account_events.go | 49 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/account_events.go b/account_events.go index 527fe3074..05f39030c 100644 --- a/account_events.go +++ b/account_events.go @@ -2,7 +2,10 @@ package linodego import ( "context" + "encoding/json" "fmt" + "strconv" + "strings" "time" ) @@ -23,7 +26,7 @@ type Event struct { PercentComplete int `json:"percent_complete"` // The rate of completion of the Event. Only some Events will return rate; for example, migration and resize Events. - Rate string `json:"rate"` + Rate *string `json:"rate"` // If this Event has been read. Read bool `json:"read"` @@ -32,7 +35,8 @@ type Event struct { Seen bool `json:"seen"` // The estimated time remaining until the completion of this Event. This value is only returned for in-progress events. - TimeRemaining int `json:"time_remaining"` + TimeRemainingMsg json.RawMessage `json:"time_remaining"` + TimeRemaining *int `json:"-"` // The username of the User who caused the Event. Username string `json:"username"` @@ -200,6 +204,7 @@ func (c *Client) GetEvent(ctx context.Context, id int) (*Event, error) { // fixDates converts JSON timestamps to Go time.Time values func (e *Event) fixDates() *Event { e.Created, _ = parseDates(e.CreatedStr) + e.TimeRemaining = unmarshalTimeRemaining(e.TimeRemainingMsg) return e } @@ -222,3 +227,43 @@ func (c *Client) MarkEventsSeen(ctx context.Context, event *Event) error { return err } + +func unmarshalTimeRemaining(m json.RawMessage) *int { + var intPtr *int + jsonBytes, err := m.MarshalJSON() + if err != nil { + panic(err) + } + if err := json.Unmarshal(jsonBytes, intPtr); err == nil { + return intPtr + } + var timeStr string + if err := json.Unmarshal(jsonBytes, timeStr); err == nil { + if dur, err := durationToSeconds(timeStr); err != nil { + panic(err) + } else { + return &dur + } + } + + return nil +} + +// durationToSeconds takes a hh:mm:ss string and returns the number of seconds +func durationToSeconds(s string) (int, error) { + multipliers := [3]int{60 * 60, 60, 1} + segs := strings.Split(s, ":") + if len(segs) > len(multipliers) { + return 0, fmt.Errorf("too many ':' separators in time duration: %s", s) + } + var d int + l := len(segs) + for i := 0; i < l; i++ { + m, err := strconv.Atoi(segs[i]) + if err != nil { + return 0, err + } + d += m * multipliers[i+len(multipliers)-l] + } + return d, nil +} From cd81cca830323670725d0b66bb04e164b36d29e3 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Mon, 3 Sep 2018 14:05:46 -0400 Subject: [PATCH 04/18] instance_config: make null and "" options possible for init_rd and root_device --- instance_configs.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/instance_configs.go b/instance_configs.go index 8da71ca5f..d9b0f333b 100644 --- a/instance_configs.go +++ b/instance_configs.go @@ -69,7 +69,7 @@ type InstanceConfigCreateOptions struct { MemoryLimit int `json:"memory_limit,omitempty"` Kernel string `json:"kernel,omitempty"` InitRD int `json:"init_rd,omitempty"` - RootDevice string `json:"root_device,omitempty"` + RootDevice *string `json:"root_device,omitempty"` RunLevel string `json:"run_level,omitempty"` VirtMode string `json:"virt_mode,omitempty"` } @@ -84,14 +84,18 @@ type InstanceConfigUpdateOptions struct { MemoryLimit int `json:"memory_limit"` Kernel string `json:"kernel,omitempty"` // InitRD is nullable, permit the sending of null - InitRD *int `json:"init_rd"` - RootDevice string `json:"root_device,omitempty"` - RunLevel string `json:"run_level,omitempty"` - VirtMode string `json:"virt_mode,omitempty"` + InitRD *int `json:"init_rd"` + RootDevice *string `json:"root_device,omitempty"` + RunLevel string `json:"run_level,omitempty"` + VirtMode string `json:"virt_mode,omitempty"` } // GetCreateOptions converts a InstanceConfig to InstanceConfigCreateOptions for use in CreateInstanceConfig func (i InstanceConfig) GetCreateOptions() InstanceConfigCreateOptions { + initrd := 0 + if i.InitRD != nil { + initrd = *i.InitRD + } return InstanceConfigCreateOptions{ Label: i.Label, Comments: i.Comments, @@ -99,8 +103,8 @@ func (i InstanceConfig) GetCreateOptions() InstanceConfigCreateOptions { Helpers: i.Helpers, MemoryLimit: i.MemoryLimit, Kernel: i.Kernel, - InitRD: *i.InitRD, - RootDevice: i.RootDevice, + InitRD: initrd, + RootDevice: copyString(&i.RootDevice), RunLevel: i.RunLevel, VirtMode: i.VirtMode, } @@ -116,7 +120,7 @@ func (i InstanceConfig) GetUpdateOptions() InstanceConfigUpdateOptions { MemoryLimit: i.MemoryLimit, Kernel: i.Kernel, InitRD: copyInt(i.InitRD), - RootDevice: i.RootDevice, + RootDevice: copyString(&i.RootDevice), RunLevel: i.RunLevel, VirtMode: i.VirtMode, } From 86c70be4713f54d9df9bf8264673781c6f499db4 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Mon, 3 Sep 2018 22:38:20 -0400 Subject: [PATCH 05/18] disable gosec lint tests --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 272f1b172..b520a18d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,8 @@ install: script: - touch .env - make test ARGS='-coverprofile=coverage.txt -covermode=atomic' - - gometalinter.v2 --enable-all --disable=vetshadow --disable=gocyclo --disable=unparam --disable=nakedret --disable=lll --disable=dupl --disable=gochecknoinits --disable=gochecknoglobals --disable=test --deadline=120s - - gometalinter.v2 --disable-all --enable=vetshadow --enable=gocyclo --enable=unparam --enable=nakedret --enable=lll --enable=dupl --enable=gochecknoinits --enable=gochecknoglobals --deadline=120s || true + - gometalinter.v2 --enable-all --disable=vetshadow --disable=gocyclo --disable=unparam --disable=nakedret --disable=lll --disable=dupl --disable=gosec --disable=gochecknoinits --disable=gochecknoglobals --disable=test --deadline=120s + - gometalinter.v2 --disable-all --enable=vetshadow --enable=gocyclo --enable=unparam --enable=nakedret --enable=lll --enable=dupl --enable=gosec --enable=gochecknoinits --enable=gochecknoglobals --deadline=120s || true after_success: - bash <(curl -s https://codecov.io/bash) From ec78d2cbb804afbda57a48d3e25d4744d561a47d Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Mon, 3 Sep 2018 23:41:24 -0400 Subject: [PATCH 06/18] add tests and fixtures for account/events time_remaining --- account_events.go | 8 +-- account_events_test.go | 32 ++++++++++ fixtures/TestListEvents_resizing.yaml | 87 +++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 account_events_test.go create mode 100644 fixtures/TestListEvents_resizing.yaml diff --git a/account_events.go b/account_events.go index 05f39030c..4905b1184 100644 --- a/account_events.go +++ b/account_events.go @@ -234,12 +234,12 @@ func unmarshalTimeRemaining(m json.RawMessage) *int { if err != nil { panic(err) } - if err := json.Unmarshal(jsonBytes, intPtr); err == nil { + if err := json.Unmarshal(jsonBytes, intPtr); err == nil && intPtr != nil { return intPtr } - var timeStr string - if err := json.Unmarshal(jsonBytes, timeStr); err == nil { - if dur, err := durationToSeconds(timeStr); err != nil { + var timeStr *string + if err := json.Unmarshal(jsonBytes, timeStr); err == nil && timeStr != nil { + if dur, err := durationToSeconds(*timeStr); err != nil { panic(err) } else { return &dur diff --git a/account_events_test.go b/account_events_test.go new file mode 100644 index 000000000..d4602f22e --- /dev/null +++ b/account_events_test.go @@ -0,0 +1,32 @@ +package linodego_test + +import ( + "context" + "testing" +) + +func TestListEvents_resizing(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + + client, teardown := createTestClient(t, "fixtures/TestListEvents_resizing") + defer teardown() + + events, err := client.ListEvents(context.Background(), nil) + if err != nil { + t.Errorf("Error getting Events, expected struct, got error %v", err) + } + + if events[2].TimeRemaining != nil { + t.Errorf("Error listing Events, expected resize event time_remaining to be nil, got %v", events[2].TimeRemaining) + } + + if events[1].TimeRemaining == nil || *events[1].TimeRemaining != 0 { + t.Errorf("Error listing Events, expected resize event time_remaining to be 0 seconds, got %v", events[1].TimeRemaining) + } + + if events[0].TimeRemaining == nil || *events[0].TimeRemaining != 60+23 { + t.Errorf("Error listing Events, expected resize event time_remaining to be 83 seconds, got %v", events[0].TimeRemaining) + } +} diff --git a/fixtures/TestListEvents_resizing.yaml b/fixtures/TestListEvents_resizing.yaml new file mode 100644 index 000000000..b3d1eaf28 --- /dev/null +++ b/fixtures/TestListEvents_resizing.yaml @@ -0,0 +1,87 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.1.1 https://github.com/linode/linodego + url: https://api.linode.com/v4/account/events + method: GET + response: + body: '{"data": [{"created": "2018-01-02T03:04:05", "username": "restricted_tester", + "status": "resizing", "time_remaining": "1:23", "id": 11846172, "percent_complete": + 0, "entity": {"label": "linodego-test-instance", "url": "/v4/linode/instances/9588435", + "id": 9588435, "type": "linode"}, "read": false, "rate": "1.23 MB/s", "seen": false, + "action": "linode_resize"}, {"created": "2018-01-02T03:04:05", "username": "restricted_tester", + "status": "finished", "time_remaining": 0, "id": 11846182, "percent_complete": + 100, "entity": {"label": "linodego-test-instance", "url": "/v4/linode/instances/9588435", + "id": 9588435, "type": "linode"}, "read": false, "rate": null, "seen": false, + "action": "linode_resize"},{"created": "2018-01-02T03:04:05", "username": "restricted_tester", + "status": "finished", "time_remaining": null, "id": 11846192, "percent_complete": + null, "entity": {"label": "linodego-test-instance", "url": "/v4/linode/instances/9588435", + "id": 9588435, "type": "linode"}, "read": false, "rate": null, "seen": false, + "action": "linode_resize"}], "page": 1, "pages": 1, "results": 3}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "35494" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 11 Aug 2018 00:02:11 GMT + Retry-After: + - "114" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - events:read_only + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "397" + X-Ratelimit-Reset: + - "1533945846" + X-Spec-Version: + - 4.0.3 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" From f701f1a69e978c07f166936453636bea8b178251 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Wed, 5 Sep 2018 22:55:30 -0400 Subject: [PATCH 07/18] List*: use slice of thing, not slice of pointer --- account_events.go | 6 +++--- account_invoices.go | 12 ++++++------ account_notifications.go | 6 +++--- domain_records.go | 6 +++--- domain_records_test.go | 2 +- domains.go | 6 +++--- images.go | 6 +++--- instance_configs.go | 6 +++--- instance_disks.go | 6 +++--- instance_volumes.go | 6 +++--- instances.go | 6 +++--- kernels.go | 6 +++--- longview.go | 6 +++--- longview_subscriptions.go | 6 +++--- network_ips.go | 6 +++--- network_pools.go | 6 +++--- network_ranges.go | 6 +++--- nodebalancer.go | 6 +++--- nodebalancer_config_nodes.go | 6 +++--- nodebalancer_configs.go | 6 +++--- regions.go | 6 +++--- stackscripts.go | 6 +++--- support.go | 6 +++--- template.go | 6 +++--- types.go | 6 +++--- volumes.go | 6 +++--- waitfor.go | 4 ++-- 27 files changed, 81 insertions(+), 81 deletions(-) diff --git a/account_events.go b/account_events.go index 527fe3074..d1cbab4bc 100644 --- a/account_events.go +++ b/account_events.go @@ -141,7 +141,7 @@ type EventEntity struct { // EventsPagedResponse represents a paginated Events API response type EventsPagedResponse struct { *PageOptions - Data []*Event `json:"data"` + Data []Event `json:"data"` } // endpoint gets the endpoint URL for Event @@ -165,13 +165,13 @@ func (e Event) endpointWithID(c *Client) string { // appendData appends Events when processing paginated Event responses func (resp *EventsPagedResponse) appendData(r *EventsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListEvents gets a collection of Event objects representing actions taken // on the Account. The Events returned depend on the token grants and the grants // of the associated user. -func (c *Client) ListEvents(ctx context.Context, opts *ListOptions) ([]*Event, error) { +func (c *Client) ListEvents(ctx context.Context, opts *ListOptions) ([]Event, error) { response := EventsPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/account_invoices.go b/account_invoices.go index 200398715..22b9fcc18 100644 --- a/account_invoices.go +++ b/account_invoices.go @@ -33,7 +33,7 @@ type InvoiceItem struct { // InvoicesPagedResponse represents a paginated Invoice API response type InvoicesPagedResponse struct { *PageOptions - Data []*Invoice `json:"data"` + Data []Invoice `json:"data"` } // endpoint gets the endpoint URL for Invoice @@ -47,11 +47,11 @@ func (InvoicesPagedResponse) endpoint(c *Client) string { // appendData appends Invoices when processing paginated Invoice responses func (resp *InvoicesPagedResponse) appendData(r *InvoicesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListInvoices gets a paginated list of Invoices against the Account -func (c *Client) ListInvoices(ctx context.Context, opts *ListOptions) ([]*Invoice, error) { +func (c *Client) ListInvoices(ctx context.Context, opts *ListOptions) ([]Invoice, error) { response := InvoicesPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { @@ -94,7 +94,7 @@ func (c *Client) GetInvoice(ctx context.Context, id int) (*Invoice, error) { // InvoiceItemsPagedResponse represents a paginated Invoice Item API response type InvoiceItemsPagedResponse struct { *PageOptions - Data []*InvoiceItem `json:"data"` + Data []InvoiceItem `json:"data"` } // endpointWithID gets the endpoint URL for InvoiceItems associated with a specific Invoice @@ -108,11 +108,11 @@ func (InvoiceItemsPagedResponse) endpointWithID(c *Client, id int) string { // appendData appends InvoiceItems when processing paginated Invoice Item responses func (resp *InvoiceItemsPagedResponse) appendData(r *InvoiceItemsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListInvoiceItems gets the invoice items associated with a specific Invoice -func (c *Client) ListInvoiceItems(ctx context.Context, id int, opts *ListOptions) ([]*InvoiceItem, error) { +func (c *Client) ListInvoiceItems(ctx context.Context, id int, opts *ListOptions) ([]InvoiceItem, error) { response := InvoiceItemsPagedResponse{} err := c.listHelperWithID(ctx, &response, id, opts) for _, el := range response.Data { diff --git a/account_notifications.go b/account_notifications.go index f5a35e093..59504dae8 100644 --- a/account_notifications.go +++ b/account_notifications.go @@ -31,7 +31,7 @@ type NotificationEntity struct { // NotificationsPagedResponse represents a paginated Notifications API response type NotificationsPagedResponse struct { *PageOptions - Data []*Notification `json:"data"` + Data []Notification `json:"data"` } // endpoint gets the endpoint URL for Notification @@ -45,7 +45,7 @@ func (NotificationsPagedResponse) endpoint(c *Client) string { // appendData appends Notifications when processing paginated Notification responses func (resp *NotificationsPagedResponse) appendData(r *NotificationsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListNotifications gets a collection of Notification objects representing important, @@ -53,7 +53,7 @@ func (resp *NotificationsPagedResponse) appendData(r *NotificationsPagedResponse // Notifications, and a Notification will disappear when the circumstances causing it // have been resolved. For example, if the account has an important Ticket open, a response // to the Ticket will dismiss the Notification. -func (c *Client) ListNotifications(ctx context.Context, opts *ListOptions) ([]*Notification, error) { +func (c *Client) ListNotifications(ctx context.Context, opts *ListOptions) ([]Notification, error) { response := NotificationsPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/domain_records.go b/domain_records.go index b2ff8e0c1..2ebbff5b7 100644 --- a/domain_records.go +++ b/domain_records.go @@ -99,7 +99,7 @@ func copyString(sPtr *string) *string { // DomainRecordsPagedResponse represents a paginated DomainRecord API response type DomainRecordsPagedResponse struct { *PageOptions - Data []*DomainRecord `json:"data"` + Data []DomainRecord `json:"data"` } // endpoint gets the endpoint URL for InstanceConfig @@ -113,11 +113,11 @@ func (DomainRecordsPagedResponse) endpointWithID(c *Client, id int) string { // appendData appends DomainRecords when processing paginated DomainRecord responses func (resp *DomainRecordsPagedResponse) appendData(r *DomainRecordsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListDomainRecords lists DomainRecords -func (c *Client) ListDomainRecords(ctx context.Context, domainID int, opts *ListOptions) ([]*DomainRecord, error) { +func (c *Client) ListDomainRecords(ctx context.Context, domainID int, opts *ListOptions) ([]DomainRecord, error) { response := DomainRecordsPagedResponse{} err := c.listHelperWithID(ctx, &response, domainID, opts) if err != nil { diff --git a/domain_records_test.go b/domain_records_test.go index e5ee2331e..154cecb30 100644 --- a/domain_records_test.go +++ b/domain_records_test.go @@ -107,7 +107,7 @@ func TestListDomainRecordsMultiplePages(t *testing.T) { t.Errorf("Error listing domains records, expected array, got error %v", err) } if len(records) != 2 { - t.Errorf("Expected ListDomainRecords to match one result") + t.Errorf("Expected ListDomainRecords to match two results") } } diff --git a/domains.go b/domains.go index 207d93117..f0f048a82 100644 --- a/domains.go +++ b/domains.go @@ -173,7 +173,7 @@ func (d Domain) GetUpdateOptions() (du DomainUpdateOptions) { // DomainsPagedResponse represents a paginated Domain API response type DomainsPagedResponse struct { *PageOptions - Data []*Domain `json:"data"` + Data []Domain `json:"data"` } // endpoint gets the endpoint URL for Domain @@ -187,11 +187,11 @@ func (DomainsPagedResponse) endpoint(c *Client) string { // appendData appends Domains when processing paginated Domain responses func (resp *DomainsPagedResponse) appendData(r *DomainsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListDomains lists Domains -func (c *Client) ListDomains(ctx context.Context, opts *ListOptions) ([]*Domain, error) { +func (c *Client) ListDomains(ctx context.Context, opts *ListOptions) ([]Domain, error) { response := DomainsPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/images.go b/images.go index 814c0a0a8..1ed99fa3d 100644 --- a/images.go +++ b/images.go @@ -54,7 +54,7 @@ func (i Image) GetUpdateOptions() (iu ImageUpdateOptions) { // ImagesPagedResponse represents a linode API response for listing of images type ImagesPagedResponse struct { *PageOptions - Data []*Image `json:"data"` + Data []Image `json:"data"` } func (ImagesPagedResponse) endpoint(c *Client) string { @@ -66,11 +66,11 @@ func (ImagesPagedResponse) endpoint(c *Client) string { } func (resp *ImagesPagedResponse) appendData(r *ImagesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListImages lists Images -func (c *Client) ListImages(ctx context.Context, opts *ListOptions) ([]*Image, error) { +func (c *Client) ListImages(ctx context.Context, opts *ListOptions) ([]Image, error) { response := ImagesPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/instance_configs.go b/instance_configs.go index 1a7adceb1..3980e8fbc 100644 --- a/instance_configs.go +++ b/instance_configs.go @@ -57,7 +57,7 @@ type InstanceConfigHelpers struct { // InstanceConfigsPagedResponse represents a paginated InstanceConfig API response type InstanceConfigsPagedResponse struct { *PageOptions - Data []*InstanceConfig `json:"data"` + Data []InstanceConfig `json:"data"` } // InstanceConfigCreateOptions are InstanceConfig settings that can be used at creation @@ -133,11 +133,11 @@ func (InstanceConfigsPagedResponse) endpointWithID(c *Client, id int) string { // appendData appends InstanceConfigs when processing paginated InstanceConfig responses func (resp *InstanceConfigsPagedResponse) appendData(r *InstanceConfigsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListInstanceConfigs lists InstanceConfigs -func (c *Client) ListInstanceConfigs(ctx context.Context, linodeID int, opts *ListOptions) ([]*InstanceConfig, error) { +func (c *Client) ListInstanceConfigs(ctx context.Context, linodeID int, opts *ListOptions) ([]InstanceConfig, error) { response := InstanceConfigsPagedResponse{} err := c.listHelperWithID(ctx, &response, linodeID, opts) for _, el := range response.Data { diff --git a/instance_disks.go b/instance_disks.go index ce086630c..b6734fed0 100644 --- a/instance_disks.go +++ b/instance_disks.go @@ -36,7 +36,7 @@ const ( // InstanceDisksPagedResponse represents a paginated InstanceDisk API response type InstanceDisksPagedResponse struct { *PageOptions - Data []*InstanceDisk `json:"data"` + Data []InstanceDisk `json:"data"` } // InstanceDiskCreateOptions are InstanceDisk settings that can be used at creation @@ -72,11 +72,11 @@ func (InstanceDisksPagedResponse) endpointWithID(c *Client, id int) string { // appendData appends InstanceDisks when processing paginated InstanceDisk responses func (resp *InstanceDisksPagedResponse) appendData(r *InstanceDisksPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListInstanceDisks lists InstanceDisks -func (c *Client) ListInstanceDisks(ctx context.Context, linodeID int, opts *ListOptions) ([]*InstanceDisk, error) { +func (c *Client) ListInstanceDisks(ctx context.Context, linodeID int, opts *ListOptions) ([]InstanceDisk, error) { response := InstanceDisksPagedResponse{} err := c.listHelperWithID(ctx, &response, linodeID, opts) for _, el := range response.Data { diff --git a/instance_volumes.go b/instance_volumes.go index 88d61bab2..f27268628 100644 --- a/instance_volumes.go +++ b/instance_volumes.go @@ -7,7 +7,7 @@ import ( // InstanceVolumesPagedResponse represents a paginated InstanceVolume API response type InstanceVolumesPagedResponse struct { *PageOptions - Data []*Volume `json:"data"` + Data []Volume `json:"data"` } // endpoint gets the endpoint URL for InstanceVolume @@ -21,11 +21,11 @@ func (InstanceVolumesPagedResponse) endpointWithID(c *Client, id int) string { // appendData appends InstanceVolumes when processing paginated InstanceVolume responses func (resp *InstanceVolumesPagedResponse) appendData(r *InstanceVolumesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListInstanceVolumes lists InstanceVolumes -func (c *Client) ListInstanceVolumes(ctx context.Context, linodeID int, opts *ListOptions) ([]*Volume, error) { +func (c *Client) ListInstanceVolumes(ctx context.Context, linodeID int, opts *ListOptions) ([]Volume, error) { response := InstanceVolumesPagedResponse{} err := c.listHelperWithID(ctx, &response, linodeID, opts) for _, el := range response.Data { diff --git a/instances.go b/instances.go index dcdee058f..5a92c19fb 100644 --- a/instances.go +++ b/instances.go @@ -131,7 +131,7 @@ func (l *Instance) fixDates() *Instance { // InstancesPagedResponse represents a linode API response for listing type InstancesPagedResponse struct { *PageOptions - Data []*Instance `json:"data"` + Data []Instance `json:"data"` } // endpoint gets the endpoint URL for Instance @@ -145,11 +145,11 @@ func (InstancesPagedResponse) endpoint(c *Client) string { // appendData appends Instances when processing paginated Instance responses func (resp *InstancesPagedResponse) appendData(r *InstancesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListInstances lists linode instances -func (c *Client) ListInstances(ctx context.Context, opts *ListOptions) ([]*Instance, error) { +func (c *Client) ListInstances(ctx context.Context, opts *ListOptions) ([]Instance, error) { response := InstancesPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/kernels.go b/kernels.go index 4bc165f9c..233a38db5 100644 --- a/kernels.go +++ b/kernels.go @@ -19,11 +19,11 @@ type LinodeKernel struct { // LinodeKernelsPagedResponse represents a Linode kernels API response for listing type LinodeKernelsPagedResponse struct { *PageOptions - Data []*LinodeKernel `json:"data"` + Data []LinodeKernel `json:"data"` } // ListKernels lists linode kernels -func (c *Client) ListKernels(ctx context.Context, opts *ListOptions) ([]*LinodeKernel, error) { +func (c *Client) ListKernels(ctx context.Context, opts *ListOptions) ([]LinodeKernel, error) { response := LinodeKernelsPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { @@ -41,7 +41,7 @@ func (LinodeKernelsPagedResponse) endpoint(c *Client) string { } func (resp *LinodeKernelsPagedResponse) appendData(r *LinodeKernelsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // GetKernel gets the kernel with the provided ID diff --git a/longview.go b/longview.go index 649ecdb60..70508f967 100644 --- a/longview.go +++ b/longview.go @@ -15,7 +15,7 @@ type LongviewClient struct { // LongviewClientsPagedResponse represents a paginated LongviewClient API response type LongviewClientsPagedResponse struct { *PageOptions - Data []*LongviewClient `json:"data"` + Data []LongviewClient `json:"data"` } // endpoint gets the endpoint URL for LongviewClient @@ -29,11 +29,11 @@ func (LongviewClientsPagedResponse) endpoint(c *Client) string { // appendData appends LongviewClients when processing paginated LongviewClient responses func (resp *LongviewClientsPagedResponse) appendData(r *LongviewClientsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListLongviewClients lists LongviewClients -func (c *Client) ListLongviewClients(ctx context.Context, opts *ListOptions) ([]*LongviewClient, error) { +func (c *Client) ListLongviewClients(ctx context.Context, opts *ListOptions) ([]LongviewClient, error) { response := LongviewClientsPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/longview_subscriptions.go b/longview_subscriptions.go index a62b6d302..816acd2a6 100644 --- a/longview_subscriptions.go +++ b/longview_subscriptions.go @@ -18,7 +18,7 @@ type LongviewSubscription struct { // LongviewSubscriptionsPagedResponse represents a paginated LongviewSubscription API response type LongviewSubscriptionsPagedResponse struct { *PageOptions - Data []*LongviewSubscription `json:"data"` + Data []LongviewSubscription `json:"data"` } // endpoint gets the endpoint URL for LongviewSubscription @@ -32,11 +32,11 @@ func (LongviewSubscriptionsPagedResponse) endpoint(c *Client) string { // appendData appends LongviewSubscriptions when processing paginated LongviewSubscription responses func (resp *LongviewSubscriptionsPagedResponse) appendData(r *LongviewSubscriptionsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListLongviewSubscriptions lists LongviewSubscriptions -func (c *Client) ListLongviewSubscriptions(ctx context.Context, opts *ListOptions) ([]*LongviewSubscription, error) { +func (c *Client) ListLongviewSubscriptions(ctx context.Context, opts *ListOptions) ([]LongviewSubscription, error) { response := LongviewSubscriptionsPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/network_ips.go b/network_ips.go index 73429a201..29b6f6b8e 100644 --- a/network_ips.go +++ b/network_ips.go @@ -8,7 +8,7 @@ import ( // IPAddressesPagedResponse represents a paginated IPAddress API response type IPAddressesPagedResponse struct { *PageOptions - Data []*InstanceIP `json:"data"` + Data []InstanceIP `json:"data"` } // endpoint gets the endpoint URL for IPAddress @@ -22,11 +22,11 @@ func (IPAddressesPagedResponse) endpoint(c *Client) string { // appendData appends IPAddresses when processing paginated InstanceIPAddress responses func (resp *IPAddressesPagedResponse) appendData(r *IPAddressesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListIPAddresses lists IPAddresses -func (c *Client) ListIPAddresses(ctx context.Context, opts *ListOptions) ([]*InstanceIP, error) { +func (c *Client) ListIPAddresses(ctx context.Context, opts *ListOptions) ([]InstanceIP, error) { response := IPAddressesPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/network_pools.go b/network_pools.go index 7fa7392b3..03085923c 100644 --- a/network_pools.go +++ b/network_pools.go @@ -8,7 +8,7 @@ import ( // IPv6PoolsPagedResponse represents a paginated IPv6Pool API response type IPv6PoolsPagedResponse struct { *PageOptions - Data []*IPv6Range `json:"data"` + Data []IPv6Range `json:"data"` } // endpoint gets the endpoint URL for IPv6Pool @@ -22,11 +22,11 @@ func (IPv6PoolsPagedResponse) endpoint(c *Client) string { // appendData appends IPv6Pools when processing paginated IPv6Pool responses func (resp *IPv6PoolsPagedResponse) appendData(r *IPv6PoolsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListIPv6Pools lists IPv6Pools -func (c *Client) ListIPv6Pools(ctx context.Context, opts *ListOptions) ([]*IPv6Range, error) { +func (c *Client) ListIPv6Pools(ctx context.Context, opts *ListOptions) ([]IPv6Range, error) { response := IPv6PoolsPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/network_ranges.go b/network_ranges.go index 0888c780e..0c0ba15a3 100644 --- a/network_ranges.go +++ b/network_ranges.go @@ -8,7 +8,7 @@ import ( // IPv6RangesPagedResponse represents a paginated IPv6Range API response type IPv6RangesPagedResponse struct { *PageOptions - Data []*IPv6Range `json:"data"` + Data []IPv6Range `json:"data"` } // endpoint gets the endpoint URL for IPv6Range @@ -22,11 +22,11 @@ func (IPv6RangesPagedResponse) endpoint(c *Client) string { // appendData appends IPv6Ranges when processing paginated IPv6Range responses func (resp *IPv6RangesPagedResponse) appendData(r *IPv6RangesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListIPv6Ranges lists IPv6Ranges -func (c *Client) ListIPv6Ranges(ctx context.Context, opts *ListOptions) ([]*IPv6Range, error) { +func (c *Client) ListIPv6Ranges(ctx context.Context, opts *ListOptions) ([]IPv6Range, error) { response := IPv6RangesPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/nodebalancer.go b/nodebalancer.go index bc6fc0a07..ce4eb790b 100644 --- a/nodebalancer.go +++ b/nodebalancer.go @@ -75,7 +75,7 @@ func (i NodeBalancer) GetUpdateOptions() NodeBalancerUpdateOptions { // NodeBalancersPagedResponse represents a paginated NodeBalancer API response type NodeBalancersPagedResponse struct { *PageOptions - Data []*NodeBalancer `json:"data"` + Data []NodeBalancer `json:"data"` } func (NodeBalancersPagedResponse) endpoint(c *Client) string { @@ -87,11 +87,11 @@ func (NodeBalancersPagedResponse) endpoint(c *Client) string { } func (resp *NodeBalancersPagedResponse) appendData(r *NodeBalancersPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListNodeBalancers lists NodeBalancers -func (c *Client) ListNodeBalancers(ctx context.Context, opts *ListOptions) ([]*NodeBalancer, error) { +func (c *Client) ListNodeBalancers(ctx context.Context, opts *ListOptions) ([]NodeBalancer, error) { response := NodeBalancersPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/nodebalancer_config_nodes.go b/nodebalancer_config_nodes.go index de9aaf4d6..08b1a9f9b 100644 --- a/nodebalancer_config_nodes.go +++ b/nodebalancer_config_nodes.go @@ -71,7 +71,7 @@ func (i NodeBalancerNode) GetUpdateOptions() NodeBalancerNodeUpdateOptions { // NodeBalancerNodesPagedResponse represents a paginated NodeBalancerNode API response type NodeBalancerNodesPagedResponse struct { *PageOptions - Data []*NodeBalancerNode `json:"data"` + Data []NodeBalancerNode `json:"data"` } // endpoint gets the endpoint URL for NodeBalancerNode @@ -85,11 +85,11 @@ func (NodeBalancerNodesPagedResponse) endpointWithTwoIDs(c *Client, nodebalancer // appendData appends NodeBalancerNodes when processing paginated NodeBalancerNode responses func (resp *NodeBalancerNodesPagedResponse) appendData(r *NodeBalancerNodesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListNodeBalancerNodes lists NodeBalancerNodes -func (c *Client) ListNodeBalancerNodes(ctx context.Context, nodebalancerID int, configID int, opts *ListOptions) ([]*NodeBalancerNode, error) { +func (c *Client) ListNodeBalancerNodes(ctx context.Context, nodebalancerID int, configID int, opts *ListOptions) ([]NodeBalancerNode, error) { response := NodeBalancerNodesPagedResponse{} err := c.listHelperWithTwoIDs(ctx, &response, nodebalancerID, configID, opts) for _, el := range response.Data { diff --git a/nodebalancer_configs.go b/nodebalancer_configs.go index babbcb35f..290c1d62c 100644 --- a/nodebalancer_configs.go +++ b/nodebalancer_configs.go @@ -149,7 +149,7 @@ func (i NodeBalancerConfig) GetUpdateOptions() NodeBalancerConfigUpdateOptions { // NodeBalancerConfigsPagedResponse represents a paginated NodeBalancerConfig API response type NodeBalancerConfigsPagedResponse struct { *PageOptions - Data []*NodeBalancerConfig `json:"data"` + Data []NodeBalancerConfig `json:"data"` } // endpointWithID gets the endpoint URL for NodeBalancerConfig @@ -163,11 +163,11 @@ func (NodeBalancerConfigsPagedResponse) endpointWithID(c *Client, id int) string // appendData appends NodeBalancerConfigs when processing paginated NodeBalancerConfig responses func (resp *NodeBalancerConfigsPagedResponse) appendData(r *NodeBalancerConfigsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListNodeBalancerConfigs lists NodeBalancerConfigs -func (c *Client) ListNodeBalancerConfigs(ctx context.Context, nodebalancerID int, opts *ListOptions) ([]*NodeBalancerConfig, error) { +func (c *Client) ListNodeBalancerConfigs(ctx context.Context, nodebalancerID int, opts *ListOptions) ([]NodeBalancerConfig, error) { response := NodeBalancerConfigsPagedResponse{} err := c.listHelperWithID(ctx, &response, nodebalancerID, opts) for _, el := range response.Data { diff --git a/regions.go b/regions.go index 7e45e26f2..d9c8e317e 100644 --- a/regions.go +++ b/regions.go @@ -14,7 +14,7 @@ type Region struct { // RegionsPagedResponse represents a linode API response for listing type RegionsPagedResponse struct { *PageOptions - Data []*Region `json:"data"` + Data []Region `json:"data"` } // endpoint gets the endpoint URL for Region @@ -28,11 +28,11 @@ func (RegionsPagedResponse) endpoint(c *Client) string { // appendData appends Regions when processing paginated Region responses func (resp *RegionsPagedResponse) appendData(r *RegionsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListRegions lists Regions -func (c *Client) ListRegions(ctx context.Context, opts *ListOptions) ([]*Region, error) { +func (c *Client) ListRegions(ctx context.Context, opts *ListOptions) ([]Region, error) { response := RegionsPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/stackscripts.go b/stackscripts.go index eb76e3e56..2dd9e82a0 100644 --- a/stackscripts.go +++ b/stackscripts.go @@ -89,7 +89,7 @@ func (i Stackscript) GetUpdateOptions() StackscriptUpdateOptions { // StackscriptsPagedResponse represents a paginated Stackscript API response type StackscriptsPagedResponse struct { *PageOptions - Data []*Stackscript `json:"data"` + Data []Stackscript `json:"data"` } // endpoint gets the endpoint URL for Stackscript @@ -103,11 +103,11 @@ func (StackscriptsPagedResponse) endpoint(c *Client) string { // appendData appends Stackscripts when processing paginated Stackscript responses func (resp *StackscriptsPagedResponse) appendData(r *StackscriptsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListStackscripts lists Stackscripts -func (c *Client) ListStackscripts(ctx context.Context, opts *ListOptions) ([]*Stackscript, error) { +func (c *Client) ListStackscripts(ctx context.Context, opts *ListOptions) ([]Stackscript, error) { response := StackscriptsPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/support.go b/support.go index 88392ca4c..6c72a4adf 100644 --- a/support.go +++ b/support.go @@ -43,7 +43,7 @@ const ( // TicketsPagedResponse represents a paginated ticket API response type TicketsPagedResponse struct { *PageOptions - Data []*Ticket `json:"data"` + Data []Ticket `json:"data"` } func (TicketsPagedResponse) endpoint(c *Client) string { @@ -55,14 +55,14 @@ func (TicketsPagedResponse) endpoint(c *Client) string { } func (resp *TicketsPagedResponse) appendData(r *TicketsPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListTickets returns a collection of Support Tickets on the Account. Support Tickets // can be both tickets opened with Linode for support, as well as tickets generated by // Linode regarding the Account. This collection includes all Support Tickets generated // on the Account, with open tickets returned first. -func (c *Client) ListTickets(ctx context.Context, opts *ListOptions) ([]*Ticket, error) { +func (c *Client) ListTickets(ctx context.Context, opts *ListOptions) ([]Ticket, error) { response := TicketsPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/template.go b/template.go index fe215b5f6..f88670177 100644 --- a/template.go +++ b/template.go @@ -46,7 +46,7 @@ func (i Template) GetUpdateOptions() (o TemplateCreateOptions) { // TemplatesPagedResponse represents a paginated Template API response type TemplatesPagedResponse struct { *PageOptions - Data []*Template `json:"data"` + Data []Template `json:"data"` } // endpoint gets the endpoint URL for Template @@ -60,11 +60,11 @@ func (TemplatesPagedResponse) endpoint(c *Client) string { // appendData appends Templates when processing paginated Template responses func (resp *TemplatesPagedResponse) appendData(r *TemplatesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListTemplates lists Templates -func (c *Client) ListTemplates(ctx context.Context, opts *ListOptions) ([]*Template, error) { +func (c *Client) ListTemplates(ctx context.Context, opts *ListOptions) ([]Template, error) { response := TemplatesPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/types.go b/types.go index d87e92af7..edeada84a 100644 --- a/types.go +++ b/types.go @@ -48,7 +48,7 @@ const ( // LinodeTypesPagedResponse represents a linode types API response for listing type LinodeTypesPagedResponse struct { *PageOptions - Data []*LinodeType `json:"data"` + Data []LinodeType `json:"data"` } func (LinodeTypesPagedResponse) endpoint(c *Client) string { @@ -60,11 +60,11 @@ func (LinodeTypesPagedResponse) endpoint(c *Client) string { } func (resp *LinodeTypesPagedResponse) appendData(r *LinodeTypesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListTypes lists linode types -func (c *Client) ListTypes(ctx context.Context, opts *ListOptions) ([]*LinodeType, error) { +func (c *Client) ListTypes(ctx context.Context, opts *ListOptions) ([]LinodeType, error) { response := LinodeTypesPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { diff --git a/volumes.go b/volumes.go index 6f00df96c..98e165775 100644 --- a/volumes.go +++ b/volumes.go @@ -59,7 +59,7 @@ type VolumeAttachOptions struct { // VolumesPagedResponse represents a linode API response for listing of volumes type VolumesPagedResponse struct { *PageOptions - Data []*Volume `json:"data"` + Data []Volume `json:"data"` } // endpoint gets the endpoint URL for Volume @@ -73,11 +73,11 @@ func (VolumesPagedResponse) endpoint(c *Client) string { // appendData appends Volumes when processing paginated Volume responses func (resp *VolumesPagedResponse) appendData(r *VolumesPagedResponse) { - (*resp).Data = append(resp.Data, r.Data...) + resp.Data = append(resp.Data, r.Data...) } // ListVolumes lists Volumes -func (c *Client) ListVolumes(ctx context.Context, opts *ListOptions) ([]*Volume, error) { +func (c *Client) ListVolumes(ctx context.Context, opts *ListOptions) ([]Volume, error) { response := VolumesPagedResponse{} err := c.listHelper(ctx, &response, opts) for _, el := range response.Data { diff --git a/waitfor.go b/waitfor.go index 420423da8..d213efd96 100644 --- a/waitfor.go +++ b/waitfor.go @@ -219,12 +219,12 @@ func (client Client) WaitForEventFinished(ctx context.Context, id interface{}, e } if event.Status == EventFailed { - return event, fmt.Errorf("%s %v action %s failed", titledEntityType, id, action) + return &event, fmt.Errorf("%s %v action %s failed", titledEntityType, id, action) } else if event.Status == EventScheduled { log.Printf("[INFO] %s %v action %s is scheduled", titledEntityType, id, action) } else if event.Status == EventFinished { log.Printf("[INFO] %s %v action %s is finished", titledEntityType, id, action) - return event, nil + return &event, nil } log.Printf("[INFO] %s %v action %s is %s", titledEntityType, id, action, event.Status) } From e35f7b576a58c13cb39d3c1c272c7c801359ea4b Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Thu, 6 Sep 2018 14:37:09 -0400 Subject: [PATCH 08/18] warn when encountering Event with nil Created --- .travis.yml | 2 +- waitfor.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 272f1b172..4ffecc4c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ install: script: - touch .env - - make test ARGS='-coverprofile=coverage.txt -covermode=atomic' + - make test ARGS='-v -race -count=2 -coverprofile=coverage.txt -covermode=atomic ./...' - gometalinter.v2 --enable-all --disable=vetshadow --disable=gocyclo --disable=unparam --disable=nakedret --disable=lll --disable=dupl --disable=gochecknoinits --disable=gochecknoglobals --disable=test --deadline=120s - gometalinter.v2 --disable-all --enable=vetshadow --enable=gocyclo --enable=unparam --enable=nakedret --enable=lll --enable=dupl --enable=gochecknoinits --enable=gochecknoglobals --deadline=120s || true diff --git a/waitfor.go b/waitfor.go index d213efd96..d36da2ed2 100644 --- a/waitfor.go +++ b/waitfor.go @@ -211,7 +211,11 @@ func (client Client) WaitForEventFinished(ctx context.Context, id interface{}, e continue } - if *event.Created != minStart && !event.Created.After(minStart) { + // @TODO(displague) This event.Created check shouldn't be needed, but it appears + // that the ListEvents method is not populating it correctly + if event.Created == nil { + log.Printf("[WARN] event.Created is nil when API returned: %#+v", event.CreatedStr) + } else if *event.Created != minStart && !event.Created.After(minStart) { // Not the event we were looking for // log.Println(event.Created, "is not >=", minStart) continue From fac5aa13fcee27adf88de1391bdfafeb05accbab Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Thu, 6 Sep 2018 14:57:44 -0400 Subject: [PATCH 09/18] test that multipaged results ran fixDates --- example_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example_test.go b/example_test.go index 7d1e2fd1a..a8070d36d 100644 --- a/example_test.go +++ b/example_test.go @@ -277,10 +277,12 @@ func ExampleClient_ListStackscripts_page1() { fmt.Println("Pages > 1:", filterOpt.Pages > 1) s := scripts[len(scripts)-1] fmt.Println("StackScript Script has shebang:", strings.Contains(s.Script, "#!/")) + fmt.Println("Created is parsed:", s.Created != nil) // Output: // Fetched == 100: true // Results > 100: true // Pages > 1: true // StackScript Script has shebang: true + // Created is parsed: true } From 033e138585bc518eee0eb5a2924f8df3dd0a67a1 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Thu, 6 Sep 2018 15:49:10 -0400 Subject: [PATCH 10/18] apply fixDates in-place on List results --- account_events.go | 4 ++-- account_invoices.go | 8 ++++---- account_notifications.go | 4 ++-- images.go | 4 ++-- instance_configs.go | 4 ++-- instance_disks.go | 4 ++-- instance_snapshots.go | 4 ++-- instance_volumes.go | 4 ++-- instances.go | 4 ++-- longview.go | 4 ++-- longview_subscriptions.go | 4 ++-- nodebalancer_config_nodes.go | 4 ++-- nodebalancer_configs.go | 4 ++-- regions.go | 4 ++-- stackscripts.go | 4 ++-- template.go | 4 ++-- volumes.go | 4 ++-- 17 files changed, 36 insertions(+), 36 deletions(-) diff --git a/account_events.go b/account_events.go index d1cbab4bc..44540e40a 100644 --- a/account_events.go +++ b/account_events.go @@ -174,8 +174,8 @@ func (resp *EventsPagedResponse) appendData(r *EventsPagedResponse) { func (c *Client) ListEvents(ctx context.Context, opts *ListOptions) ([]Event, error) { response := EventsPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/account_invoices.go b/account_invoices.go index 22b9fcc18..75ca2f73d 100644 --- a/account_invoices.go +++ b/account_invoices.go @@ -54,8 +54,8 @@ func (resp *InvoicesPagedResponse) appendData(r *InvoicesPagedResponse) { func (c *Client) ListInvoices(ctx context.Context, opts *ListOptions) ([]Invoice, error) { response := InvoicesPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err @@ -115,8 +115,8 @@ func (resp *InvoiceItemsPagedResponse) appendData(r *InvoiceItemsPagedResponse) func (c *Client) ListInvoiceItems(ctx context.Context, id int, opts *ListOptions) ([]InvoiceItem, error) { response := InvoiceItemsPagedResponse{} err := c.listHelperWithID(ctx, &response, id, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/account_notifications.go b/account_notifications.go index 59504dae8..6b63e3850 100644 --- a/account_notifications.go +++ b/account_notifications.go @@ -56,8 +56,8 @@ func (resp *NotificationsPagedResponse) appendData(r *NotificationsPagedResponse func (c *Client) ListNotifications(ctx context.Context, opts *ListOptions) ([]Notification, error) { response := NotificationsPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/images.go b/images.go index 1ed99fa3d..91ab57bb9 100644 --- a/images.go +++ b/images.go @@ -73,8 +73,8 @@ func (resp *ImagesPagedResponse) appendData(r *ImagesPagedResponse) { func (c *Client) ListImages(ctx context.Context, opts *ListOptions) ([]Image, error) { response := ImagesPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/instance_configs.go b/instance_configs.go index 3980e8fbc..ab3643935 100644 --- a/instance_configs.go +++ b/instance_configs.go @@ -140,8 +140,8 @@ func (resp *InstanceConfigsPagedResponse) appendData(r *InstanceConfigsPagedResp func (c *Client) ListInstanceConfigs(ctx context.Context, linodeID int, opts *ListOptions) ([]InstanceConfig, error) { response := InstanceConfigsPagedResponse{} err := c.listHelperWithID(ctx, &response, linodeID, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/instance_disks.go b/instance_disks.go index b6734fed0..c8f6392d7 100644 --- a/instance_disks.go +++ b/instance_disks.go @@ -79,8 +79,8 @@ func (resp *InstanceDisksPagedResponse) appendData(r *InstanceDisksPagedResponse func (c *Client) ListInstanceDisks(ctx context.Context, linodeID int, opts *ListOptions) ([]InstanceDisk, error) { response := InstanceDisksPagedResponse{} err := c.listHelperWithID(ctx, &response, linodeID, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/instance_snapshots.go b/instance_snapshots.go index 8e2932e11..7933507dc 100644 --- a/instance_snapshots.go +++ b/instance_snapshots.go @@ -178,8 +178,8 @@ func (l *InstanceBackupSnapshotResponse) fixDates() *InstanceBackupSnapshotRespo } func (l *InstanceBackupsResponse) fixDates() *InstanceBackupsResponse { - for _, el := range l.Automatic { - el.fixDates() + for i := range l.Automatic { + l.Automatic[i].fixDates() } if l.Snapshot != nil { l.Snapshot.fixDates() diff --git a/instance_volumes.go b/instance_volumes.go index f27268628..b6c9a9ae0 100644 --- a/instance_volumes.go +++ b/instance_volumes.go @@ -28,8 +28,8 @@ func (resp *InstanceVolumesPagedResponse) appendData(r *InstanceVolumesPagedResp func (c *Client) ListInstanceVolumes(ctx context.Context, linodeID int, opts *ListOptions) ([]Volume, error) { response := InstanceVolumesPagedResponse{} err := c.listHelperWithID(ctx, &response, linodeID, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/instances.go b/instances.go index 5a92c19fb..ba081b665 100644 --- a/instances.go +++ b/instances.go @@ -152,8 +152,8 @@ func (resp *InstancesPagedResponse) appendData(r *InstancesPagedResponse) { func (c *Client) ListInstances(ctx context.Context, opts *ListOptions) ([]Instance, error) { response := InstancesPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/longview.go b/longview.go index 70508f967..524af6776 100644 --- a/longview.go +++ b/longview.go @@ -36,8 +36,8 @@ func (resp *LongviewClientsPagedResponse) appendData(r *LongviewClientsPagedResp func (c *Client) ListLongviewClients(ctx context.Context, opts *ListOptions) ([]LongviewClient, error) { response := LongviewClientsPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/longview_subscriptions.go b/longview_subscriptions.go index 816acd2a6..253316599 100644 --- a/longview_subscriptions.go +++ b/longview_subscriptions.go @@ -39,8 +39,8 @@ func (resp *LongviewSubscriptionsPagedResponse) appendData(r *LongviewSubscripti func (c *Client) ListLongviewSubscriptions(ctx context.Context, opts *ListOptions) ([]LongviewSubscription, error) { response := LongviewSubscriptionsPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/nodebalancer_config_nodes.go b/nodebalancer_config_nodes.go index 08b1a9f9b..e1ca55cb5 100644 --- a/nodebalancer_config_nodes.go +++ b/nodebalancer_config_nodes.go @@ -92,8 +92,8 @@ func (resp *NodeBalancerNodesPagedResponse) appendData(r *NodeBalancerNodesPaged func (c *Client) ListNodeBalancerNodes(ctx context.Context, nodebalancerID int, configID int, opts *ListOptions) ([]NodeBalancerNode, error) { response := NodeBalancerNodesPagedResponse{} err := c.listHelperWithTwoIDs(ctx, &response, nodebalancerID, configID, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/nodebalancer_configs.go b/nodebalancer_configs.go index 290c1d62c..422fc3612 100644 --- a/nodebalancer_configs.go +++ b/nodebalancer_configs.go @@ -170,8 +170,8 @@ func (resp *NodeBalancerConfigsPagedResponse) appendData(r *NodeBalancerConfigsP func (c *Client) ListNodeBalancerConfigs(ctx context.Context, nodebalancerID int, opts *ListOptions) ([]NodeBalancerConfig, error) { response := NodeBalancerConfigsPagedResponse{} err := c.listHelperWithID(ctx, &response, nodebalancerID, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/regions.go b/regions.go index d9c8e317e..b13b996ea 100644 --- a/regions.go +++ b/regions.go @@ -35,8 +35,8 @@ func (resp *RegionsPagedResponse) appendData(r *RegionsPagedResponse) { func (c *Client) ListRegions(ctx context.Context, opts *ListOptions) ([]Region, error) { response := RegionsPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/stackscripts.go b/stackscripts.go index 2dd9e82a0..daf339b2f 100644 --- a/stackscripts.go +++ b/stackscripts.go @@ -110,8 +110,8 @@ func (resp *StackscriptsPagedResponse) appendData(r *StackscriptsPagedResponse) func (c *Client) ListStackscripts(ctx context.Context, opts *ListOptions) ([]Stackscript, error) { response := StackscriptsPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/template.go b/template.go index f88670177..426a77915 100644 --- a/template.go +++ b/template.go @@ -67,8 +67,8 @@ func (resp *TemplatesPagedResponse) appendData(r *TemplatesPagedResponse) { func (c *Client) ListTemplates(ctx context.Context, opts *ListOptions) ([]Template, error) { response := TemplatesPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err diff --git a/volumes.go b/volumes.go index 98e165775..eef492d83 100644 --- a/volumes.go +++ b/volumes.go @@ -80,8 +80,8 @@ func (resp *VolumesPagedResponse) appendData(r *VolumesPagedResponse) { func (c *Client) ListVolumes(ctx context.Context, opts *ListOptions) ([]Volume, error) { response := VolumesPagedResponse{} err := c.listHelper(ctx, &response, opts) - for _, el := range response.Data { - el.fixDates() + for i := range response.Data { + response.Data[i].fixDates() } if err != nil { return nil, err From ff5f45ea422f7755c77ba6e715bce2ae82a65c20 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Fri, 7 Sep 2018 11:04:28 -0400 Subject: [PATCH 11/18] feature: add support for SSHKeys --- API_SUPPORT.md | 50 +++++++ client.go | 5 +- fixtures/TestGetSSHKey_found.yaml | 220 +++++++++++++++++++++++++++ fixtures/TestGetSSHKey_missing.yaml | 59 ++++++++ fixtures/TestListSSHKey.yaml | 221 ++++++++++++++++++++++++++++ fixtures/TestUpdateSSHKey.yaml | 218 +++++++++++++++++++++++++++ pagination.go | 10 ++ profile_sshkeys.go | 162 ++++++++++++++++++++ profile_sshkeys_test.go | 132 +++++++++++++++++ resources.go | 2 + template.go | 14 +- 11 files changed, 1087 insertions(+), 6 deletions(-) create mode 100644 fixtures/TestGetSSHKey_found.yaml create mode 100644 fixtures/TestGetSSHKey_missing.yaml create mode 100644 fixtures/TestListSSHKey.yaml create mode 100644 fixtures/TestUpdateSSHKey.yaml create mode 100644 profile_sshkeys.go create mode 100644 profile_sshkeys_test.go diff --git a/API_SUPPORT.md b/API_SUPPORT.md index 09778f444..60e9e5ee0 100644 --- a/API_SUPPORT.md +++ b/API_SUPPORT.md @@ -289,6 +289,56 @@ - `/account/users/$username/password` - [ ] `POST` +## Profile + +### Personalized User Settings + +- `/profile` + - [ ] `GET` + - [ ] `PUT` + +### Granted OAuth Apps + +- `/profile/apps` + - [ ] `GET` +- `/profile/apps/$id` + - [ ] `GET` + - [ ] `DELETE` + +### Grants to Linode Resources + +- `/profile/grants` + - [ ] `GET` + +### SSH Keys + +- `/profile/sshkeys` + - [x] `GET` + - [x] `POST` +- `/profile/sshkeys/$id` + - [x] `GET` + - [x] `PUT` + - [x] `DELETE` + +### Two-Factor + +- `/profile/tfa-disable` + - [ ] `POST` +- `/profile/tfa-enable` + - [ ] `POST` +- `/profile/tfa-enable-confirm` + - [ ] `POST` + +### Personal Access API Tokens + +- `/profile/tokens` + - [ ] `GET` + - [ ] `POST` +- `/profile/tokens/$id` + - [ ] `GET` + - [ ] `PUT` + - [ ] `DELETE` + ## Images - `/images` diff --git a/client.go b/client.go index 5a96ddb95..3d0aec4f6 100644 --- a/client.go +++ b/client.go @@ -19,7 +19,7 @@ const ( // APIProto connect to API with http(s) APIProto = "https" // Version of linodego - Version = "0.4.0" + Version = "0.5.0" // APIEnvVar environment var to check for API token APIEnvVar = "LINODE_TOKEN" // APISecondsPerPoll how frequently to poll for new Events @@ -61,6 +61,7 @@ type Client struct { NodeBalancers *Resource NodeBalancerConfigs *Resource NodeBalancerNodes *Resource + SSHKeys *Resource Tickets *Resource Account *Resource Invoices *Resource @@ -154,6 +155,7 @@ func NewClient(hc *http.Client) (client Client) { nodebalancersName: NewResource(&client, nodebalancersName, nodebalancersEndpoint, false, NodeBalancer{}, NodeBalancerConfigsPagedResponse{}), nodebalancerconfigsName: NewResource(&client, nodebalancerconfigsName, nodebalancerconfigsEndpoint, true, NodeBalancerConfig{}, NodeBalancerConfigsPagedResponse{}), nodebalancernodesName: NewResource(&client, nodebalancernodesName, nodebalancernodesEndpoint, true, NodeBalancerNode{}, NodeBalancerNodesPagedResponse{}), + sshkeysName: NewResource(&client, sshkeysName, sshkeysEndpoint, false, SSHKey{}, SSHKeysPagedResponse{}), ticketsName: NewResource(&client, ticketsName, ticketsEndpoint, false, Ticket{}, TicketsPagedResponse{}), accountName: NewResource(&client, accountName, accountEndpoint, false, Account{}, nil), // really? eventsName: NewResource(&client, eventsName, eventsEndpoint, false, Event{}, EventsPagedResponse{}), @@ -188,6 +190,7 @@ func NewClient(hc *http.Client) (client Client) { client.NodeBalancers = resources[nodebalancersName] client.NodeBalancerConfigs = resources[nodebalancerconfigsName] client.NodeBalancerNodes = resources[nodebalancernodesName] + client.SSHKeys = resources[sshkeysName] client.Tickets = resources[ticketsName] client.Account = resources[accountName] client.Events = resources[eventsName] diff --git a/fixtures/TestGetSSHKey_found.yaml b/fixtures/TestGetSSHKey_found.yaml new file mode 100644 index 000000000..d54dbaef4 --- /dev/null +++ b/fixtures/TestGetSSHKey_found.yaml @@ -0,0 +1,220 @@ +--- +version: 1 +interactions: +- request: + body: '{"label":"lpq6h62z88m4-linodego-testing","ssh_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys + method: POST + response: + body: '{"id": 43, "ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing", "label": "lpq6h62z88m4-linodego-testing", "created": + "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "511" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332646" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys/43 + method: GET + response: + body: '{"ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing", "id": 43, "created": "2018-01-02T03:04:05", + "label": "lpq6h62z88m4-linodego-testing"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "511" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_only + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332647" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys/43 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332647" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/fixtures/TestGetSSHKey_missing.yaml b/fixtures/TestGetSSHKey_missing.yaml new file mode 100644 index 000000000..fa798b644 --- /dev/null +++ b/fixtures/TestGetSSHKey_missing.yaml @@ -0,0 +1,59 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys/123 + method: GET + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + Connection: + - keep-alive + Content-Length: + - "37" + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:06 GMT + Retry-After: + - "119" + Server: + - nginx + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_only + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332646" + X-Spec-Version: + - 4.0.4 + status: 404 NOT FOUND + code: 404 + duration: "" diff --git a/fixtures/TestListSSHKey.yaml b/fixtures/TestListSSHKey.yaml new file mode 100644 index 000000000..fabbfdb74 --- /dev/null +++ b/fixtures/TestListSSHKey.yaml @@ -0,0 +1,221 @@ +--- +version: 1 +interactions: +- request: + body: '{"label":"lpq6h62z88m4-linodego-testing","ssh_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys + method: POST + response: + body: '{"id": 45, "ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing", "label": "lpq6h62z88m4-linodego-testing", "created": + "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "511" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332647" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys + method: GET + response: + body: '{"data": [{"ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing", "id": 45, "created": "2018-01-02T03:04:05", + "label": "lpq6h62z88m4-linodego-testing"}], "pages": 1, "page": 1, "results": + 1}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "560" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:08 GMT + Retry-After: + - "118" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_only + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536332647" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys/45 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:08 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332648" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/fixtures/TestUpdateSSHKey.yaml b/fixtures/TestUpdateSSHKey.yaml new file mode 100644 index 000000000..124ddbfae --- /dev/null +++ b/fixtures/TestUpdateSSHKey.yaml @@ -0,0 +1,218 @@ +--- +version: 1 +interactions: +- request: + body: '{"label":"lpq6h62z88m4-linodego-testing","ssh_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys + method: POST + response: + body: '{"label": "lpq6h62z88m4-linodego-testing", "id": 44, "ssh_key": "ssh-rsa + AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing", "created": "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "511" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332647" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"lpq6h62z88m4-linodego-testing_r"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys/44 + method: PUT + response: + body: '{"label": "lpq6h62z88m4-linodego-testing_r", "id": 44, "ssh_key": "ssh-rsa + AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X + lpq6h62z88m4-linodego-testing", "created": "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "513" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536332647" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.5.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/profile/sshkeys/44 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Fri, 07 Sep 2018 15:02:07 GMT + Retry-After: + - "118" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - account:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536332646" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/pagination.go b/pagination.go index 7c0627a54..a9b73d196 100644 --- a/pagination.go +++ b/pagination.go @@ -145,6 +145,16 @@ func (c *Client) listHelper(ctx context.Context, i interface{}, opts *ListOption v.appendData(r.Result().(*IPv6RangesPagedResponse)) // @TODO consolidate this type with IPv6PoolsPagedResponse? } + case *SSHKeysPagedResponse: + if r, err = coupleAPIErrors(req.SetResult(SSHKeysPagedResponse{}).Get(v.endpoint(c))); err == nil { + response, ok := r.Result().(*SSHKeysPagedResponse) + if !ok { + return fmt.Errorf("Response is not a *SSHKeysPagedResponse") + } + pages = response.Pages + results = response.Results + v.appendData(response) + } case *TicketsPagedResponse: if r, err = coupleAPIErrors(req.SetResult(TicketsPagedResponse{}).Get(v.endpoint(c))); err == nil { pages = r.Result().(*TicketsPagedResponse).Pages diff --git a/profile_sshkeys.go b/profile_sshkeys.go new file mode 100644 index 000000000..c6e20aed4 --- /dev/null +++ b/profile_sshkeys.go @@ -0,0 +1,162 @@ +package linodego + +import ( + "context" + "encoding/json" + "fmt" + "time" +) + +// SSHKey represents a SSHKey object +type SSHKey struct { + ID int `json:"id"` + Label string `json:"label"` + SSHKey string `json:"ssh_key"` + CreatedStr string `json:"created"` + Created *time.Time `json:"-"` +} + +// SSHKeyCreateOptions fields are those accepted by CreateSSHKey +type SSHKeyCreateOptions struct { + Label string `json:"label"` + SSHKey string `json:"ssh_key"` +} + +// SSHKeyUpdateOptions fields are those accepted by UpdateSSHKey +type SSHKeyUpdateOptions struct { + Label string `json:"label"` +} + +// GetCreateOptions converts a SSHKey to SSHKeyCreateOptions for use in CreateSSHKey +func (i SSHKey) GetCreateOptions() (o SSHKeyCreateOptions) { + o.Label = i.Label + o.SSHKey = i.SSHKey + return +} + +// GetUpdateOptions converts a SSHKey to SSHKeyCreateOptions for use in UpdateSSHKey +func (i SSHKey) GetUpdateOptions() (o SSHKeyUpdateOptions) { + o.Label = i.Label + return +} + +// SSHKeysPagedResponse represents a paginated SSHKey API response +type SSHKeysPagedResponse struct { + *PageOptions + Data []SSHKey `json:"data"` +} + +// endpoint gets the endpoint URL for SSHKey +func (SSHKeysPagedResponse) endpoint(c *Client) string { + endpoint, err := c.SSHKeys.Endpoint() + if err != nil { + panic(err) + } + return endpoint +} + +// appendData appends SSHKeys when processing paginated SSHKey responses +func (resp *SSHKeysPagedResponse) appendData(r *SSHKeysPagedResponse) { + resp.Data = append(resp.Data, r.Data...) +} + +// ListSSHKeys lists SSHKeys +func (c *Client) ListSSHKeys(ctx context.Context, opts *ListOptions) ([]SSHKey, error) { + response := SSHKeysPagedResponse{} + err := c.listHelper(ctx, &response, opts) + for i := range response.Data { + response.Data[i].fixDates() + } + if err != nil { + return nil, err + } + return response.Data, nil +} + +// fixDates converts JSON timestamps to Go time.Time values +func (i *SSHKey) fixDates() *SSHKey { + i.Created, _ = parseDates(i.CreatedStr) + return i +} + +// GetSSHKey gets the sshkey with the provided ID +func (c *Client) GetSSHKey(ctx context.Context, id int) (*SSHKey, error) { + e, err := c.SSHKeys.Endpoint() + if err != nil { + return nil, err + } + e = fmt.Sprintf("%s/%d", e, id) + r, err := coupleAPIErrors(c.R(ctx).SetResult(&SSHKey{}).Get(e)) + if err != nil { + return nil, err + } + return r.Result().(*SSHKey).fixDates(), nil +} + +// CreateSSHKey creates a SSHKey +func (c *Client) CreateSSHKey(ctx context.Context, createOpts SSHKeyCreateOptions) (*SSHKey, error) { + var body string + e, err := c.SSHKeys.Endpoint() + if err != nil { + return nil, err + } + + req := c.R(ctx).SetResult(&SSHKey{}) + + if bodyData, err := json.Marshal(createOpts); err == nil { + body = string(bodyData) + } else { + return nil, NewError(err) + } + + r, err := coupleAPIErrors(req. + SetBody(body). + Post(e)) + + if err != nil { + return nil, err + } + return r.Result().(*SSHKey).fixDates(), nil +} + +// UpdateSSHKey updates the SSHKey with the specified id +func (c *Client) UpdateSSHKey(ctx context.Context, id int, updateOpts SSHKeyUpdateOptions) (*SSHKey, error) { + var body string + e, err := c.SSHKeys.Endpoint() + if err != nil { + return nil, err + } + e = fmt.Sprintf("%s/%d", e, id) + + req := c.R(ctx).SetResult(&SSHKey{}) + + if bodyData, err := json.Marshal(updateOpts); err == nil { + body = string(bodyData) + } else { + return nil, NewError(err) + } + + r, err := coupleAPIErrors(req. + SetBody(body). + Put(e)) + + if err != nil { + return nil, err + } + return r.Result().(*SSHKey).fixDates(), nil +} + +// DeleteSSHKey deletes the SSHKey with the specified id +func (c *Client) DeleteSSHKey(ctx context.Context, id int) error { + e, err := c.SSHKeys.Endpoint() + if err != nil { + return err + } + e = fmt.Sprintf("%s/%d", e, id) + + if _, err := coupleAPIErrors(c.R(ctx).Delete(e)); err != nil { + return err + } + + return nil +} diff --git a/profile_sshkeys_test.go b/profile_sshkeys_test.go new file mode 100644 index 000000000..8647ceeb5 --- /dev/null +++ b/profile_sshkeys_test.go @@ -0,0 +1,132 @@ +package linodego_test + +import ( + "context" + "strings" + + . "github.com/linode/linodego" + + "testing" +) + +var ( + testSSHKeyCreateOpts = SSHKeyCreateOptions{ + Label: label, + SSHKey: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYlv4Ns3tY2NEseuuMXEz1sLzO9sGC0cwaT2ECbWFyrsn1Fg5ISdkaJD8LiuhZ41/1Mh0Sq49wY89yLkmw+Ukrd+thFbhUqTzjL09U89kn3Ds/ajVJgwnJ4pXmBqhq0/3pmO/UkYIBi5ErTnPWL+yHAoQ1HsVetxYUmY2SPaT0pduDIrvNZRvWn3Nvn9qsUVfthWiGc8oHWE5xyd7+3UPLHSMkE4rZd2k6e7bJWCM/VJ7ZrJQ6UVTDXjBCkkT12WsOWxcEuL36RUGgGa4h5M4IY0SkgQSKHer01dJSj3c6OBzj2CRDZFoM8f/YC66s0+ZQ9cE/aADDycMIvqOJBI6X " + label, + } +) + +func TestGetSSHKey_missing(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestGetSSHKey_missing") + defer teardown() + + notfoundID := 123 + i, err := client.GetSSHKey(context.Background(), notfoundID) + if err == nil { + t.Errorf("should have received an error requesting a missing sshkey, got %v", i) + } + e, ok := err.(*Error) + if !ok { + t.Errorf("should have received an Error requesting a missing sshkey, got %v", e) + } + + if e.Code != 404 { + t.Errorf("should have received a 404 Code requesting a missing sshkey, got %v", e.Code) + } +} + +func TestGetSSHKey_found(t *testing.T) { + client, sshkey, teardown, err := setupSSHKey(t, "fixtures/TestGetSSHKey_found") + defer teardown() + + i, err := client.GetSSHKey(context.Background(), sshkey.ID) + if err != nil { + t.Errorf("Error getting sshkey, expected struct, got %v and error %v", i, err) + } + if i.ID != sshkey.ID { + t.Errorf("Expected sshkey id %d, but got %d", i.ID, sshkey.ID) + } + if testSSHKeyCreateOpts.Label != sshkey.Label { + t.Errorf("Expected sshkey label '%s', but got '%s'", testSSHKeyCreateOpts.Label, sshkey.Label) + } + if testSSHKeyCreateOpts.SSHKey != sshkey.SSHKey { + t.Errorf("Expected sshkey sshkey, but got a different one") + } +} + +func TestUpdateSSHKey(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + client, sshkey, teardown, err := setupSSHKey(t, "fixtures/TestUpdateSSHKey") + defer teardown() + if err != nil { + t.Error(err) + } + + renamedLabel := sshkey.Label + "_r" + updateOpts := SSHKeyUpdateOptions{ + Label: renamedLabel, + } + sshkey, err = client.UpdateSSHKey(context.Background(), sshkey.ID, updateOpts) + + if err != nil { + t.Errorf("Error renaming sshkey, %s", err) + } + + if !strings.Contains(sshkey.Label, "-linodego-testing_r") { + t.Errorf("sshkey returned does not match sshkey update request") + } +} + +func TestListSSHKeys(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + client, sshkey, teardown, err := setupSSHKey(t, "fixtures/TestListSSHKey") + defer teardown() + if err != nil { + t.Error(err) + } + + sshkeys, err := client.ListSSHKeys(context.Background(), nil) + if err != nil { + t.Errorf("Error listing sshkeys, expected struct, got error %v", err) + } + if len(sshkeys) == 0 { + t.Errorf("Expected a list of sshkeys, but got %v", sshkeys) + } + notFound := true + for i := range sshkeys { + if sshkeys[i].Label == sshkey.Label { + notFound = false + + if sshkeys[i].Created == nil { + t.Errorf("Expected listed sshkeys to have parsed Created") + } + break + } + } + if notFound { + t.Errorf("Expected to find created sshkey, but '%s' was not found", sshkey.Label) + } +} + +func setupSSHKey(t *testing.T, fixturesYaml string) (*Client, *SSHKey, func(), error) { + t.Helper() + var fixtureTeardown func() + client, fixtureTeardown := createTestClient(t, fixturesYaml) + createOpts := testSSHKeyCreateOpts + sshkey, err := client.CreateSSHKey(context.Background(), createOpts) + if err != nil { + t.Errorf("Error listing sshkeys, expected struct, got error %v", err) + } + + teardown := func() { + if err := client.DeleteSSHKey(context.Background(), sshkey.ID); err != nil { + t.Errorf("Expected to delete a sshkey, but got %v", err) + } + fixtureTeardown() + } + return client, sshkey, teardown, err +} diff --git a/resources.go b/resources.go index fe38dba2e..1a2027841 100644 --- a/resources.go +++ b/resources.go @@ -33,6 +33,7 @@ const ( nodebalancersName = "nodebalancers" nodebalancerconfigsName = "nodebalancerconfigs" nodebalancernodesName = "nodebalancernodes" + sshkeysName = "sshkeys" ticketsName = "tickets" accountName = "account" eventsName = "events" @@ -69,6 +70,7 @@ const ( // Should we include these fields in CreateOpts and UpdateOpts? nodebalancerconfigsEndpoint = "nodebalancers/{{ .ID }}/configs" nodebalancernodesEndpoint = "nodebalancers/{{ .ID }}/configs/{{ .SecondID }}/nodes" + sshkeysEndpoint = "profile/sshkeys" ticketsEndpoint = "support/tickets" accountEndpoint = "account" eventsEndpoint = "account/events" diff --git a/template.go b/template.go index 426a77915..7edf0edc2 100644 --- a/template.go +++ b/template.go @@ -25,19 +25,23 @@ type Template struct { // Updated *time.Time `json:"-"` } +// TemplateCreateOptions fields are those accepted by CreateTemplate type TemplateCreateOptions struct { } +// TemplateUpdateOptions fields are those accepted by UpdateTemplate type TemplateUpdateOptions struct { } +// GetCreateOptions converts a Template to TemplateCreateOptions for use in CreateTemplate func (i Template) GetCreateOptions() (o TemplateCreateOptions) { // o.Label = i.Label // o.Description = copyString(o.Description) return } -func (i Template) GetUpdateOptions() (o TemplateCreateOptions) { +// GetUpdateOptions converts a Template to TemplateUpdateOptions for use in UpdateTemplate +func (i Template) GetUpdateOptions() (o TemplateUpdateOptions) { // o.Label = i.Label // o.Description = copyString(o.Description) return @@ -77,10 +81,10 @@ func (c *Client) ListTemplates(ctx context.Context, opts *ListOptions) ([]Templa } // fixDates converts JSON timestamps to Go time.Time values -func (v *Template) fixDates() *Template { - // v.Created, _ = parseDates(v.CreatedStr) - // v.Updated, _ = parseDates(v.UpdatedStr) - return v +func (i *Template) fixDates() *Template { + // i.Created, _ = parseDates(i.CreatedStr) + // i.Updated, _ = parseDates(i.UpdatedStr) + return i } // GetTemplate gets the template with the provided ID From 7b71bcf3b86085c05075cf3b90ba4660884a997d Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Fri, 7 Sep 2018 14:17:10 -0400 Subject: [PATCH 12/18] fix json parsing for event time_remaining values --- account_events.go | 22 +++++++++++++++------- account_events_test.go | 2 ++ instances.go | 2 ++ resources_test.go | 13 +++++++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/account_events.go b/account_events.go index 94911ae5d..e2365c35b 100644 --- a/account_events.go +++ b/account_events.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" "strconv" "strings" "time" @@ -229,23 +230,30 @@ func (c *Client) MarkEventsSeen(ctx context.Context, event *Event) error { } func unmarshalTimeRemaining(m json.RawMessage) *int { - var intPtr *int jsonBytes, err := m.MarshalJSON() if err != nil { - panic(err) + panic(jsonBytes) } - if err := json.Unmarshal(jsonBytes, intPtr); err == nil && intPtr != nil { - return intPtr + + if len(jsonBytes) == 4 && string(jsonBytes) == "null" { + return nil } - var timeStr *string - if err := json.Unmarshal(jsonBytes, timeStr); err == nil && timeStr != nil { - if dur, err := durationToSeconds(*timeStr); err != nil { + + var timeStr string + if err := json.Unmarshal(jsonBytes, &timeStr); err == nil && len(timeStr) > 0 { + if dur, err := durationToSeconds(timeStr); err != nil { panic(err) } else { return &dur } + } else { + var intPtr int + if err := json.Unmarshal(jsonBytes, &intPtr); err == nil { + return &intPtr + } } + log.Println("[WARN] Unexpected unmarshalTimeRemaining value: ", jsonBytes) return nil } diff --git a/account_events_test.go b/account_events_test.go index d4602f22e..4de8aacf4 100644 --- a/account_events_test.go +++ b/account_events_test.go @@ -18,6 +18,8 @@ func TestListEvents_resizing(t *testing.T) { t.Errorf("Error getting Events, expected struct, got error %v", err) } + // TODO(displague) this test is dependent on specific fixture data, mock it here, or just test + // fixDates directly if events[2].TimeRemaining != nil { t.Errorf("Error listing Events, expected resize event time_remaining to be nil, got %v", events[2].TimeRemaining) } diff --git a/instances.go b/instances.go index ba081b665..efb2bf814 100644 --- a/instances.go +++ b/instances.go @@ -87,6 +87,7 @@ type InstanceCreateOptions struct { Group string `json:"group,omitempty"` RootPass string `json:"root_pass,omitempty"` AuthorizedKeys []string `json:"authorized_keys,omitempty"` + AuthorizedUsers []string `json:"authorized_users,omitempty"` StackScriptID int `json:"stackscript_id,omitempty"` StackScriptData map[string]string `json:"stackscript_data,omitempty"` BackupID int `json:"backup_id,omitempty"` @@ -335,6 +336,7 @@ type RebuildInstanceOptions struct { Image string `json:"image"` RootPass string `json:"root_pass"` AuthorizedKeys []string `json:"authorized_keys"` + AuthorizedUsers []string `json:"authorized_users"` StackscriptID int `json:"stackscript_id"` StackscriptData map[string]string `json:"stackscript_data"` Booted bool `json:"booted"` diff --git a/resources_test.go b/resources_test.go index c6b5252ee..7fb48d603 100644 --- a/resources_test.go +++ b/resources_test.go @@ -2,6 +2,7 @@ package linodego import ( "context" + "encoding/json" "fmt" "testing" @@ -41,3 +42,15 @@ func TestResourceTemplatedendpointWithID(t *testing.T) { t.Errorf("Backups endpoint did not contain backup ID '%d'", backupID) } } + +func TestUnmarshalTimeRemaining(t *testing.T) { + if *unmarshalTimeRemaining(json.RawMessage("\"1:23\"")) != 83 { + t.Errorf("Error parsing duration style time_remaining") + } + if unmarshalTimeRemaining(json.RawMessage("null")) != nil { + t.Errorf("Error parsing null time_remaining") + } + if *unmarshalTimeRemaining(json.RawMessage("0")) != 0 { + t.Errorf("Error parsing int style time_remaining") + } +} From ff1dbedda36e66ebf3c993fbdeb9ab8d011cf424 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Sat, 8 Sep 2018 12:46:37 -0400 Subject: [PATCH 13/18] fixes and tests for RebuildNodeBalancerConfig --- API_SUPPORT.md | 2 + fixtures/TestRebuildNodeBalancer.yaml | 490 ++++++++++++++++++++++++++ nodebalancer_config_nodes_test.go | 28 +- nodebalancer_configs.go | 96 ++--- 4 files changed, 574 insertions(+), 42 deletions(-) create mode 100644 fixtures/TestRebuildNodeBalancer.yaml diff --git a/API_SUPPORT.md b/API_SUPPORT.md index 09778f444..2332abd80 100644 --- a/API_SUPPORT.md +++ b/API_SUPPORT.md @@ -169,6 +169,8 @@ - [X] `GET` - [X] `PUT` - [X] `DELETE` +- `/nodebalancers/$id/configs/$id/rebuild` + - [X] `POST` ## Networking diff --git a/fixtures/TestRebuildNodeBalancer.yaml b/fixtures/TestRebuildNodeBalancer.yaml new file mode 100644 index 000000000..28790e114 --- /dev/null +++ b/fixtures/TestRebuildNodeBalancer.yaml @@ -0,0 +1,490 @@ +--- +version: 1 +interactions: +- request: + body: '{"label":"lpq6h62z88m4-linodego-testing","region":"us-west","client_conn_throttle":20}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers + method: POST + response: + body: '{"id": 38590, "ipv6": "1234::5678", "label": "lpq6h62z88m4-linodego-testing", + "region": "us-west", "created": "2018-01-02T03:04:05", "hostname": "nb-10-20-30-40.fremont.nodebalancer.linode.com", + "ipv4": "010.020.030.040", "transfer": {"out": null, "in": null, "total": null}, + "client_conn_throttle": 20, "updated": "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "345" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:58 GMT + Retry-After: + - "118" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424857" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"port":80,"protocol":"http","algorithm":"roundrobin"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers/38590/configs + method: POST + response: + body: '{"check_attempts": 3, "ssl_commonname": "", "protocol": "http", "stickiness": + "none", "algorithm": "roundrobin", "check_path": "", "ssl_cert": null, "check": + "none", "check_interval": 0, "check_body": "", "port": 80, "nodebalancer_id": + 38590, "cipher_suite": "recommended", "id": 34233, "ssl_fingerprint": "", "ssl_key": + null, "check_passive": true, "check_timeout": 30, "nodes_status": {"up": 0, + "down": 0}}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "408" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:58 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424858" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"address":"192.168.030.040:8080","label":"test-label","weight":10,"mode":"accept"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers/38590/configs/34233/nodes + method: POST + response: + body: '{"address": "192.168.030.040:8080", "nodebalancer_id": 38590, "config_id": + 34233, "id": 320215, "label": "test-label", "status": "Unknown", "mode": "accept", + "weight": 10}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "169" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:58 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424858" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"port":80,"protocol":"http","algorithm":"roundrobin","stickiness":"none","check":"none","check_attempts":3,"check_passive":true,"check_timeout":30,"cipher_suite":"recommended","nodes":[]}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers/38590/configs/34233/rebuild + method: POST + response: + body: '{"check": "none", "nodebalancer_id": 38590, "nodes_status": {"down": 1, + "up": 0}, "stickiness": "none", "cipher_suite": "recommended", "id": 34233, + "ssl_fingerprint": "", "check_passive": true, "protocol": "http", "check_timeout": + 30, "check_body": "", "port": 80, "check_attempts": 3, "algorithm": "roundrobin", + "check_path": "", "ssl_commonname": "", "check_interval": 0, "ssl_key": null, + "ssl_cert": null}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "408" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:58 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424858" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers/38590/configs/34233/nodes/320215 + method: DELETE + response: + body: '{"errors": [{"reason": "Not found"}]}' + headers: + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Connection: + - keep-alive + Content-Length: + - "37" + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:59 GMT + Retry-After: + - "119" + Server: + - nginx + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Frame-Options: + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424859" + X-Spec-Version: + - 4.0.4 + status: 404 NOT FOUND + code: 404 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers/38590/configs/34233 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:59 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424859" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/nodebalancers/38590 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 16:38:59 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - nodebalancers:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536424859" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/nodebalancer_config_nodes_test.go b/nodebalancer_config_nodes_test.go index 8ae0fd03c..2df1a6e89 100644 --- a/nodebalancer_config_nodes_test.go +++ b/nodebalancer_config_nodes_test.go @@ -135,6 +135,28 @@ func TestGetNodeBalancerNode(t *testing.T) { } } +func TestRebuildNodeBalancer(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + client, nodebalancer, config, _, teardown, err := setupNodeBalancerNode(t, "fixtures/TestRebuildNodeBalancer") + defer teardown() + if err != nil { + t.Error(err) + } + + nbcRebuildOpts := config.GetRebuildOptions() + + nbcGot, err := client.RebuildNodeBalancerConfig(context.Background(), nodebalancer.ID, config.ID, nbcRebuildOpts) + if err != nil { + t.Errorf("Error rebuilding nodebalancer config %d: %v", config.ID, err) + } + if nbcGot.Port != config.Port { + t.Errorf("RebuildNodeBalancerConfig did not return the expected port") + } + +} + func setupNodeBalancerNode(t *testing.T, fixturesYaml string) (*linodego.Client, *linodego.NodeBalancer, *linodego.NodeBalancerConfig, *linodego.NodeBalancerNode, func(), error) { t.Helper() var fixtureTeardown func() @@ -152,7 +174,11 @@ func setupNodeBalancerNode(t *testing.T, fixturesYaml string) (*linodego.Client, teardown := func() { // delete the NodeBalancerNode to exercise the code if err := client.DeleteNodeBalancerNode(context.Background(), nodebalancer.ID, config.ID, node.ID); err != nil { - t.Errorf("Expected to delete a NodeBalancer Config Node, but got %v", err) + e, ok := err.(*linodego.Error) + // Tollerate 404 because Rebuild testing will delete all Nodes + if !ok || e.Code != 404 { + t.Errorf("Expected to delete a NodeBalancer Config Node, but got %v", err) + } } fixtureTeardown() } diff --git a/nodebalancer_configs.go b/nodebalancer_configs.go index d4538b396..4f5809d3e 100644 --- a/nodebalancer_configs.go +++ b/nodebalancer_configs.go @@ -87,47 +87,40 @@ type NodeBalancerNodeStatus struct { // NodeBalancerConfigCreateOptions are permitted by CreateNodeBalancerConfig type NodeBalancerConfigCreateOptions struct { - Port int `json:"port"` - Protocol ConfigProtocol `json:"protocol,omitempty"` - Algorithm ConfigAlgorithm `json:"algorithm,omitempty"` - Stickiness ConfigStickiness `json:"stickiness,omitempty"` - Check ConfigCheck `json:"check,omitempty"` - CheckInterval int `json:"check_interval,omitempty"` - CheckAttempts int `json:"check_attempts,omitempty"` - CheckPath string `json:"check_path,omitempty"` - CheckBody string `json:"check_body,omitempty"` - CheckPassive *bool `json:"check_passive,omitempty"` - CheckTimeout int `json:"check_timeout,omitempty"` - CipherSuite ConfigCipher `json:"cipher_suite,omitempty"` - SSLCert string `json:"ssl_cert,omitempty"` - SSLKey string `json:"ssl_key,omitempty"` -} - -// NodeBalancerConfigRebuildOptionsNode for a nodebalancer instance mapping -type NodeBalancerConfigRebuildOptionsNode struct { - Address *string `json:"address"` - Label *string `json:"label"` - Weight *int `json:"weight"` - Mode *string `json:"mode"` + Port int `json:"port"` + Protocol ConfigProtocol `json:"protocol,omitempty"` + Algorithm ConfigAlgorithm `json:"algorithm,omitempty"` + Stickiness ConfigStickiness `json:"stickiness,omitempty"` + Check ConfigCheck `json:"check,omitempty"` + CheckInterval int `json:"check_interval,omitempty"` + CheckAttempts int `json:"check_attempts,omitempty"` + CheckPath string `json:"check_path,omitempty"` + CheckBody string `json:"check_body,omitempty"` + CheckPassive *bool `json:"check_passive,omitempty"` + CheckTimeout int `json:"check_timeout,omitempty"` + CipherSuite ConfigCipher `json:"cipher_suite,omitempty"` + SSLCert string `json:"ssl_cert,omitempty"` + SSLKey string `json:"ssl_key,omitempty"` + Nodes []NodeBalancerNodeCreateOptions `json:"nodes,omitempty"` } // NodeBalancerConfigRebuildOptions used by RebuildNodeBalancerConfig type NodeBalancerConfigRebuildOptions struct { - Port int `json:"port"` - Protocol ConfigProtocol `json:"protocol,omitempty"` - Algorithm ConfigAlgorithm `json:"algorithm,omitempty"` - Stickiness ConfigStickiness `json:"stickiness,omitempty"` - Check ConfigCheck `json:"check,omitempty"` - CheckInterval int `json:"check_interval,omitempty"` - CheckAttempts int `json:"check_attempts,omitempty"` - CheckPath string `json:"check_path,omitempty"` - CheckBody string `json:"check_body,omitempty"` - CheckPassive *bool `json:"check_passive,omitempty"` - CheckTimeout int `json:"check_timeout,omitempty"` - CipherSuite ConfigCipher `json:"cipher_suite,omitempty"` - SSLCert string `json:"ssl_cert,omitempty"` - SSLKey string `json:"ssl_key,omitempty"` - Nodes []*NodeBalancerConfigRebuildOptionsNode `json:"nodes,omitempty"` + Port int `json:"port"` + Protocol ConfigProtocol `json:"protocol,omitempty"` + Algorithm ConfigAlgorithm `json:"algorithm,omitempty"` + Stickiness ConfigStickiness `json:"stickiness,omitempty"` + Check ConfigCheck `json:"check,omitempty"` + CheckInterval int `json:"check_interval,omitempty"` + CheckAttempts int `json:"check_attempts,omitempty"` + CheckPath string `json:"check_path,omitempty"` + CheckBody string `json:"check_body,omitempty"` + CheckPassive *bool `json:"check_passive,omitempty"` + CheckTimeout int `json:"check_timeout,omitempty"` + CipherSuite ConfigCipher `json:"cipher_suite,omitempty"` + SSLCert string `json:"ssl_cert,omitempty"` + SSLKey string `json:"ssl_key,omitempty"` + Nodes []NodeBalancerNodeCreateOptions `json:"nodes"` } // NodeBalancerConfigUpdateOptions are permitted by UpdateNodeBalancerConfig @@ -173,6 +166,27 @@ func (i NodeBalancerConfig) GetUpdateOptions() NodeBalancerConfigUpdateOptions { } } +// GetRebuildOptions converts a NodeBalancerConfig to NodeBalancerConfigRebuildOptions for use in RebuildNodeBalancerConfig +func (i NodeBalancerConfig) GetRebuildOptions() NodeBalancerConfigRebuildOptions { + return NodeBalancerConfigRebuildOptions{ + Port: i.Port, + Protocol: i.Protocol, + Algorithm: i.Algorithm, + Stickiness: i.Stickiness, + Check: i.Check, + CheckInterval: i.CheckInterval, + CheckAttempts: i.CheckAttempts, + CheckTimeout: i.CheckTimeout, + CheckPath: i.CheckPath, + CheckBody: i.CheckBody, + CheckPassive: &i.CheckPassive, + CipherSuite: i.CipherSuite, + SSLCert: i.SSLCert, + SSLKey: i.SSLKey, + Nodes: make([]NodeBalancerNodeCreateOptions, 0), + } +} + // NodeBalancerConfigsPagedResponse represents a paginated NodeBalancerConfig API response type NodeBalancerConfigsPagedResponse struct { *PageOptions @@ -293,7 +307,7 @@ func (c *Client) DeleteNodeBalancerConfig(ctx context.Context, nodebalancerID in } // RebuildNodeBalancerConfig updates the NodeBalancer with the specified id -func (c *Client) RebuildNodeBalancerConfig(ctx context.Context, nodeBalancerID int, configID int, rebuildOpts NodeBalancerConfigRebuildOptions) (*NodeBalancer, error) { +func (c *Client) RebuildNodeBalancerConfig(ctx context.Context, nodeBalancerID int, configID int, rebuildOpts NodeBalancerConfigRebuildOptions) (*NodeBalancerConfig, error) { var body string e, err := c.NodeBalancerConfigs.endpointWithID(nodeBalancerID) if err != nil { @@ -301,7 +315,7 @@ func (c *Client) RebuildNodeBalancerConfig(ctx context.Context, nodeBalancerID i } e = fmt.Sprintf("%s/%d/rebuild", e, configID) - req := c.R(ctx).SetResult(&NodeBalancer{}) + req := c.R(ctx).SetResult(&NodeBalancerConfig{}) if bodyData, err := json.Marshal(rebuildOpts); err == nil { body = string(bodyData) @@ -311,10 +325,10 @@ func (c *Client) RebuildNodeBalancerConfig(ctx context.Context, nodeBalancerID i r, err := coupleAPIErrors(req. SetBody(body). - Put(e)) + Post(e)) if err != nil { return nil, err } - return r.Result().(*NodeBalancer).fixDates(), nil + return r.Result().(*NodeBalancerConfig).fixDates(), nil } From 03b2c582ccf2eebe2c10ca883b327859cfd87da8 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Sun, 9 Sep 2018 13:16:59 -0400 Subject: [PATCH 14/18] use setup functions in tests to avoid magic number requirements during testing Closes #32 --- Makefile | 12 +- README.md | 5 +- client_test.go | 14 - env.sample | 2 - fixtures/TestGetInstance.yaml | 254 ++++++++++++++- fixtures/TestGetVolume.yaml | 160 +++++++++- fixtures/TestListInstanceConfigs.yaml | 255 ++++++++++++++- fixtures/TestListInstanceDisks.yaml | 170 +++++++++- fixtures/TestListInstanceVolumes.yaml | 166 +++++++++- .../TestListInstanceVolumes_instance.yaml | 301 +++++++++++++++++ fixtures/TestListInstances.yaml | 257 ++++++++++++++- fixtures/TestUpdateInstanceConfig.yaml | 302 ++++++++++++++++++ instance_snapshots_test.go | 2 +- instances_test.go | 94 ++++-- volumes_test.go | 13 +- 15 files changed, 1871 insertions(+), 136 deletions(-) create mode 100644 fixtures/TestListInstanceVolumes_instance.yaml create mode 100644 fixtures/TestUpdateInstanceConfig.yaml diff --git a/Makefile b/Makefile index bd911532c..cbed613e1 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,9 @@ include .env .PHONY: vendor example refresh-fixtures clean-fixtures -LINODE_FIXTURE_INSTANCE:=76859403 -LINODE_FIXTURE_VOLUME:=6574839201 - .PHONY: test test: vendor - @LINODE_TEST_INSTANCE=$(LINODE_FIXTURE_INSTANCE) \ - LINODE_TEST_VOLUME=$(LINODE_FIXTURE_VOLUME) \ - LINODE_FIXTURE_MODE="play" \ + @LINODE_FIXTURE_MODE="play" \ LINODE_TOKEN="awesometokenawesometokenawesometoken" \ go test $(ARGS) @@ -31,19 +26,16 @@ refresh-fixtures: clean-fixtures fixtures fixtures: @echo "* Running fixtures" @LINODE_TOKEN=$(LINODE_TOKEN) \ - LINODE_TEST_INSTANCE=$(LINODE_TEST_INSTANCE) \ - LINODE_TEST_VOLUME=$(LINODE_TEST_VOLUME) \ LINODE_FIXTURE_MODE="record" go test $(ARGS) @echo "* Santizing fixtures" @for yaml in fixtures/*yaml; do \ sed -E -i "" -e "s/$(LINODE_TOKEN)/awesometokenawesometokenawesometoken/g" \ - -e "s/$(LINODE_TEST_INSTANCE)/$(LINODE_FIXTURE_INSTANCE)/g" \ -e 's/20[0-9]{2}-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-9]{2}:[0-9]{2}/2018-01-02T03:04:05/g' \ -e 's/nb-[0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}\./nb-10-20-30-40./g' \ -e 's/192\.168\.((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.)(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])/192.168.030.040/g' \ -e '/^192\.168/!s/((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])/010.020.030.040/g' \ -e 's/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/1234::5678/g' \ - -e "s/$(LINODE_TEST_VOLUME)/$(LINODE_FIXTURE_VOLUME)/g" $$yaml; \ + $$yaml; \ done .PHONY: godoc diff --git a/README.md b/README.md index dfdd322ea..2a83dcda6 100644 --- a/README.md +++ b/README.md @@ -156,9 +156,8 @@ When performing a `POST` or `PUT` request, multiple field related errors will be Run `make test` to run the unit tests. This is the same as running `go test` except that `make test` will execute the tests while playing back API response fixtures that were recorded during a previous development build. -`go test` can be used without the fixtures, so long as `LINODE_TEST_INSTANCE` and `LINODE_TEST_VOLUME` are set -to an instance ID and volume ID that exists on your account. The Linode instance must have a backup and a snapshot to -match the test expectations. Copy `env.sample` to `.env` and configure your persistent test settings, including an API token. +`go test` can be used without the fixtures. Copy `env.sample` to `.env` and configure your persistent test +settings, including an API token. `go test -short` can be used to run live API tests that do not require an account token. diff --git a/client_test.go b/client_test.go index 0c6ff619f..1a227d97b 100644 --- a/client_test.go +++ b/client_test.go @@ -16,9 +16,6 @@ var testingMode = recorder.ModeDisabled var debugAPI = false var validTestAPIKey = "NOTANAPIKEY" -var TestInstanceID int -var TestVolumeID int - func init() { if apiToken, ok := os.LookupEnv("LINODE_TOKEN"); ok { validTestAPIKey = apiToken @@ -42,17 +39,6 @@ func init() { testingMode = recorder.ModeReplaying } } - - if apiTestInstance, ok := os.LookupEnv("LINODE_TEST_INSTANCE"); ok { - TestInstanceID, _ = strconv.Atoi(apiTestInstance) - log.Printf("[INFO] LINODE_TEST_INSTANCE %d will be examined for tests", TestInstanceID) - } - - if apiTestVolume, ok := os.LookupEnv("LINODE_TEST_VOLUME"); ok { - TestVolumeID, _ = strconv.Atoi(apiTestVolume) - log.Printf("[INFO] LINODE_TEST_VOLUME %d will be examined for tests", TestVolumeID) - } - } // testRecorder returns a go-vcr recorder and an associated function that the caller must defer diff --git a/env.sample b/env.sample index 01d23cf49..b1c9d1803 100644 --- a/env.sample +++ b/env.sample @@ -1,4 +1,2 @@ LINODE_TOKEN= LINODE_DEBUG=0 -LINODE_TEST_INSTANCE= -LINODE_TEST_VOLUME= diff --git a/fixtures/TestGetInstance.yaml b/fixtures/TestGetInstance.yaml index 1c064510c..d91ba2add 100644 --- a/fixtures/TestGetInstance.yaml +++ b/fixtures/TestGetInstance.yaml @@ -1,6 +1,159 @@ --- version: 1 interactions: +- request: + body: '{"region":"us-west","type":"g6-nanode-1","label":"linodego-test-instance","booted":false}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances + method: POST + response: + body: '{"region": "us-west", "alerts": {"network_in": 10, "io": 10000, "cpu": + 90, "transfer_quota": 80, "network_out": 10}, "created": "2018-01-02T03:04:05", + "label": "linodego-test-instance", "updated": "2018-01-02T03:04:05", "watchdog_enabled": + true, "image": null, "id": 10157452, "group": "", "ipv4": ["010.020.030.040"], + "status": "provisioning", "hypervisor": "kvm", "ipv6": "1234::5678/64", + "type": "g6-nanode-1", "backups": {"enabled": false, "schedule": {"day": null, + "window": null}}, "specs": {"vcpus": 1, "disk": 25600, "memory": 1024, "transfer": + 1000}}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "576" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 20:05:47 GMT + Retry-After: + - "118" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536437266" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-config","devices":{}}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10157452/configs + method: POST + response: + body: '{"virt_mode": "paravirt", "devices": {"sdg": null, "sda": null, "sdd": + null, "sdb": null, "sde": null, "sdc": null, "sdh": null, "sdf": null}, "memory_limit": + 0, "comments": "", "updated": "2018-01-02T03:04:05", "run_level": "default", + "label": "linodego-test-config", "id": 11404308, "created": "2018-01-02T03:04:05", + "initrd": null, "root_device": "/dev/sda", "helpers": {"distro": true, "modules_dep": + true, "network": true, "devtmpfs_automount": true, "updatedb_disabled": true}, + "kernel": "linode/latest-64bit"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "516" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 20:05:47 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536437267" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" - request: body: "" form: {} @@ -12,18 +165,17 @@ interactions: Content-Type: - application/json User-Agent: - - linodego 0.0.1 https://github.com/linode/linodego - url: https://api.linode.com/v4/linode/instances/76859403 + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10157452 method: GET response: - body: '{"watchdog_enabled": true, "ipv6": "1234::5678/64", - "hypervisor": "kvm", "ipv4": ["010.020.030.040", "192.168.030.040"], "status": "running", - "label": "test-linode", "backups": {"schedule": {"window": "W16", "day": "Monday"}, - "enabled": true}, "updated": "2018-01-02T03:04:05", "image": "linode/ubuntu18.04", - "created": "2018-01-02T03:04:05", "id": 76859403, "type": "g6-standard-1", "region": - "us-east", "group": "", "specs": {"vcpus": 1, "disk": 51200, "memory": 2048, - "transfer": 2000}, "alerts": {"cpu": 90, "io": 10000, "network_out": 10, "network_in": - 10, "transfer_quota": 80}}' + body: '{"group": "", "backups": {"schedule": {"window": null, "day": null}, "enabled": + false}, "region": "us-west", "created": "2018-01-02T03:04:05", "label": "linodego-test-instance", + "id": 10157452, "status": "provisioning", "image": null, "specs": {"transfer": + 1000, "vcpus": 1, "disk": 25600, "memory": 1024}, "updated": "2018-01-02T03:04:05", + "ipv6": "1234::5678/64", "hypervisor": "kvm", "type": "g6-nanode-1", + "alerts": {"cpu": 90, "network_in": 10, "io": 10000, "transfer_quota": 80, "network_out": + 10}, "ipv4": ["010.020.030.040"], "watchdog_enabled": true}' headers: Access-Control-Allow-Credentials: - "true" @@ -41,15 +193,15 @@ interactions: Connection: - keep-alive Content-Length: - - "599" + - "576" Content-Security-Policy: - default-src 'none' Content-Type: - application/json Date: - - Tue, 03 Jul 2018 01:38:49 GMT + - Sat, 08 Sep 2018 20:05:48 GMT Retry-After: - - "28" + - "15" Server: - nginx Strict-Transport-Security: @@ -70,11 +222,81 @@ interactions: X-Ratelimit-Limit: - "400" X-Ratelimit-Remaining: - - "395" + - "398" + X-Ratelimit-Reset: + - "1536437164" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10157452 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 20:05:48 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" X-Ratelimit-Reset: - - "1530581958" + - "1536437268" X-Spec-Version: - - 4.0.2 + - 4.0.4 X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/fixtures/TestGetVolume.yaml b/fixtures/TestGetVolume.yaml index 0359aeb73..8481bd1bb 100644 --- a/fixtures/TestGetVolume.yaml +++ b/fixtures/TestGetVolume.yaml @@ -1,6 +1,78 @@ --- version: 1 interactions: +- request: + body: '{"label":"linodego-test-volume","region":"us-west"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/volumes + method: POST + response: + body: '{"updated": "2018-01-02T03:04:05", "filesystem_path": "/dev/disk/by-id/scsi-0Linode_Volume_linodego-test-volume", + "created": "2018-01-02T03:04:05", "id": 12771, "label": "linodego-test-volume", + "status": "creating", "region": "us-west", "linode_id": null, "size": 20}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "267" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 22:25:51 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - volumes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536445671" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" - request: body: "" form: {} @@ -12,13 +84,13 @@ interactions: Content-Type: - application/json User-Agent: - - linodego 0.0.1 https://github.com/linode/linodego - url: https://api.linode.com/v4/volumes/6574839201 + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/volumes/12771 method: GET response: - body: '{"updated": "2018-01-02T03:04:05", "linode_id": null, "created": "2018-01-02T03:04:05", - "size": 11, "filesystem_path": "/dev/disk/by-id/scsi-0Linode_Volume_test-volume", - "status": "active", "region": "us-east", "label": "test-volume", "id": 6574839201}' + body: '{"label": "linodego-test-volume", "filesystem_path": "/dev/disk/by-id/scsi-0Linode_Volume_linodego-test-volume", + "size": 20, "status": "creating", "updated": "2018-01-02T03:04:05", "created": + "2018-01-02T03:04:05", "linode_id": null, "region": "us-west", "id": 12771}' headers: Access-Control-Allow-Credentials: - "true" @@ -36,13 +108,13 @@ interactions: Connection: - keep-alive Content-Length: - - "246" + - "267" Content-Security-Policy: - default-src 'none' Content-Type: - application/json Date: - - Fri, 13 Jul 2018 04:53:18 GMT + - Sat, 08 Sep 2018 22:25:52 GMT Retry-After: - "119" Server: @@ -67,9 +139,79 @@ interactions: X-Ratelimit-Remaining: - "399" X-Ratelimit-Reset: - - "1531457718" + - "1536445672" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/volumes/12771 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 22:25:52 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - volumes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536445672" X-Spec-Version: - - 4.0.3 + - 4.0.4 X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/fixtures/TestListInstanceConfigs.yaml b/fixtures/TestListInstanceConfigs.yaml index bf616d2c1..d92c11dc6 100644 --- a/fixtures/TestListInstanceConfigs.yaml +++ b/fixtures/TestListInstanceConfigs.yaml @@ -1,6 +1,159 @@ --- version: 1 interactions: +- request: + body: '{"region":"us-west","type":"g6-nanode-1","label":"linodego-test-instance","booted":false}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances + method: POST + response: + body: '{"backups": {"enabled": false, "schedule": {"day": null, "window": null}}, + "updated": "2018-01-02T03:04:05", "region": "us-west", "hypervisor": "kvm", + "label": "linodego-test-instance", "created": "2018-01-02T03:04:05", "image": + null, "alerts": {"network_in": 10, "cpu": 90, "network_out": 10, "transfer_quota": + 80, "io": 10000}, "group": "", "specs": {"vcpus": 1, "transfer": 1000, "disk": + 25600, "memory": 1024}, "ipv6": "1234::5678/64", "type": + "g6-nanode-1", "id": 10174066, "status": "provisioning", "watchdog_enabled": + true, "ipv4": ["010.020.030.040"]}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "578" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:11:24 GMT + Retry-After: + - "41" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536513126" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-config","devices":{}}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174066/configs + method: POST + response: + body: '{"helpers": {"distro": true, "network": true, "devtmpfs_automount": true, + "updatedb_disabled": true, "modules_dep": true}, "virt_mode": "paravirt", "created": + "2018-01-02T03:04:05", "label": "linodego-test-config", "id": 11421183, "devices": + {"sdc": null, "sdd": null, "sda": null, "sdf": null, "sdb": null, "sde": null, + "sdg": null, "sdh": null}, "run_level": "default", "updated": "2018-01-02T03:04:05", + "memory_limit": 0, "kernel": "linode/latest-64bit", "comments": "", "initrd": + null, "root_device": "/dev/sda"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "516" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:11:24 GMT + Retry-After: + - "40" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536513125" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" - request: body: "" form: {} @@ -12,19 +165,17 @@ interactions: Content-Type: - application/json User-Agent: - - linodego 0.0.1 https://github.com/linode/linodego - url: https://api.linode.com/v4/linode/instances/76859403/configs + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174066/configs method: GET response: - body: '{"pages": 1, "page": 1, "data": [{"updated": "2018-01-02T03:04:05", "root_device": - "/dev/sda", "helpers": {"updatedb_disabled": true, "distro": true, "network": - true, "modules_dep": true, "devtmpfs_automount": true}, "virt_mode": "paravirt", - "id": 9958462, "memory_limit": 0, "label": "My Ubuntu 18.04 LTS Disk Profile", - "run_level": "default", "kernel": "linode/grub2", "devices": {"sda": {"disk_id": - 18974977, "volume_id": null}, "sdd": null, "sdg": null, "sdh": null, "sdf": - null, "sde": null, "sdc": {"disk_id": null, "volume_id": 6574839201}, "sdb": {"disk_id": - 18974978, "volume_id": null}}, "comments": "", "initrd": null, "created": "2018-01-02T03:04:05"}], - "results": 1}' + body: '{"data": [{"helpers": {"distro": true, "devtmpfs_automount": true, "updatedb_disabled": + true, "network": true, "modules_dep": true}, "memory_limit": 0, "label": "linodego-test-config", + "comments": "", "updated": "2018-01-02T03:04:05", "run_level": "default", "id": + 11421183, "initrd": null, "root_device": "/dev/sda", "virt_mode": "paravirt", + "devices": {"sdg": null, "sde": null, "sdc": null, "sdh": null, "sda": null, + "sdf": null, "sdb": null, "sdd": null}, "kernel": "linode/latest-64bit", "created": + "2018-01-02T03:04:05"}], "pages": 1, "page": 1, "results": 1}' headers: Access-Control-Allow-Credentials: - "true" @@ -42,15 +193,15 @@ interactions: Connection: - keep-alive Content-Length: - - "673" + - "565" Content-Security-Policy: - default-src 'none' Content-Type: - application/json Date: - - Tue, 03 Jul 2018 01:38:49 GMT + - Sun, 09 Sep 2018 17:11:24 GMT Retry-After: - - "29" + - "119" Server: - nginx Strict-Transport-Security: @@ -71,11 +222,81 @@ interactions: X-Ratelimit-Limit: - "400" X-Ratelimit-Remaining: - - "395" + - "399" + X-Ratelimit-Reset: + - "1536513204" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174066 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:11:24 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" X-Ratelimit-Reset: - - "1530581959" + - "1536513204" X-Spec-Version: - - 4.0.2 + - 4.0.4 X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/fixtures/TestListInstanceDisks.yaml b/fixtures/TestListInstanceDisks.yaml index 37fba63c5..aaec90c34 100644 --- a/fixtures/TestListInstanceDisks.yaml +++ b/fixtures/TestListInstanceDisks.yaml @@ -1,6 +1,82 @@ --- version: 1 interactions: +- request: + body: '{"region":"us-west","type":"g6-nanode-1","label":"linodego-test-instance","root_pass":"R34lBAdP455","image":"linode/debian9","booted":false}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances + method: POST + response: + body: '{"group": "", "specs": {"transfer": 1000, "memory": 1024, "disk": 25600, + "vcpus": 1}, "created": "2018-01-02T03:04:05", "region": "us-west", "hypervisor": + "kvm", "label": "linodego-test-instance", "image": "linode/debian9", "alerts": + {"network_out": 10, "transfer_quota": 80, "io": 10000, "cpu": 90, "network_in": + 10}, "status": "provisioning", "updated": "2018-01-02T03:04:05", "ipv6": "1234::5678/64", + "backups": {"enabled": false, "schedule": {"day": null, "window": null}}, "type": + "g6-nanode-1", "ipv4": ["010.020.030.040"], "watchdog_enabled": true, "id": 10158886}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "589" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 22:09:52 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536444712" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" - request: body: "" form: {} @@ -12,15 +88,15 @@ interactions: Content-Type: - application/json User-Agent: - - linodego 0.0.1 https://github.com/linode/linodego - url: https://api.linode.com/v4/linode/instances/76859403/disks + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10158886/disks method: GET response: - body: '{"data": [{"updated": "2018-01-02T03:04:05", "created": "2018-01-02T03:04:05", - "size": 50688, "status": "ready", "filesystem": "ext4", "id": 18974977, "label": - "Ubuntu 18.04 LTS Disk"}, {"updated": "2018-01-02T03:04:05", "created": "2018-01-02T03:04:05", - "size": 512, "status": "ready", "filesystem": "swap", "id": 18974978, "label": - "512 MB Swap Image"}], "page": 1, "pages": 1, "results": 2}' + body: '{"pages": 1, "results": 2, "data": [{"id": 21758686, "status": "not ready", + "label": "Debian 9 Disk", "created": "2018-01-02T03:04:05", "size": 25088, "filesystem": + "ext4", "updated": "2018-01-02T03:04:05"}, {"id": 21758687, "status": "not ready", + "label": "512 MB Swap Image", "created": "2018-01-02T03:04:05", "size": 512, + "filesystem": "swap", "updated": "2018-01-02T03:04:05"}], "page": 1}' headers: Access-Control-Allow-Credentials: - "true" @@ -44,9 +120,9 @@ interactions: Content-Type: - application/json Date: - - Tue, 03 Jul 2018 01:38:49 GMT + - Sat, 08 Sep 2018 22:09:53 GMT Retry-After: - - "28" + - "119" Server: - nginx Strict-Transport-Security: @@ -67,11 +143,81 @@ interactions: X-Ratelimit-Limit: - "400" X-Ratelimit-Remaining: - - "393" + - "399" + X-Ratelimit-Reset: + - "1536444713" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10158886 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 22:09:53 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" X-Ratelimit-Reset: - - "1530581958" + - "1536444713" X-Spec-Version: - - 4.0.2 + - 4.0.4 X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/fixtures/TestListInstanceVolumes.yaml b/fixtures/TestListInstanceVolumes.yaml index 2e34185f4..99fc6d055 100644 --- a/fixtures/TestListInstanceVolumes.yaml +++ b/fixtures/TestListInstanceVolumes.yaml @@ -1,6 +1,78 @@ --- version: 1 interactions: +- request: + body: '{"label":"linodego-test-volume","region":"us-west"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/volumes + method: POST + response: + body: '{"filesystem_path": "/dev/disk/by-id/scsi-0Linode_Volume_linodego-test-volume", + "linode_id": null, "region": "us-west", "status": "creating", "label": "linodego-test-volume", + "id": 12787, "created": "2018-01-02T03:04:05", "size": 20, "updated": "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "267" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:41 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - volumes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536513281" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" - request: body: "" form: {} @@ -12,14 +84,14 @@ interactions: Content-Type: - application/json User-Agent: - - linodego 0.0.1 https://github.com/linode/linodego - url: https://api.linode.com/v4/linode/instances/76859403/volumes + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174075/volumes method: GET response: - body: '{"results": 1, "data": [{"created": "2018-01-02T03:04:05", "id": 6574839201, - "linode_id": 76859403, "label": "test-volume", "filesystem_path": "/dev/disk/by-id/scsi-0Linode_Volume_test-volume", - "region": "us-east", "status": "active", "size": 10, "updated": "2018-01-02T03:04:05"}], - "pages": 1, "page": 1}' + body: '{"pages": 1, "results": 1, "data": [{"id": 12787, "status": "active", "label": + "linodego-test-volume", "updated": "2018-01-02T03:04:05", "created": "2018-01-02T03:04:05", + "filesystem_path": "/dev/disk/by-id/scsi-0Linode_Volume_linodego-test-volume", + "size": 20, "linode_id": 10174075, "region": "us-west"}], "page": 1}' headers: Access-Control-Allow-Credentials: - "true" @@ -37,15 +109,15 @@ interactions: Connection: - keep-alive Content-Length: - - "298" + - "318" Content-Security-Policy: - default-src 'none' Content-Type: - application/json Date: - - Tue, 03 Jul 2018 01:38:50 GMT + - Sun, 09 Sep 2018 17:12:42 GMT Retry-After: - - "27" + - "119" Server: - nginx Strict-Transport-Security: @@ -66,11 +138,81 @@ interactions: X-Ratelimit-Limit: - "400" X-Ratelimit-Remaining: - - "394" + - "399" + X-Ratelimit-Reset: + - "1536513282" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/volumes/12787 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:42 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - volumes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" X-Ratelimit-Reset: - - "1530581958" + - "1536513282" X-Spec-Version: - - 4.0.2 + - 4.0.4 X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/fixtures/TestListInstanceVolumes_instance.yaml b/fixtures/TestListInstanceVolumes_instance.yaml new file mode 100644 index 000000000..90f93478f --- /dev/null +++ b/fixtures/TestListInstanceVolumes_instance.yaml @@ -0,0 +1,301 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-west","type":"g6-nanode-1","label":"linodego-test-instance","booted":false}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances + method: POST + response: + body: '{"group": "", "specs": {"transfer": 1000, "memory": 1024, "disk": 25600, + "vcpus": 1}, "created": "2018-01-02T03:04:05", "region": "us-west", "hypervisor": + "kvm", "label": "linodego-test-instance", "image": null, "alerts": {"network_out": + 10, "transfer_quota": 80, "io": 10000, "cpu": 90, "network_in": 10}, "status": + "provisioning", "updated": "2018-01-02T03:04:05", "ipv6": "1234::5678/64", + "backups": {"enabled": false, "schedule": {"day": null, "window": null}}, "type": + "g6-nanode-1", "ipv4": ["010.020.030.040"], "watchdog_enabled": true, "id": 10174075}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "578" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:40 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536513280" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-config","devices":{}}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174075/configs + method: POST + response: + body: '{"virt_mode": "paravirt", "devices": {"sdg": null, "sda": null, "sdd": + null, "sdb": null, "sde": null, "sdc": null, "sdh": null, "sdf": null}, "memory_limit": + 0, "comments": "", "updated": "2018-01-02T03:04:05", "run_level": "default", + "label": "linodego-test-config", "id": 11421192, "created": "2018-01-02T03:04:05", + "initrd": null, "root_device": "/dev/sda", "helpers": {"distro": true, "modules_dep": + true, "network": true, "devtmpfs_automount": true, "updatedb_disabled": true}, + "kernel": "linode/latest-64bit"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "516" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:41 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536513281" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"volume-test","comments":"","devices":{"sda":{"volume_id":12787}},"memory_limit":0,"init_rd":null}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174075/configs/11421192 + method: PUT + response: + body: '{"root_device": "/dev/sda", "updated": "2018-01-02T03:04:05", "virt_mode": + "paravirt", "initrd": null, "label": "volume-test", "created": "2018-01-02T03:04:05", + "comments": "", "memory_limit": 0, "kernel": "linode/latest-64bit", "run_level": + "default", "devices": {"sdb": null, "sdg": null, "sdh": null, "sda": {"disk_id": + null, "volume_id": 12787}, "sdd": null, "sde": null, "sdf": null, "sdc": null}, + "helpers": {"distro": true, "modules_dep": true, "devtmpfs_automount": true, + "network": true, "updatedb_disabled": true}, "id": 11421192}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "540" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:42 GMT + Retry-After: + - "118" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536513281" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174075 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:42 GMT + Retry-After: + - "117" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536513280" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/fixtures/TestListInstances.yaml b/fixtures/TestListInstances.yaml index eb57035b4..3fa3a5908 100644 --- a/fixtures/TestListInstances.yaml +++ b/fixtures/TestListInstances.yaml @@ -2,7 +2,7 @@ version: 1 interactions: - request: - body: "" + body: '{"region":"us-west","type":"g6-nanode-1","label":"linodego-test-instance","booted":false}' form: {} headers: Accept: @@ -12,19 +12,172 @@ interactions: Content-Type: - application/json User-Agent: - - linodego 0.0.1 https://github.com/linode/linodego + - linodego 0.4.0 https://github.com/linode/linodego url: https://api.linode.com/v4/linode/instances + method: POST + response: + body: '{"status": "provisioning", "group": "", "watchdog_enabled": true, "hypervisor": + "kvm", "specs": {"memory": 1024, "transfer": 1000, "disk": 25600, "vcpus": 1}, + "ipv4": ["010.020.030.040"], "label": "linodego-test-instance", "updated": "2018-01-02T03:04:05", + "id": 10157365, "type": "g6-nanode-1", "image": null, "created": "2018-01-02T03:04:05", + "backups": {"schedule": {"window": null, "day": null}, "enabled": false}, "alerts": + {"network_in": 10, "network_out": 10, "cpu": 90, "transfer_quota": 80, "io": + 10000}, "ipv6": "1234::5678/64", "region": "us-west"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "576" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 20:04:03 GMT + Retry-After: + - "116" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536437160" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-config","devices":{}}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10157365/configs + method: POST + response: + body: '{"helpers": {"distro": true, "devtmpfs_automount": true, "updatedb_disabled": + true, "network": true, "modules_dep": true}, "memory_limit": 0, "label": "linodego-test-config", + "comments": "", "updated": "2018-01-02T03:04:05", "run_level": "default", "id": + 11404221, "initrd": null, "root_device": "/dev/sda", "virt_mode": "paravirt", + "devices": {"sdg": null, "sde": null, "sdc": null, "sdh": null, "sda": null, + "sdf": null, "sdb": null, "sdd": null}, "kernel": "linode/latest-64bit", "created": + "2018-01-02T03:04:05"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "516" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 20:04:03 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536437163" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + X-Filter: + - '{"id": 10157365}' + url: https://api.linode.com/v4/linode/instances?page=1 method: GET response: - body: '{"data": [{"region": "us-east", "alerts": {"network_in": 10, "network_out": - 10, "io": 10000, "cpu": 90, "transfer_quota": 80}, "specs": {"disk": 51200, - "transfer": 2000, "vcpus": 1, "memory": 2048}, "image": "linode/ubuntu18.04", - "created": "2018-01-02T03:04:05", "ipv6": "1234::5678/64", - "hypervisor": "kvm", "ipv4": ["010.020.030.040", "192.168.030.040"], "updated": - "2018-01-02T03:04:05", "watchdog_enabled": true, "group": "", "id": 76859403, - "status": "running", "backups": {"schedule": {"day": "Monday", "window": "W16"}, - "enabled": true}, "label": "test-linode", "type": "g6-standard-1"}], "page": - 1, "pages": 1, "results": 1}' + body: '{"data": [{"backups": {"enabled": false, "schedule": {"window": null, "day": + null}}, "ipv6": "1234::5678/64", "status": "provisioning", + "group": "", "type": "g6-nanode-1", "hypervisor": "kvm", "specs": {"vcpus": + 1, "disk": 25600, "transfer": 1000, "memory": 1024}, "region": "us-west", "label": + "linodego-test-instance", "ipv4": ["010.020.030.040"], "id": 10157365, "created": + "2018-01-02T03:04:05", "updated": "2018-01-02T03:04:05", "alerts": {"cpu": 90, + "network_out": 10, "transfer_quota": 80, "network_in": 10, "io": 10000}, "image": + null, "watchdog_enabled": true}], "results": 1, "page": 1, "pages": 1}' headers: Access-Control-Allow-Credentials: - "true" @@ -42,15 +195,15 @@ interactions: Connection: - keep-alive Content-Length: - - "648" + - "625" Content-Security-Policy: - default-src 'none' Content-Type: - application/json Date: - - Tue, 03 Jul 2018 01:38:48 GMT + - Sat, 08 Sep 2018 20:04:04 GMT Retry-After: - - "29" + - "118" Server: - nginx Strict-Transport-Security: @@ -71,11 +224,81 @@ interactions: X-Ratelimit-Limit: - "400" X-Ratelimit-Remaining: - - "394" + - "399" + X-Ratelimit-Reset: + - "1536437163" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10157365 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sat, 08 Sep 2018 20:04:04 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" X-Ratelimit-Reset: - - "1530581958" + - "1536437164" X-Spec-Version: - - 4.0.2 + - 4.0.4 X-Xss-Protection: - 1; mode=block status: 200 OK diff --git a/fixtures/TestUpdateInstanceConfig.yaml b/fixtures/TestUpdateInstanceConfig.yaml new file mode 100644 index 000000000..eba0bc39d --- /dev/null +++ b/fixtures/TestUpdateInstanceConfig.yaml @@ -0,0 +1,302 @@ +--- +version: 1 +interactions: +- request: + body: '{"region":"us-west","type":"g6-nanode-1","label":"linodego-test-instance","booted":false}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances + method: POST + response: + body: '{"region": "us-west", "alerts": {"network_in": 10, "io": 10000, "cpu": + 90, "transfer_quota": 80, "network_out": 10}, "created": "2018-01-02T03:04:05", + "label": "linodego-test-instance", "updated": "2018-01-02T03:04:05", "watchdog_enabled": + true, "image": null, "id": 10174070, "group": "", "ipv4": ["010.020.030.040"], + "status": "provisioning", "hypervisor": "kvm", "ipv6": "1234::5678/64", + "type": "g6-nanode-1", "backups": {"enabled": false, "schedule": {"day": null, + "window": null}}, "specs": {"vcpus": 1, "disk": 25600, "memory": 1024, "transfer": + 1000}}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "577" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:08 GMT + Retry-After: + - "75" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536513204" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"linodego-test-config","devices":{}}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174070/configs + method: POST + response: + body: '{"helpers": {"distro": true, "network": true, "devtmpfs_automount": true, + "updatedb_disabled": true, "modules_dep": true}, "virt_mode": "paravirt", "created": + "2018-01-02T03:04:05", "label": "linodego-test-config", "id": 11421187, "devices": + {"sdc": null, "sdd": null, "sda": null, "sdf": null, "sdb": null, "sde": null, + "sdg": null, "sdh": null}, "run_level": "default", "updated": "2018-01-02T03:04:05", + "memory_limit": 0, "kernel": "linode/latest-64bit", "comments": "", "initrd": + null, "root_device": "/dev/sda"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "516" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:08 GMT + Retry-After: + - "119" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "399" + X-Ratelimit-Reset: + - "1536513248" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: '{"label":"bar","comments":"","devices":{},"memory_limit":0,"init_rd":null,"root_device":"/dev/root"}' + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174070/configs/11421187 + method: PUT + response: + body: '{"root_device": "/dev/root", "updated": "2018-01-02T03:04:05", "virt_mode": + "paravirt", "initrd": null, "label": "bar", "created": "2018-01-02T03:04:05", + "comments": "", "memory_limit": 0, "kernel": "linode/latest-64bit", "run_level": + "default", "devices": {"sdb": null, "sdg": null, "sdh": null, "sda": null, "sdd": + null, "sde": null, "sdf": null, "sdc": null}, "helpers": {"distro": true, "modules_dep": + true, "devtmpfs_automount": true, "network": true, "updatedb_disabled": true}, + "id": 11421187}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "500" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:08 GMT + Retry-After: + - "18" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536513147" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Authorization: + - Bearer awesometokenawesometokenawesometoken + Content-Type: + - application/json + User-Agent: + - linodego 0.4.0 https://github.com/linode/linodego + url: https://api.linode.com/v4/linode/instances/10174070 + method: DELETE + response: + body: '{}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=60, s-maxage=60 + Connection: + - keep-alive + Content-Length: + - "2" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Date: + - Sun, 09 Sep 2018 17:12:08 GMT + Retry-After: + - "16" + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - linodes:read_write + X-Content-Type-Options: + - nosniff + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "400" + X-Ratelimit-Remaining: + - "398" + X-Ratelimit-Reset: + - "1536513145" + X-Spec-Version: + - 4.0.4 + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/instance_snapshots_test.go b/instance_snapshots_test.go index d8a2f1372..b642750c8 100644 --- a/instance_snapshots_test.go +++ b/instance_snapshots_test.go @@ -65,7 +65,7 @@ func TestListInstanceBackups(t *testing.T) { func setupInstanceBackup(t *testing.T, fixturesYaml string) (*linodego.Client, *linodego.Instance, *linodego.InstanceSnapshot, func(), error) { t.Helper() - client, instance, fixtureTeardown, err := setupInstanceWithoutDisks(t, fixturesYaml) + client, instance, _, fixtureTeardown, err := setupInstanceWithoutDisks(t, fixturesYaml) if err != nil { t.Errorf("Error creating instance, got error %v", err) } diff --git a/instances_test.go b/instances_test.go index df19ee140..1eb2157a9 100644 --- a/instances_test.go +++ b/instances_test.go @@ -2,6 +2,7 @@ package linodego_test import ( "context" + "strconv" "testing" "github.com/linode/linodego" @@ -11,31 +12,40 @@ func TestListInstances(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - client, teardown := createTestClient(t, "fixtures/TestListInstances") + client, instance, _, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestListInstances") defer teardown() - linodes, err := client.ListInstances(context.Background(), nil) + listOpts := linodego.NewListOptions(1, "{\"id\": "+strconv.Itoa(instance.ID)+"}") + linodes, err := client.ListInstances(context.Background(), listOpts) if err != nil { t.Errorf("Error listing instances, expected struct, got error %v", err) } - if len(linodes) == 0 { + if len(linodes) != 1 { t.Errorf("Expected a list of instances, but got %v", linodes) } + + if linodes[0].ID != instance.ID { + t.Errorf("Expected list of instances to include test instance, but got %v", linodes) + } } func TestGetInstance(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - client, teardown := createTestClient(t, "fixtures/TestGetInstance") + client, instance, _, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestGetInstance") defer teardown() - instance, err := client.GetInstance(context.Background(), TestInstanceID) + instanceGot, err := client.GetInstance(context.Background(), instance.ID) if err != nil { - t.Errorf("Error getting instance TestInstanceID, expected *LinodeInstance, got error %v", err) + t.Errorf("Error getting instance: %s", err) } + if instanceGot.ID != instance.ID { + t.Errorf("Expected instance ID %d to match %d", instanceGot.ID, instance.ID) + } + if instance.Specs.Disk <= 0 { - t.Errorf("Error in instance TestInstanceID spec for disk size, %v", instance.Specs) + t.Errorf("Error parsing instance spec for disk size: %v", instance.Specs) } } @@ -43,10 +53,10 @@ func TestListInstanceDisks(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - client, teardown := createTestClient(t, "fixtures/TestListInstanceDisks") + client, instance, teardown, err := setupInstance(t, "fixtures/TestListInstanceDisks") defer teardown() - disks, err := client.ListInstanceDisks(context.Background(), TestInstanceID, nil) + disks, err := client.ListInstanceDisks(context.Background(), instance.ID, nil) if err != nil { t.Errorf("Error listing instance disks, expected struct, got error %v", err) } @@ -59,26 +69,71 @@ func TestListInstanceConfigs(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - client, teardown := createTestClient(t, "fixtures/TestListInstanceConfigs") + client, instance, config, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestListInstanceConfigs") defer teardown() - configs, err := client.ListInstanceConfigs(context.Background(), TestInstanceID, nil) + configs, err := client.ListInstanceConfigs(context.Background(), instance.ID, nil) if err != nil { t.Errorf("Error listing instance configs, expected struct, got error %v", err) } if len(configs) == 0 { t.Errorf("Expected a list of instance configs, but got %v", configs) } + if configs[0].ID != config.ID { + t.Errorf("Expected config id %d, got %d", configs[0].ID, config.ID) + } +} + +func TestUpdateInstanceConfig(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + client, instance, config, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestUpdateInstanceConfig") + defer teardown() + + updateConfigOpts := linodego.InstanceConfigUpdateOptions{ + Label: "bar", + Devices: linodego.InstanceConfigDeviceMap{}, + RootDevice: "/dev/root", + } + + _, err = client.UpdateInstanceConfig(context.Background(), instance.ID, config.ID, updateConfigOpts) + if err != nil { + t.Error(err) + } } func TestListInstanceVolumes(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - client, teardown := createTestClient(t, "fixtures/TestListInstanceVolumes") + + client, instance, config, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestListInstanceVolumes_instance") defer teardown() + if err != nil { + t.Error(err) + } + + clientVol, volume, teardown, err := setupVolume(t, "fixtures/TestListInstanceVolumes") + defer teardown() + if err != nil { + t.Error(err) + } - volumes, err := client.ListInstanceVolumes(context.Background(), TestInstanceID, nil) + configOpts := linodego.InstanceConfigUpdateOptions{ + Label: "volume-test", + Devices: linodego.InstanceConfigDeviceMap{ + SDA: &linodego.InstanceConfigDevice{ + VolumeID: volume.ID, + }, + }, + } + _, err = client.UpdateInstanceConfig(context.Background(), instance.ID, config.ID, configOpts) + if err != nil { + t.Error(err) + } + + volumes, err := clientVol.ListInstanceVolumes(context.Background(), instance.ID, nil) if err != nil { t.Errorf("Error listing instance volumes, expected struct, got error %v", err) } @@ -90,11 +145,14 @@ func TestListInstanceVolumes(t *testing.T) { func setupInstance(t *testing.T, fixturesYaml string) (*linodego.Client, *linodego.Instance, func(), error) { t.Helper() client, fixtureTeardown := createTestClient(t, fixturesYaml) + falseBool := false createOpts := linodego.InstanceCreateOptions{ Label: "linodego-test-instance", RootPass: "R34lBAdP455", Region: "us-west", Type: "g6-nanode-1", + Image: "linode/debian9", + Booted: &falseBool, } instance, err := client.CreateInstance(context.Background(), createOpts) if err != nil { @@ -110,7 +168,7 @@ func setupInstance(t *testing.T, fixturesYaml string) (*linodego.Client, *linode return client, instance, teardown, err } -func setupInstanceWithoutDisks(t *testing.T, fixturesYaml string) (*linodego.Client, *linodego.Instance, func(), error) { +func setupInstanceWithoutDisks(t *testing.T, fixturesYaml string) (*linodego.Client, *linodego.Instance, *linodego.InstanceConfig, func(), error) { t.Helper() client, fixtureTeardown := createTestClient(t, fixturesYaml) falseBool := false @@ -123,15 +181,15 @@ func setupInstanceWithoutDisks(t *testing.T, fixturesYaml string) (*linodego.Cli instance, err := client.CreateInstance(context.Background(), createOpts) if err != nil { t.Errorf("Error creating test Instance: %s", err) - return nil, nil, fixtureTeardown, err + return nil, nil, nil, fixtureTeardown, err } configOpts := linodego.InstanceConfigCreateOptions{ Label: "linodego-test-config", } - _, err = client.CreateInstanceConfig(context.Background(), instance.ID, configOpts) + config, err := client.CreateInstanceConfig(context.Background(), instance.ID, configOpts) if err != nil { t.Errorf("Error creating config: %s", err) - return nil, nil, fixtureTeardown, err + return nil, nil, nil, fixtureTeardown, err } teardown := func() { @@ -140,5 +198,5 @@ func setupInstanceWithoutDisks(t *testing.T, fixturesYaml string) (*linodego.Cli } fixtureTeardown() } - return client, instance, teardown, err + return client, instance, config, teardown, err } diff --git a/volumes_test.go b/volumes_test.go index 7885e62ee..6898bf18b 100644 --- a/volumes_test.go +++ b/volumes_test.go @@ -83,12 +83,15 @@ func TestGetVolume(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - client, teardown := createTestClient(t, "fixtures/TestGetVolume") - defer teardown() + client, volume, teardownVolume, errVolume := setupVolume(t, "fixtures/TestGetVolume") + defer teardownVolume() + if errVolume != nil { + t.Error(errVolume) + } - _, err := client.GetVolume(context.Background(), TestVolumeID) + _, err := client.GetVolume(context.Background(), volume.ID) if err != nil { - t.Errorf("Error getting volume %d, expected *LinodeVolume, got error %v", TestVolumeID, err) + t.Errorf("Error getting volume %d, expected *LinodeVolume, got error %v", volume.ID, err) } } @@ -105,7 +108,7 @@ func TestWaitForVolumeLinodeID_nil(t *testing.T) { _, err = client.WaitForVolumeLinodeID(context.Background(), volume.ID, nil, 3) if err != nil { - t.Errorf("Error getting volume %d, expected *LinodeVolume, got error %v", TestVolumeID, err) + t.Errorf("Error getting volume %d, expected *LinodeVolume, got error %v", volume.ID, err) } } From dff010884298b42de9831251f6ae15fd22640299 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Sun, 9 Sep 2018 13:44:54 -0400 Subject: [PATCH 15/18] add authorized_keys to InstanceDiskCreateOptions --- instance_disks.go | 1 + 1 file changed, 1 insertion(+) diff --git a/instance_disks.go b/instance_disks.go index c8f6392d7..8c31491a2 100644 --- a/instance_disks.go +++ b/instance_disks.go @@ -50,6 +50,7 @@ type InstanceDiskCreateOptions struct { Filesystem string `json:"filesystem,omitempty"` AuthorizedKeys []string `json:"authorized_keys,omitempty"` + AuthorizedUsers []string `json:"authorized_users,omitempty"` ReadOnly bool `json:"read_only,omitempty"` StackscriptID int `json:"stackscript_id,omitempty"` StackscriptData map[string]string `json:"stackscript_data,omitempty"` From 7e5debd7bd68de9d12dcdf569c3131b97aa8e365 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Sun, 9 Sep 2018 14:06:46 -0400 Subject: [PATCH 16/18] root_device has no meaning as "", avoid pointers for omission --- instance_configs.go | 10 +++++----- instances_test.go | 20 ++++++++++++++++++-- profile_sshkeys.go | 6 ++---- profile_sshkeys_test.go | 3 +++ template.go | 7 ++----- template_test.go | 3 +++ 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/instance_configs.go b/instance_configs.go index e9aeb87f7..979a27495 100644 --- a/instance_configs.go +++ b/instance_configs.go @@ -84,10 +84,10 @@ type InstanceConfigUpdateOptions struct { MemoryLimit int `json:"memory_limit"` Kernel string `json:"kernel,omitempty"` // InitRD is nullable, permit the sending of null - InitRD *int `json:"init_rd"` - RootDevice *string `json:"root_device,omitempty"` - RunLevel string `json:"run_level,omitempty"` - VirtMode string `json:"virt_mode,omitempty"` + InitRD *int `json:"init_rd"` + RootDevice string `json:"root_device,omitempty"` + RunLevel string `json:"run_level,omitempty"` + VirtMode string `json:"virt_mode,omitempty"` } // GetCreateOptions converts a InstanceConfig to InstanceConfigCreateOptions for use in CreateInstanceConfig @@ -120,7 +120,7 @@ func (i InstanceConfig) GetUpdateOptions() InstanceConfigUpdateOptions { MemoryLimit: i.MemoryLimit, Kernel: i.Kernel, InitRD: copyInt(i.InitRD), - RootDevice: copyString(&i.RootDevice), + RootDevice: i.RootDevice, RunLevel: i.RunLevel, VirtMode: i.VirtMode, } diff --git a/instances_test.go b/instances_test.go index 1eb2157a9..b73fbedaa 100644 --- a/instances_test.go +++ b/instances_test.go @@ -15,6 +15,10 @@ func TestListInstances(t *testing.T) { client, instance, _, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestListInstances") defer teardown() + if err != nil { + t.Error(err) + } + listOpts := linodego.NewListOptions(1, "{\"id\": "+strconv.Itoa(instance.ID)+"}") linodes, err := client.ListInstances(context.Background(), listOpts) if err != nil { @@ -35,6 +39,9 @@ func TestGetInstance(t *testing.T) { } client, instance, _, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestGetInstance") defer teardown() + if err != nil { + t.Error(err) + } instanceGot, err := client.GetInstance(context.Background(), instance.ID) if err != nil { @@ -55,6 +62,9 @@ func TestListInstanceDisks(t *testing.T) { } client, instance, teardown, err := setupInstance(t, "fixtures/TestListInstanceDisks") defer teardown() + if err != nil { + t.Error(err) + } disks, err := client.ListInstanceDisks(context.Background(), instance.ID, nil) if err != nil { @@ -71,6 +81,9 @@ func TestListInstanceConfigs(t *testing.T) { } client, instance, config, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestListInstanceConfigs") defer teardown() + if err != nil { + t.Error(err) + } configs, err := client.ListInstanceConfigs(context.Background(), instance.ID, nil) if err != nil { @@ -90,10 +103,13 @@ func TestUpdateInstanceConfig(t *testing.T) { } client, instance, config, teardown, err := setupInstanceWithoutDisks(t, "fixtures/TestUpdateInstanceConfig") defer teardown() + if err != nil { + t.Error(err) + } updateConfigOpts := linodego.InstanceConfigUpdateOptions{ Label: "bar", - Devices: linodego.InstanceConfigDeviceMap{}, + Devices: &linodego.InstanceConfigDeviceMap{}, RootDevice: "/dev/root", } @@ -122,7 +138,7 @@ func TestListInstanceVolumes(t *testing.T) { configOpts := linodego.InstanceConfigUpdateOptions{ Label: "volume-test", - Devices: linodego.InstanceConfigDeviceMap{ + Devices: &linodego.InstanceConfigDeviceMap{ SDA: &linodego.InstanceConfigDevice{ VolumeID: volume.ID, }, diff --git a/profile_sshkeys.go b/profile_sshkeys.go index c6e20aed4..2ec4d4f71 100644 --- a/profile_sshkeys.go +++ b/profile_sshkeys.go @@ -154,9 +154,7 @@ func (c *Client) DeleteSSHKey(ctx context.Context, id int) error { } e = fmt.Sprintf("%s/%d", e, id) - if _, err := coupleAPIErrors(c.R(ctx).Delete(e)); err != nil { - return err - } + _, err = coupleAPIErrors(c.R(ctx).Delete(e)) + return err - return nil } diff --git a/profile_sshkeys_test.go b/profile_sshkeys_test.go index 8647ceeb5..267d1c4f4 100644 --- a/profile_sshkeys_test.go +++ b/profile_sshkeys_test.go @@ -38,6 +38,9 @@ func TestGetSSHKey_missing(t *testing.T) { func TestGetSSHKey_found(t *testing.T) { client, sshkey, teardown, err := setupSSHKey(t, "fixtures/TestGetSSHKey_found") defer teardown() + if err != nil { + t.Error(err) + } i, err := client.GetSSHKey(context.Background(), sshkey.ID) if err != nil { diff --git a/template.go b/template.go index 7edf0edc2..6048dded3 100644 --- a/template.go +++ b/template.go @@ -162,9 +162,6 @@ func (c *Client) DeleteTemplate(ctx context.Context, id int) error { } e = fmt.Sprintf("%s/%d", e, id) - if _, err := coupleAPIErrors(c.R(ctx).Delete(e)); err != nil { - return err - } - - return nil + _, err = coupleAPIErrors(c.R(ctx).Delete(e)) + return err } diff --git a/template_test.go b/template_test.go index 960ca0c67..b974971d3 100644 --- a/template_test.go +++ b/template_test.go @@ -31,6 +31,9 @@ func TestGetTemplate_missing(t *testing.T) { func TestGetTemplate_found(t *testing.T) { client, teardown := createTestClient(t, "fixtures/TestGetTemplate_found") defer teardown() + if err != nil { + t.Error(err) + } i, err := client.GetTemplate(context.Background(), "linode/ubuntu16.04lts") if err != nil { From 4d828dc3419a316b8a15f0cf71f825de526088b3 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Sun, 9 Sep 2018 14:33:31 -0400 Subject: [PATCH 17/18] v0.5.0 changelog bump --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25d7a042e..72740cffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Change Log + +## [v0.5.0](https://github.com/linode/linodego/compare/v0.4.0...v0.5.0) (2018-09-09) + +### Breaking Changes + +* List functions return slice of thing instead of slice of pointer to thing + +### Feature + +* add SSHKeys methods to client (also affects InstanceCreate, InstanceDiskCreate) +* add RebuildNodeBalancerConfig (and CreateNodeBalancerConfig with Nodes) + +### Fixes + +* Event.TimeRemaining wouldn't parse all possible API value +* Tests no longer rely on known/special instance and volume ids + ## [0.4.0](https://github.com/linode/linodego/compare/v0.3.0...0.4.0) (2018-08-27) From d0d31d8ca62fa3f7e4526ca0ce95de81e4ed001e Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Mon, 10 Sep 2018 08:17:52 -0400 Subject: [PATCH 18/18] v0.5.1 fixes imported Domain.Status values --- CHANGELOG.md | 7 +++++++ client.go | 2 +- domains.go | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72740cffc..8fc2594d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log + +## [v0.5.1](https://github.com/linode/linodego/compare/v0.5.0...v0.5.1) (2018-09-10) + +### Fixes + +* Domain.Status was not imported from API responses correctly + ## [v0.5.0](https://github.com/linode/linodego/compare/v0.4.0...v0.5.0) (2018-09-09) diff --git a/client.go b/client.go index 3d0aec4f6..81c51f692 100644 --- a/client.go +++ b/client.go @@ -19,7 +19,7 @@ const ( // APIProto connect to API with http(s) APIProto = "https" // Version of linodego - Version = "0.5.0" + Version = "0.5.1" // APIEnvVar environment var to check for API token APIEnvVar = "LINODE_TOKEN" // APISecondsPerPoll how frequently to poll for new Events diff --git a/domains.go b/domains.go index f0f048a82..4ae7167fa 100644 --- a/domains.go +++ b/domains.go @@ -21,7 +21,7 @@ type Domain struct { Group string `json:"group"` // Used to control whether this Domain is currently being rendered. - Status DomainStatus `json:"domain_status"` // Enum:"disabled" "active" "edit_mode" "has_errors" + Status DomainStatus `json:"status"` // Enum:"disabled" "active" "edit_mode" "has_errors" // A description for this Domain. This is for display purposes only. Description string `json:"description"`