diff --git a/Gopkg.lock b/Gopkg.lock index 761ea717d..bb923bf1d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -345,7 +345,7 @@ revision = "0b12d6b5" [[projects]] - digest = "0:" + digest = "1:8e36686e8b139f8fe240c1d5cf3a145bc675c22ff8e707857cdd3ae17b00d728" name = "github.com/json-iterator/go" packages = ["."] pruneopts = "NUT" diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go deleted file mode 100644 index ef385f3a9..000000000 --- a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go +++ /dev/null @@ -1,110 +0,0 @@ -package push - -//Licensed under the Apache License, Version 2.0 (the "License"); -//you may not use this file except in compliance with the License. -//You may obtain a copy of the License at -// -//http://www.apache.org/licenses/LICENSE-2.0 -// -//Unless required by applicable law or agreed to in writing, software -//distributed under the License is distributed on an "AS IS" BASIS, -//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -//See the License for the specific language governing permissions and -//limitations under the License. -// -// Code generated by Alibaba Cloud SDK Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" -) - -// PushNoticeToAndroid invokes the push.PushNoticeToAndroid API synchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoandroid.html -func (client *Client) PushNoticeToAndroid(request *PushNoticeToAndroidRequest) (response *PushNoticeToAndroidResponse, err error) { - response = CreatePushNoticeToAndroidResponse() - err = client.DoAction(request, response) - return -} - -// PushNoticeToAndroidWithChan invokes the push.PushNoticeToAndroid API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoandroid.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToAndroidWithChan(request *PushNoticeToAndroidRequest) (<-chan *PushNoticeToAndroidResponse, <-chan error) { - responseChan := make(chan *PushNoticeToAndroidResponse, 1) - errChan := make(chan error, 1) - err := client.AddAsyncTask(func() { - defer close(responseChan) - defer close(errChan) - response, err := client.PushNoticeToAndroid(request) - if err != nil { - errChan <- err - } else { - responseChan <- response - } - }) - if err != nil { - errChan <- err - close(responseChan) - close(errChan) - } - return responseChan, errChan -} - -// PushNoticeToAndroidWithCallback invokes the push.PushNoticeToAndroid API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoandroid.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToAndroidWithCallback(request *PushNoticeToAndroidRequest, callback func(response *PushNoticeToAndroidResponse, err error)) <-chan int { - result := make(chan int, 1) - err := client.AddAsyncTask(func() { - var response *PushNoticeToAndroidResponse - var err error - defer close(result) - response, err = client.PushNoticeToAndroid(request) - callback(response, err) - result <- 1 - }) - if err != nil { - defer close(result) - callback(nil, err) - result <- 0 - } - return result -} - -// PushNoticeToAndroidRequest is the request struct for api PushNoticeToAndroid -type PushNoticeToAndroidRequest struct { - *requests.RpcRequest - AppKey requests.Integer `position:"Query" name:"AppKey"` - Target string `position:"Query" name:"Target"` - TargetValue string `position:"Query" name:"TargetValue"` - Title string `position:"Query" name:"Title"` - Body string `position:"Query" name:"Body"` - JobKey string `position:"Query" name:"JobKey"` - ExtParameters string `position:"Query" name:"ExtParameters"` -} - -// PushNoticeToAndroidResponse is the response struct for api PushNoticeToAndroid -type PushNoticeToAndroidResponse struct { - *responses.BaseResponse - RequestId string `json:"RequestId" xml:"RequestId"` - MessageId string `json:"MessageId" xml:"MessageId"` -} - -// CreatePushNoticeToAndroidRequest creates a request to invoke PushNoticeToAndroid API -func CreatePushNoticeToAndroidRequest() (request *PushNoticeToAndroidRequest) { - request = &PushNoticeToAndroidRequest{ - RpcRequest: &requests.RpcRequest{}, - } - request.InitWithApiInfo("Push", "2016-08-01", "PushNoticeToAndroid", "", "") - return -} - -// CreatePushNoticeToAndroidResponse creates a response to parse from PushNoticeToAndroid response -func CreatePushNoticeToAndroidResponse() (response *PushNoticeToAndroidResponse) { - response = &PushNoticeToAndroidResponse{ - BaseResponse: &responses.BaseResponse{}, - } - return -} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go deleted file mode 100644 index 73d1a588e..000000000 --- a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go +++ /dev/null @@ -1,111 +0,0 @@ -package push - -//Licensed under the Apache License, Version 2.0 (the "License"); -//you may not use this file except in compliance with the License. -//You may obtain a copy of the License at -// -//http://www.apache.org/licenses/LICENSE-2.0 -// -//Unless required by applicable law or agreed to in writing, software -//distributed under the License is distributed on an "AS IS" BASIS, -//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -//See the License for the specific language governing permissions and -//limitations under the License. -// -// Code generated by Alibaba Cloud SDK Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" -) - -// PushNoticeToiOS invokes the push.PushNoticeToiOS API synchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoios.html -func (client *Client) PushNoticeToiOS(request *PushNoticeToiOSRequest) (response *PushNoticeToiOSResponse, err error) { - response = CreatePushNoticeToiOSResponse() - err = client.DoAction(request, response) - return -} - -// PushNoticeToiOSWithChan invokes the push.PushNoticeToiOS API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoios.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToiOSWithChan(request *PushNoticeToiOSRequest) (<-chan *PushNoticeToiOSResponse, <-chan error) { - responseChan := make(chan *PushNoticeToiOSResponse, 1) - errChan := make(chan error, 1) - err := client.AddAsyncTask(func() { - defer close(responseChan) - defer close(errChan) - response, err := client.PushNoticeToiOS(request) - if err != nil { - errChan <- err - } else { - responseChan <- response - } - }) - if err != nil { - errChan <- err - close(responseChan) - close(errChan) - } - return responseChan, errChan -} - -// PushNoticeToiOSWithCallback invokes the push.PushNoticeToiOS API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoios.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToiOSWithCallback(request *PushNoticeToiOSRequest, callback func(response *PushNoticeToiOSResponse, err error)) <-chan int { - result := make(chan int, 1) - err := client.AddAsyncTask(func() { - var response *PushNoticeToiOSResponse - var err error - defer close(result) - response, err = client.PushNoticeToiOS(request) - callback(response, err) - result <- 1 - }) - if err != nil { - defer close(result) - callback(nil, err) - result <- 0 - } - return result -} - -// PushNoticeToiOSRequest is the request struct for api PushNoticeToiOS -type PushNoticeToiOSRequest struct { - *requests.RpcRequest - AppKey requests.Integer `position:"Query" name:"AppKey"` - Target string `position:"Query" name:"Target"` - TargetValue string `position:"Query" name:"TargetValue"` - ApnsEnv string `position:"Query" name:"ApnsEnv"` - Title string `position:"Query" name:"Title"` - Body string `position:"Query" name:"Body"` - JobKey string `position:"Query" name:"JobKey"` - ExtParameters string `position:"Query" name:"ExtParameters"` -} - -// PushNoticeToiOSResponse is the response struct for api PushNoticeToiOS -type PushNoticeToiOSResponse struct { - *responses.BaseResponse - RequestId string `json:"RequestId" xml:"RequestId"` - MessageId string `json:"MessageId" xml:"MessageId"` -} - -// CreatePushNoticeToiOSRequest creates a request to invoke PushNoticeToiOS API -func CreatePushNoticeToiOSRequest() (request *PushNoticeToiOSRequest) { - request = &PushNoticeToiOSRequest{ - RpcRequest: &requests.RpcRequest{}, - } - request.InitWithApiInfo("Push", "2016-08-01", "PushNoticeToiOS", "", "") - return -} - -// CreatePushNoticeToiOSResponse creates a response to parse from PushNoticeToiOS response -func CreatePushNoticeToiOSResponse() (response *PushNoticeToiOSResponse) { - response = &PushNoticeToiOSResponse{ - BaseResponse: &responses.BaseResponse{}, - } - return -} diff --git a/vendor/github.com/packethost/packngo/LICENSE.txt b/vendor/github.com/packethost/packngo/LICENSE.txt new file mode 100644 index 000000000..57c50110c --- /dev/null +++ b/vendor/github.com/packethost/packngo/LICENSE.txt @@ -0,0 +1,56 @@ +Copyright (c) 2014 The packngo AUTHORS. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +====================== +Portions of the client are based on code at: +https://github.com/google/go-github/ and +https://github.com/digitalocean/godo + +Copyright (c) 2013 The go-github AUTHORS. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/github.com/packethost/packngo/batches.go b/vendor/github.com/packethost/packngo/batches.go new file mode 100644 index 000000000..ca314b37f --- /dev/null +++ b/vendor/github.com/packethost/packngo/batches.go @@ -0,0 +1,97 @@ +package packngo + +import ( + "fmt" +) + +const batchBasePath = "/batches" + +// BatchService interface defines available batch methods +type BatchService interface { + Get(batchID string, getOpt *GetOptions) (*Batch, *Response, error) + List(ProjectID string, listOpt *ListOptions) ([]Batch, *Response, error) + Create(projectID string, batches *BatchCreateRequest) ([]Batch, *Response, error) + Delete(string, bool) (*Response, error) +} + +// Batch type +type Batch struct { + ID string `json:"id"` + State string `json:"state,omitempty"` + Quantity int32 `json:"quantity,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + Href string `json:"href,omitempty"` + Project Href `json:"project,omitempty"` + Devices []Device `json:"devices,omitempty"` +} + +//BatchesList represents collection of batches +type batchesList struct { + Batches []Batch `json:"batches,omitempty"` +} + +// BatchCreateRequest type used to create batch of device instances +type BatchCreateRequest struct { + Batches []BatchCreateDevice `json:"batches"` +} + +// BatchCreateDevice type used to describe batch instances +type BatchCreateDevice struct { + DeviceCreateRequest + Quantity int32 `json:"quantity"` + FacilityDiversityLevel int32 `json:"facility_diversity_level,omitempty"` +} + +// BatchServiceOp implements BatchService +type BatchServiceOp struct { + client *Client +} + +// Get returns batch details +func (s *BatchServiceOp) Get(batchID string, getOpt *GetOptions) (*Batch, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", batchBasePath, batchID, params) + batch := new(Batch) + + resp, err := s.client.DoRequest("GET", path, nil, batch) + if err != nil { + return nil, resp, err + } + + return batch, resp, err +} + +// List returns batches on a project +func (s *BatchServiceOp) List(projectID string, listOpt *ListOptions) (batches []Batch, resp *Response, err error) { + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, batchBasePath, params) + subset := new(batchesList) + resp, err = s.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + batches = append(batches, subset.Batches...) + return batches, resp, err +} + +// Create function to create batch of device instances +func (s *BatchServiceOp) Create(projectID string, request *BatchCreateRequest) ([]Batch, *Response, error) { + path := fmt.Sprintf("%s/%s/devices/batch", projectBasePath, projectID) + + batches := new(batchesList) + resp, err := s.client.DoRequest("POST", path, request, batches) + + if err != nil { + return nil, resp, err + } + + return batches.Batches, resp, err +} + +// Delete function to remove an instance batch +func (s *BatchServiceOp) Delete(id string, removeDevices bool) (*Response, error) { + path := fmt.Sprintf("%s/%s?remove_associated_instances=%t", batchBasePath, id, removeDevices) + + return s.client.DoRequest("DELETE", path, nil, nil) +} diff --git a/vendor/github.com/packethost/packngo/bgp_configs.go b/vendor/github.com/packethost/packngo/bgp_configs.go new file mode 100644 index 000000000..aa21c5561 --- /dev/null +++ b/vendor/github.com/packethost/packngo/bgp_configs.go @@ -0,0 +1,81 @@ +package packngo + +import "fmt" + +var bgpConfigBasePath = "/bgp-config" + +// BGPConfigService interface defines available BGP config methods +type BGPConfigService interface { + Get(projectID string, getOpt *GetOptions) (*BGPConfig, *Response, error) + Create(string, CreateBGPConfigRequest) (*Response, error) + // Delete(configID string) (resp *Response, err error) TODO: Not in Packet API +} + +// BGPConfigServiceOp implements BgpConfigService +type BGPConfigServiceOp struct { + client *Client +} + +// CreateBGPConfigRequest struct +type CreateBGPConfigRequest struct { + DeploymentType string `json:"deployment_type,omitempty"` + Asn int `json:"asn,omitempty"` + Md5 string `json:"md5,omitempty"` + UseCase string `json:"use_case,omitempty"` +} + +// BGPConfig represents a Packet BGP Config +type BGPConfig struct { + ID string `json:"id,omitempty"` + Status string `json:"status,omitempty"` + DeploymentType string `json:"deployment_type,omitempty"` + Asn int `json:"asn,omitempty"` + RouteObject string `json:"route_object,omitempty"` + Md5 string `json:"md5,omitempty"` + MaxPrefix int `json:"max_prefix,omitempty"` + Project Project `json:"project,omitempty"` + CreatedAt Timestamp `json:"created_at,omitempty"` + RequestedAt Timestamp `json:"requested_at,omitempty"` + Sessions []BGPSession `json:"sessions,omitempty"` + Href string `json:"href,omitempty"` +} + +// Create function +func (s *BGPConfigServiceOp) Create(projectID string, request CreateBGPConfigRequest) (*Response, error) { + path := fmt.Sprintf("%s/%s%ss", projectBasePath, projectID, bgpConfigBasePath) + + resp, err := s.client.DoRequest("POST", path, request, nil) + if err != nil { + return resp, err + } + + return resp, err +} + +// Get function +func (s *BGPConfigServiceOp) Get(projectID string, getOpt *GetOptions) (bgpConfig *BGPConfig, resp *Response, err error) { + params := createGetOptionsURL(getOpt) + + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, bgpConfigBasePath, params) + + subset := new(BGPConfig) + + resp, err = s.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + return subset, resp, err +} + +// Delete function TODO: this is not implemented in the Packet API +// func (s *BGPConfigServiceOp) Delete(configID string) (resp *Response, err error) { +// path := fmt.Sprintf("%ss/%s", bgpConfigBasePath, configID) + +// resp, err = s.client.DoRequest("DELETE", path, nil, nil) +// if err != nil { +// return resp, err +// } + +// return resp, err +// } diff --git a/vendor/github.com/packethost/packngo/bgp_sessions.go b/vendor/github.com/packethost/packngo/bgp_sessions.go new file mode 100644 index 000000000..b18f6fa1a --- /dev/null +++ b/vendor/github.com/packethost/packngo/bgp_sessions.go @@ -0,0 +1,70 @@ +package packngo + +import "fmt" + +var bgpSessionBasePath = "/bgp/sessions" + +// BGPSessionService interface defines available BGP session methods +type BGPSessionService interface { + Get(string, *GetOptions) (*BGPSession, *Response, error) + Create(string, CreateBGPSessionRequest) (*BGPSession, *Response, error) + Delete(string) (*Response, error) +} + +type bgpSessionsRoot struct { + Sessions []BGPSession `json:"bgp_sessions"` + Meta meta `json:"meta"` +} + +// BGPSessionServiceOp implements BgpSessionService +type BGPSessionServiceOp struct { + client *Client +} + +// BGPSession represents a Packet BGP Session +type BGPSession struct { + ID string `json:"id,omitempty"` + Status string `json:"status,omitempty"` + LearnedRoutes []string `json:"learned_routes,omitempty"` + AddressFamily string `json:"address_family,omitempty"` + Device Device `json:"device,omitempty"` + Href string `json:"href,omitempty"` +} + +// CreateBGPSessionRequest struct +type CreateBGPSessionRequest struct { + AddressFamily string `json:"address_family"` +} + +// Create function +func (s *BGPSessionServiceOp) Create(deviceID string, request CreateBGPSessionRequest) (*BGPSession, *Response, error) { + path := fmt.Sprintf("%s/%s%s", deviceBasePath, deviceID, bgpSessionBasePath) + session := new(BGPSession) + + resp, err := s.client.DoRequest("POST", path, request, session) + if err != nil { + return nil, resp, err + } + + return session, resp, err +} + +// Delete function +func (s *BGPSessionServiceOp) Delete(id string) (*Response, error) { + path := fmt.Sprintf("%s/%s", bgpSessionBasePath, id) + + return s.client.DoRequest("DELETE", path, nil, nil) +} + +// Get function +func (s *BGPSessionServiceOp) Get(id string, getOpt *GetOptions) (session *BGPSession, response *Response, err error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", bgpSessionBasePath, id, params) + session = new(BGPSession) + response, err = s.client.DoRequest("GET", path, nil, session) + if err != nil { + return nil, response, err + } + + return session, response, err +} diff --git a/vendor/github.com/packethost/packngo/billing_address.go b/vendor/github.com/packethost/packngo/billing_address.go new file mode 100644 index 000000000..93255b322 --- /dev/null +++ b/vendor/github.com/packethost/packngo/billing_address.go @@ -0,0 +1,7 @@ +package packngo + +type BillingAddress struct { + StreetAddress string `json:"street_address,omitempty"` + PostalCode string `json:"postal_code,omitempty"` + CountryCode string `json:"country_code_alpha2,omitempty"` +} diff --git a/vendor/github.com/packethost/packngo/capacities.go b/vendor/github.com/packethost/packngo/capacities.go new file mode 100644 index 000000000..fa51413be --- /dev/null +++ b/vendor/github.com/packethost/packngo/capacities.go @@ -0,0 +1,79 @@ +package packngo + +const capacityBasePath = "/capacity" + +// CapacityService interface defines available capacity methods +type CapacityService interface { + List() (*CapacityReport, *Response, error) + Check(*CapacityInput) (*CapacityInput, *Response, error) +} + +// CapacityInput struct +type CapacityInput struct { + Servers []ServerInfo `json:"servers,omitempty"` +} + +// ServerInfo struct +type ServerInfo struct { + Facility string `json:"facility,omitempty"` + Plan string `json:"plan,omitempty"` + Quantity int `json:"quantity,omitempty"` + Available bool `json:"available,omitempty"` +} + +type capacityRoot struct { + Capacity CapacityReport `json:"capacity,omitempty"` +} + +// CapacityReport map +type CapacityReport map[string]map[string]CapacityPerBaremetal + +// // CapacityPerFacility struct +// type CapacityPerFacility struct { +// T1SmallX86 *CapacityPerBaremetal `json:"t1.small.x86,omitempty"` +// C1SmallX86 *CapacityPerBaremetal `json:"c1.small.x86,omitempty"` +// M1XlargeX86 *CapacityPerBaremetal `json:"m1.xlarge.x86,omitempty"` +// C1XlargeX86 *CapacityPerBaremetal `json:"c1.xlarge.x86,omitempty"` + +// Baremetal0 *CapacityPerBaremetal `json:"baremetal_0,omitempty"` +// Baremetal1 *CapacityPerBaremetal `json:"baremetal_1,omitempty"` +// Baremetal1e *CapacityPerBaremetal `json:"baremetal_1e,omitempty"` +// Baremetal2 *CapacityPerBaremetal `json:"baremetal_2,omitempty"` +// Baremetal2a *CapacityPerBaremetal `json:"baremetal_2a,omitempty"` +// Baremetal2a2 *CapacityPerBaremetal `json:"baremetal_2a2,omitempty"` +// Baremetal3 *CapacityPerBaremetal `json:"baremetal_3,omitempty"` +// } + +// CapacityPerBaremetal struct +type CapacityPerBaremetal struct { + Level string `json:"level,omitempty"` +} + +// CapacityList struct +type CapacityList struct { + Capacity CapacityReport `json:"capacity,omitempty"` +} + +// CapacityServiceOp implements CapacityService +type CapacityServiceOp struct { + client *Client +} + +// List returns a list of facilities and plans with their current capacity. +func (s *CapacityServiceOp) List() (*CapacityReport, *Response, error) { + root := new(capacityRoot) + + resp, err := s.client.DoRequest("GET", capacityBasePath, nil, root) + if err != nil { + return nil, resp, err + } + + return &root.Capacity, nil, nil +} + +// Check validates if a deploy can be fulfilled. +func (s *CapacityServiceOp) Check(input *CapacityInput) (cap *CapacityInput, resp *Response, err error) { + cap = new(CapacityInput) + resp, err = s.client.DoRequest("POST", capacityBasePath, input, cap) + return cap, resp, err +} diff --git a/vendor/github.com/packethost/packngo/devices.go b/vendor/github.com/packethost/packngo/devices.go new file mode 100644 index 000000000..277436334 --- /dev/null +++ b/vendor/github.com/packethost/packngo/devices.go @@ -0,0 +1,279 @@ +package packngo + +import ( + "fmt" +) + +const deviceBasePath = "/devices" + +// DeviceService interface defines available device methods +type DeviceService interface { + List(ProjectID string, listOpt *ListOptions) ([]Device, *Response, error) + Get(DeviceID string, getOpt *GetOptions) (*Device, *Response, error) + Create(*DeviceCreateRequest) (*Device, *Response, error) + Update(string, *DeviceUpdateRequest) (*Device, *Response, error) + Delete(string) (*Response, error) + Reboot(string) (*Response, error) + PowerOff(string) (*Response, error) + PowerOn(string) (*Response, error) + Lock(string) (*Response, error) + Unlock(string) (*Response, error) + ListBGPSessions(deviceID string, listOpt *ListOptions) ([]BGPSession, *Response, error) + ListEvents(string, *ListOptions) ([]Event, *Response, error) +} + +type devicesRoot struct { + Devices []Device `json:"devices"` + Meta meta `json:"meta"` +} + +// Device represents a Packet device +type Device struct { + ID string `json:"id"` + Href string `json:"href,omitempty"` + Hostname string `json:"hostname,omitempty"` + State string `json:"state,omitempty"` + Created string `json:"created_at,omitempty"` + Updated string `json:"updated_at,omitempty"` + Locked bool `json:"locked,omitempty"` + BillingCycle string `json:"billing_cycle,omitempty"` + Storage map[string]interface{} `json:"storage,omitempty"` + Tags []string `json:"tags,omitempty"` + Network []*IPAddressAssignment `json:"ip_addresses"` + Volumes []*Volume `json:"volumes"` + OS *OS `json:"operating_system,omitempty"` + Plan *Plan `json:"plan,omitempty"` + Facility *Facility `json:"facility,omitempty"` + Project *Project `json:"project,omitempty"` + ProvisionEvents []*Event `json:"provisioning_events,omitempty"` + ProvisionPer float32 `json:"provisioning_percentage,omitempty"` + UserData string `json:"userdata,omitempty"` + RootPassword string `json:"root_password,omitempty"` + IPXEScriptURL string `json:"ipxe_script_url,omitempty"` + AlwaysPXE bool `json:"always_pxe,omitempty"` + HardwareReservation Href `json:"hardware_reservation,omitempty"` + SpotInstance bool `json:"spot_instance,omitempty"` + SpotPriceMax float64 `json:"spot_price_max,omitempty"` + TerminationTime *Timestamp `json:"termination_time,omitempty"` + NetworkPorts []Port `json:"network_ports,omitempty"` + CustomData map[string]interface{} `json:"customdata,omitempty"` + SSHKeys []SSHKey `json:"ssh_keys,omitempty"` +} + +func (d Device) String() string { + return Stringify(d) +} + +// DeviceCreateRequest type used to create a Packet device +type DeviceCreateRequest struct { + Hostname string `json:"hostname"` + Plan string `json:"plan"` + Facility []string `json:"facility"` + OS string `json:"operating_system"` + BillingCycle string `json:"billing_cycle"` + ProjectID string `json:"project_id"` + UserData string `json:"userdata"` + Storage string `json:"storage,omitempty"` + Tags []string `json:"tags"` + IPXEScriptURL string `json:"ipxe_script_url,omitempty"` + PublicIPv4SubnetSize int `json:"public_ipv4_subnet_size,omitempty"` + AlwaysPXE bool `json:"always_pxe,omitempty"` + HardwareReservationID string `json:"hardware_reservation_id,omitempty"` + SpotInstance bool `json:"spot_instance,omitempty"` + SpotPriceMax float64 `json:"spot_price_max,omitempty,string"` + TerminationTime *Timestamp `json:"termination_time,omitempty"` + CustomData string `json:"customdata,omitempty"` + // UserSSHKeys is a list of user UUIDs - essentialy a list of + // collaborators. The users must be a collaborator in the same project + // where the device is created. The user's SSH keys then go to the + // device. + UserSSHKeys []string `json:"user_ssh_keys,omitempty"` + // Project SSHKeys is a list of SSHKeys resource UUIDs. If this param + // is supplied, only the listed SSHKeys will go to the device. + // Any other Project SSHKeys and any User SSHKeys will not be present + // in the device. + ProjectSSHKeys []string `json:"project_ssh_keys,omitempty"` + Features map[string]string `json:"features,omitempty"` +} + +// DeviceUpdateRequest type used to update a Packet device +type DeviceUpdateRequest struct { + Hostname *string `json:"hostname,omitempty"` + Description *string `json:"description,omitempty"` + UserData *string `json:"userdata,omitempty"` + Locked *bool `json:"locked,omitempty"` + Tags *[]string `json:"tags,omitempty"` + AlwaysPXE *bool `json:"always_pxe,omitempty"` + IPXEScriptURL *string `json:"ipxe_script_url,omitempty"` + CustomData *string `json:"customdata,omitempty"` +} + +func (d DeviceCreateRequest) String() string { + return Stringify(d) +} + +// DeviceActionRequest type used to execute actions on devices +type DeviceActionRequest struct { + Type string `json:"type"` +} + +func (d DeviceActionRequest) String() string { + return Stringify(d) +} + +// DeviceServiceOp implements DeviceService +type DeviceServiceOp struct { + client *Client +} + +// List returns devices on a project +func (s *DeviceServiceOp) List(projectID string, listOpt *ListOptions) (devices []Device, resp *Response, err error) { + listOpt = makeSureListOptionsInclude(listOpt, "facility") + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, deviceBasePath, params) + + for { + subset := new(devicesRoot) + + resp, err = s.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + devices = append(devices, subset.Devices...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + + return + } +} + +// Get returns a device by id +func (s *DeviceServiceOp) Get(deviceID string, getOpt *GetOptions) (*Device, *Response, error) { + getOpt = makeSureGetOptionsInclude(getOpt, "facility") + params := createGetOptionsURL(getOpt) + + path := fmt.Sprintf("%s/%s?%s", deviceBasePath, deviceID, params) + device := new(Device) + resp, err := s.client.DoRequest("GET", path, nil, device) + if err != nil { + return nil, resp, err + } + return device, resp, err +} + +// Create creates a new device +func (s *DeviceServiceOp) Create(createRequest *DeviceCreateRequest) (*Device, *Response, error) { + path := fmt.Sprintf("%s/%s%s", projectBasePath, createRequest.ProjectID, deviceBasePath) + device := new(Device) + + resp, err := s.client.DoRequest("POST", path, createRequest, device) + if err != nil { + return nil, resp, err + } + + return device, resp, err +} + +// Update updates an existing device +func (s *DeviceServiceOp) Update(deviceID string, updateRequest *DeviceUpdateRequest) (*Device, *Response, error) { + path := fmt.Sprintf("%s/%s?include=facility", deviceBasePath, deviceID) + device := new(Device) + + resp, err := s.client.DoRequest("PUT", path, updateRequest, device) + if err != nil { + return nil, resp, err + } + + return device, resp, err +} + +// Delete deletes a device +func (s *DeviceServiceOp) Delete(deviceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID) + + return s.client.DoRequest("DELETE", path, nil, nil) +} + +// Reboot reboots on a device +func (s *DeviceServiceOp) Reboot(deviceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s/actions", deviceBasePath, deviceID) + action := &DeviceActionRequest{Type: "reboot"} + + return s.client.DoRequest("POST", path, action, nil) +} + +// PowerOff powers on a device +func (s *DeviceServiceOp) PowerOff(deviceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s/actions", deviceBasePath, deviceID) + action := &DeviceActionRequest{Type: "power_off"} + + return s.client.DoRequest("POST", path, action, nil) +} + +// PowerOn powers on a device +func (s *DeviceServiceOp) PowerOn(deviceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s/actions", deviceBasePath, deviceID) + action := &DeviceActionRequest{Type: "power_on"} + + return s.client.DoRequest("POST", path, action, nil) +} + +type lockType struct { + Locked bool `json:"locked"` +} + +// Lock sets a device to "locked" +func (s *DeviceServiceOp) Lock(deviceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID) + action := lockType{Locked: true} + + return s.client.DoRequest("PATCH", path, action, nil) +} + +// Unlock sets a device to "unlocked" +func (s *DeviceServiceOp) Unlock(deviceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", deviceBasePath, deviceID) + action := lockType{Locked: false} + + return s.client.DoRequest("PATCH", path, action, nil) +} + +// ListBGPSessions returns all BGP Sessions associated with the device +func (s *DeviceServiceOp) ListBGPSessions(deviceID string, listOpt *ListOptions) (bgpSessions []BGPSession, resp *Response, err error) { + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s/%s%s?%s", deviceBasePath, deviceID, bgpSessionBasePath, params) + + for { + subset := new(bgpSessionsRoot) + + resp, err = s.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + bgpSessions = append(bgpSessions, subset.Sessions...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + return + } +} + +// ListEvents returns list of device events +func (s *DeviceServiceOp) ListEvents(deviceID string, listOpt *ListOptions) ([]Event, *Response, error) { + path := fmt.Sprintf("%s/%s%s", deviceBasePath, deviceID, eventBasePath) + + return listEvents(s.client, path, listOpt) +} diff --git a/vendor/github.com/packethost/packngo/email.go b/vendor/github.com/packethost/packngo/email.go new file mode 100644 index 000000000..acce8999b --- /dev/null +++ b/vendor/github.com/packethost/packngo/email.go @@ -0,0 +1,87 @@ +package packngo + +import "fmt" + +const emailBasePath = "/emails" + +// EmailRequest type used to add an email address to the current user +type EmailRequest struct { + Address string `json:"address,omitempty"` + Default *bool `json:"default,omitempty"` +} + +// EmailService interface defines available email methods +type EmailService interface { + Get(string, *GetOptions) (*Email, *Response, error) + Create(*EmailRequest) (*Email, *Response, error) + Update(string, *EmailRequest) (*Email, *Response, error) + Delete(string) (*Response, error) +} + +// Email represents a user's email address +type Email struct { + ID string `json:"id"` + Address string `json:"address"` + Default bool `json:"default,omitempty"` + URL string `json:"href,omitempty"` +} + +func (e Email) String() string { + return Stringify(e) +} + +// EmailServiceOp implements EmailService +type EmailServiceOp struct { + client *Client +} + +// Get retrieves an email by id +func (s *EmailServiceOp) Get(emailID string, getOpt *GetOptions) (*Email, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", emailBasePath, emailID, params) + email := new(Email) + + resp, err := s.client.DoRequest("GET", path, nil, email) + if err != nil { + return nil, resp, err + } + + return email, resp, err +} + +// Create adds a new email address to the current user. +func (s *EmailServiceOp) Create(request *EmailRequest) (*Email, *Response, error) { + email := new(Email) + + resp, err := s.client.DoRequest("POST", emailBasePath, request, email) + if err != nil { + return nil, resp, err + } + + return email, resp, err +} + +// Delete removes the email addres from the current user account +func (s *EmailServiceOp) Delete(emailID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", emailBasePath, emailID) + + resp, err := s.client.DoRequest("DELETE", path, nil, nil) + if err != nil { + return resp, err + } + + return resp, err +} + +// Update email parameters +func (s *EmailServiceOp) Update(emailID string, request *EmailRequest) (*Email, *Response, error) { + email := new(Email) + path := fmt.Sprintf("%s/%s", emailBasePath, emailID) + + resp, err := s.client.DoRequest("PUT", path, request, email) + if err != nil { + return nil, resp, err + } + + return email, resp, err +} diff --git a/vendor/github.com/packethost/packngo/events.go b/vendor/github.com/packethost/packngo/events.go new file mode 100644 index 000000000..78ec9b7f5 --- /dev/null +++ b/vendor/github.com/packethost/packngo/events.go @@ -0,0 +1,104 @@ +package packngo + +import "fmt" + +const eventBasePath = "/events" + +// Event struct +type Event struct { + ID string `json:"id,omitempty"` + State string `json:"state,omitempty"` + Type string `json:"type,omitempty"` + Body string `json:"body,omitempty"` + Relationships []Href `json:"relationships,omitempty"` + Interpolated string `json:"interpolated,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + Href string `json:"href,omitempty"` +} + +type eventsRoot struct { + Events []Event `json:"events,omitempty"` + Meta meta `json:"meta,omitempty"` +} + +// EventService interface defines available event functions +type EventService interface { + List(*ListOptions) ([]Event, *Response, error) + Get(string, *GetOptions) (*Event, *Response, error) +} + +// EventServiceOp implements EventService +type EventServiceOp struct { + client *Client +} + +// List returns all events +func (s *EventServiceOp) List(listOpt *ListOptions) ([]Event, *Response, error) { + return listEvents(s.client, eventBasePath, listOpt) +} + +// Get returns an event by ID +func (s *EventServiceOp) Get(eventID string, getOpt *GetOptions) (*Event, *Response, error) { + path := fmt.Sprintf("%s/%s", eventBasePath, eventID) + return get(s.client, path, getOpt) +} + +// list helper function for all event functions +func listEvents(client *Client, path string, listOpt *ListOptions) (events []Event, resp *Response, err error) { + params := createListOptionsURL(listOpt) + path = fmt.Sprintf("%s?%s", path, params) + + for { + subset := new(eventsRoot) + + resp, err = client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + events = append(events, subset.Events...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + + return + } + +} + +// list helper function for all event functions +/* +func listEvents(client *Client, path string, listOpt *ListOptions) ([]Event, *Response, error) { + params := createListOptionsURL(listOpt) + root := new(eventsRoot) + + path = fmt.Sprintf("%s?%s", path, params) + + resp, err := client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + return root.Events, resp, err +} +*/ + +func get(client *Client, path string, getOpt *GetOptions) (*Event, *Response, error) { + params := createGetOptionsURL(getOpt) + + event := new(Event) + + path = fmt.Sprintf("%s?%s", path, params) + + resp, err := client.DoRequest("GET", path, nil, event) + if err != nil { + return nil, resp, err + } + + return event, resp, err +} diff --git a/vendor/github.com/packethost/packngo/facilities.go b/vendor/github.com/packethost/packngo/facilities.go new file mode 100644 index 000000000..fd4a7bf91 --- /dev/null +++ b/vendor/github.com/packethost/packngo/facilities.go @@ -0,0 +1,56 @@ +package packngo + +import "fmt" + +const facilityBasePath = "/facilities" + +// FacilityService interface defines available facility methods +type FacilityService interface { + List(*ListOptions) ([]Facility, *Response, error) +} + +type facilityRoot struct { + Facilities []Facility `json:"facilities"` +} + +// Facility represents a Packet facility +type Facility struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` + Code string `json:"code,omitempty"` + Features []string `json:"features,omitempty"` + Address *Address `json:"address,omitempty"` + URL string `json:"href,omitempty"` +} + +func (f Facility) String() string { + return Stringify(f) +} + +// Address - the physical address of the facility +type Address struct { + ID string `json:"id,omitempty"` +} + +func (a Address) String() string { + return Stringify(a) +} + +// FacilityServiceOp implements FacilityService +type FacilityServiceOp struct { + client *Client +} + +// List returns all facilities +func (s *FacilityServiceOp) List(listOpt *ListOptions) ([]Facility, *Response, error) { + root := new(facilityRoot) + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s?%s", facilityBasePath, params) + + resp, err := s.client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + return root.Facilities, resp, err +} diff --git a/vendor/github.com/packethost/packngo/hardware_reservations.go b/vendor/github.com/packethost/packngo/hardware_reservations.go new file mode 100644 index 000000000..efa3d6269 --- /dev/null +++ b/vendor/github.com/packethost/packngo/hardware_reservations.go @@ -0,0 +1,94 @@ +package packngo + +import "fmt" + +const hardwareReservationBasePath = "/hardware-reservations" + +// HardwareReservationService interface defines available hardware reservation functions +type HardwareReservationService interface { + Get(hardwareReservationID string, getOpt *GetOptions) (*HardwareReservation, *Response, error) + List(projectID string, listOpt *ListOptions) ([]HardwareReservation, *Response, error) + Move(string, string) (*HardwareReservation, *Response, error) +} + +// HardwareReservationServiceOp implements HardwareReservationService +type HardwareReservationServiceOp struct { + client *Client +} + +// HardwareReservation struct +type HardwareReservation struct { + ID string `json:"id,omitempty"` + ShortID string `json:"short_id,omitempty"` + Facility Facility `json:"facility,omitempty"` + Plan Plan `json:"plan,omitempty"` + Href string `json:"href,omitempty"` + Project Project `json:"project,omitempty"` + Device *Device `json:"device,omitempty"` + CreatedAt Timestamp `json:"created_at,omitempty"` +} + +type hardwareReservationRoot struct { + HardwareReservations []HardwareReservation `json:"hardware_reservations"` + Meta meta `json:"meta"` +} + +// List returns all hardware reservations for a given project +func (s *HardwareReservationServiceOp) List(projectID string, listOpt *ListOptions) (reservations []HardwareReservation, resp *Response, err error) { + root := new(hardwareReservationRoot) + params := createListOptionsURL(listOpt) + + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, hardwareReservationBasePath, params) + + for { + subset := new(hardwareReservationRoot) + + resp, err = s.client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + reservations = append(reservations, root.HardwareReservations...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + + return + } +} + +// Get returns a single hardware reservation +func (s *HardwareReservationServiceOp) Get(hardwareReservationdID string, getOpt *GetOptions) (*HardwareReservation, *Response, error) { + params := createGetOptionsURL(getOpt) + + hardwareReservation := new(HardwareReservation) + + path := fmt.Sprintf("%s/%s?%s", hardwareReservationBasePath, hardwareReservationdID, params) + + resp, err := s.client.DoRequest("GET", path, nil, hardwareReservation) + if err != nil { + return nil, resp, err + } + + return hardwareReservation, resp, err +} + +// Move a hardware reservation to another project +func (s *HardwareReservationServiceOp) Move(hardwareReservationdID, projectID string) (*HardwareReservation, *Response, error) { + hardwareReservation := new(HardwareReservation) + path := fmt.Sprintf("%s/%s/%s", hardwareReservationBasePath, hardwareReservationdID, "move") + body := map[string]string{} + body["project_id"] = projectID + + resp, err := s.client.DoRequest("POST", path, body, hardwareReservation) + if err != nil { + return nil, resp, err + } + + return hardwareReservation, resp, err +} diff --git a/vendor/github.com/packethost/packngo/ip.go b/vendor/github.com/packethost/packngo/ip.go new file mode 100644 index 000000000..79501a426 --- /dev/null +++ b/vendor/github.com/packethost/packngo/ip.go @@ -0,0 +1,196 @@ +package packngo + +import ( + "fmt" +) + +const ipBasePath = "/ips" + +// DeviceIPService handles assignment of addresses from reserved blocks to instances in a project. +type DeviceIPService interface { + Assign(deviceID string, assignRequest *AddressStruct) (*IPAddressAssignment, *Response, error) + Unassign(assignmentID string) (*Response, error) + Get(assignmentID string, getOpt *GetOptions) (*IPAddressAssignment, *Response, error) +} + +// ProjectIPService handles reservation of IP address blocks for a project. +type ProjectIPService interface { + Get(reservationID string, getOpt *GetOptions) (*IPAddressReservation, *Response, error) + List(projectID string) ([]IPAddressReservation, *Response, error) + Request(projectID string, ipReservationReq *IPReservationRequest) (*IPAddressReservation, *Response, error) + Remove(ipReservationID string) (*Response, error) + AvailableAddresses(ipReservationID string, r *AvailableRequest) ([]string, *Response, error) +} + +type ipAddressCommon struct { + ID string `json:"id"` + Address string `json:"address"` + Gateway string `json:"gateway"` + Network string `json:"network"` + AddressFamily int `json:"address_family"` + Netmask string `json:"netmask"` + Public bool `json:"public"` + CIDR int `json:"cidr"` + Created string `json:"created_at,omitempty"` + Updated string `json:"updated_at,omitempty"` + Href string `json:"href"` + Management bool `json:"management"` + Manageable bool `json:"manageable"` + Project Href `json:"project"` +} + +// IPAddressReservation is created when user sends IP reservation request for a project (considering it's within quota). +type IPAddressReservation struct { + ipAddressCommon + Assignments []Href `json:"assignments"` + Facility Facility `json:"facility,omitempty"` + Available string `json:"available"` + Addon bool `json:"addon"` + Bill bool `json:"bill"` +} + +// AvailableResponse is a type for listing of available addresses from a reserved block. +type AvailableResponse struct { + Available []string `json:"available"` +} + +// AvailableRequest is a type for listing available addresses from a reserved block. +type AvailableRequest struct { + CIDR int `json:"cidr"` +} + +// IPAddressAssignment is created when an IP address from reservation block is assigned to a device. +type IPAddressAssignment struct { + ipAddressCommon + AssignedTo Href `json:"assigned_to"` +} + +// IPReservationRequest represents the body of a reservation request. +type IPReservationRequest struct { + Type string `json:"type"` + Quantity int `json:"quantity"` + Comments string `json:"comments"` + Facility string `json:"facility"` +} + +// AddressStruct is a helper type for request/response with dict like {"address": ... } +type AddressStruct struct { + Address string `json:"address"` +} + +func deleteFromIP(client *Client, resourceID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", ipBasePath, resourceID) + + return client.DoRequest("DELETE", path, nil, nil) +} + +func (i IPAddressReservation) String() string { + return Stringify(i) +} + +func (i IPAddressAssignment) String() string { + return Stringify(i) +} + +// DeviceIPServiceOp is interface for IP-address assignment methods. +type DeviceIPServiceOp struct { + client *Client +} + +// Unassign unassigns an IP address from the device to which it is currently assigned. +// This will remove the relationship between an IP and the device and will make the IP +// address available to be assigned to another device. +func (i *DeviceIPServiceOp) Unassign(assignmentID string) (*Response, error) { + return deleteFromIP(i.client, assignmentID) +} + +// Assign assigns an IP address to a device. +// The IP address must be in one of the IP ranges assigned to the device’s project. +func (i *DeviceIPServiceOp) Assign(deviceID string, assignRequest *AddressStruct) (*IPAddressAssignment, *Response, error) { + path := fmt.Sprintf("%s/%s%s", deviceBasePath, deviceID, ipBasePath) + ipa := new(IPAddressAssignment) + + resp, err := i.client.DoRequest("POST", path, assignRequest, ipa) + if err != nil { + return nil, resp, err + } + + return ipa, resp, err +} + +// Get returns assignment by ID. +func (i *DeviceIPServiceOp) Get(assignmentID string, getOpt *GetOptions) (*IPAddressAssignment, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", ipBasePath, assignmentID, params) + ipa := new(IPAddressAssignment) + + resp, err := i.client.DoRequest("GET", path, nil, ipa) + if err != nil { + return nil, resp, err + } + + return ipa, resp, err +} + +// ProjectIPServiceOp is interface for IP assignment methods. +type ProjectIPServiceOp struct { + client *Client +} + +// Get returns reservation by ID. +func (i *ProjectIPServiceOp) Get(reservationID string, getOpt *GetOptions) (*IPAddressReservation, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", ipBasePath, reservationID, params) + ipr := new(IPAddressReservation) + + resp, err := i.client.DoRequest("GET", path, nil, ipr) + if err != nil { + return nil, resp, err + } + + return ipr, resp, err +} + +// List provides a list of IP resevations for a single project. +func (i *ProjectIPServiceOp) List(projectID string) ([]IPAddressReservation, *Response, error) { + path := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, ipBasePath) + reservations := new(struct { + Reservations []IPAddressReservation `json:"ip_addresses"` + }) + + resp, err := i.client.DoRequest("GET", path, nil, reservations) + if err != nil { + return nil, resp, err + } + return reservations.Reservations, resp, nil +} + +// Request requests more IP space for a project in order to have additional IP addresses to assign to devices. +func (i *ProjectIPServiceOp) Request(projectID string, ipReservationReq *IPReservationRequest) (*IPAddressReservation, *Response, error) { + path := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, ipBasePath) + ipr := new(IPAddressReservation) + + resp, err := i.client.DoRequest("POST", path, ipReservationReq, ipr) + if err != nil { + return nil, resp, err + } + return ipr, resp, err +} + +// Remove removes an IP reservation from the project. +func (i *ProjectIPServiceOp) Remove(ipReservationID string) (*Response, error) { + return deleteFromIP(i.client, ipReservationID) +} + +// AvailableAddresses lists addresses available from a reserved block +func (i *ProjectIPServiceOp) AvailableAddresses(ipReservationID string, r *AvailableRequest) ([]string, *Response, error) { + path := fmt.Sprintf("%s/%s/available?cidr=%d", ipBasePath, ipReservationID, r.CIDR) + ar := new(AvailableResponse) + + resp, err := i.client.DoRequest("GET", path, r, ar) + if err != nil { + return nil, resp, err + } + return ar.Available, resp, nil + +} diff --git a/vendor/github.com/packethost/packngo/notifications.go b/vendor/github.com/packethost/packngo/notifications.go new file mode 100644 index 000000000..051ca56f9 --- /dev/null +++ b/vendor/github.com/packethost/packngo/notifications.go @@ -0,0 +1,95 @@ +package packngo + +import "fmt" + +const notificationBasePath = "/notifications" + +// Notification struct +type Notification struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Body string `json:"body,omitempty"` + Severity string `json:"severity,omitempty"` + Read bool `json:"read,omitempty"` + Context string `json:"context,omitempty"` + CreatedAt Timestamp `json:"created_at,omitempty"` + UpdatedAt Timestamp `json:"updated_at,omitempty"` + User Href `json:"user,omitempty"` + Href string `json:"href,omitempty"` +} + +type notificationsRoot struct { + Notifications []Notification `json:"notifications,omitempty"` + Meta meta `json:"meta,omitempty"` +} + +// NotificationService interface defines available event functions +type NotificationService interface { + List(*ListOptions) ([]Notification, *Response, error) + Get(string, *GetOptions) (*Notification, *Response, error) + MarkAsRead(string) (*Notification, *Response, error) +} + +// NotificationServiceOp implements NotificationService +type NotificationServiceOp struct { + client *Client +} + +// List returns all notifications +func (s *NotificationServiceOp) List(listOpt *ListOptions) ([]Notification, *Response, error) { + return listNotifications(s.client, notificationBasePath, listOpt) +} + +// Get returns a notification by ID +func (s *NotificationServiceOp) Get(notificationID string, getOpt *GetOptions) (*Notification, *Response, error) { + params := createGetOptionsURL(getOpt) + + path := fmt.Sprintf("%s/%s?%s", notificationBasePath, notificationID, params) + return getNotifications(s.client, path) +} + +// Marks notification as read by ID +func (s *NotificationServiceOp) MarkAsRead(notificationID string) (*Notification, *Response, error) { + path := fmt.Sprintf("%s/%s", notificationBasePath, notificationID) + return markAsRead(s.client, path) +} + +// list helper function for all notification functions +func listNotifications(client *Client, path string, listOpt *ListOptions) ([]Notification, *Response, error) { + params := createListOptionsURL(listOpt) + + root := new(notificationsRoot) + + path = fmt.Sprintf("%s?%s", path, params) + + resp, err := client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + return root.Notifications, resp, err +} + +func getNotifications(client *Client, path string) (*Notification, *Response, error) { + + notification := new(Notification) + + resp, err := client.DoRequest("GET", path, nil, notification) + if err != nil { + return nil, resp, err + } + + return notification, resp, err +} + +func markAsRead(client *Client, path string) (*Notification, *Response, error) { + + notification := new(Notification) + + resp, err := client.DoRequest("PUT", path, nil, notification) + if err != nil { + return nil, resp, err + } + + return notification, resp, err +} diff --git a/vendor/github.com/packethost/packngo/operatingsystems.go b/vendor/github.com/packethost/packngo/operatingsystems.go new file mode 100644 index 000000000..12aa1bb5b --- /dev/null +++ b/vendor/github.com/packethost/packngo/operatingsystems.go @@ -0,0 +1,42 @@ +package packngo + +const osBasePath = "/operating-systems" + +// OSService interface defines available operating_systems methods +type OSService interface { + List() ([]OS, *Response, error) +} + +type osRoot struct { + OperatingSystems []OS `json:"operating_systems"` +} + +// OS represents a Packet operating system +type OS struct { + Name string `json:"name"` + Slug string `json:"slug"` + Distro string `json:"distro"` + Version string `json:"version"` + ProvisionableOn []string `json:"provisionable_on"` +} + +func (o OS) String() string { + return Stringify(o) +} + +// OSServiceOp implements OSService +type OSServiceOp struct { + client *Client +} + +// List returns all available operating systems +func (s *OSServiceOp) List() ([]OS, *Response, error) { + root := new(osRoot) + + resp, err := s.client.DoRequest("GET", osBasePath, nil, root) + if err != nil { + return nil, resp, err + } + + return root.OperatingSystems, resp, err +} diff --git a/vendor/github.com/packethost/packngo/organizations.go b/vendor/github.com/packethost/packngo/organizations.go new file mode 100644 index 000000000..03b59c601 --- /dev/null +++ b/vendor/github.com/packethost/packngo/organizations.go @@ -0,0 +1,171 @@ +package packngo + +import "fmt" + +// API documentation https://www.packet.net/developers/api/organizations/ +const organizationBasePath = "/organizations" + +// OrganizationService interface defines available organization methods +type OrganizationService interface { + List(*ListOptions) ([]Organization, *Response, error) + Get(string, *GetOptions) (*Organization, *Response, error) + Create(*OrganizationCreateRequest) (*Organization, *Response, error) + Update(string, *OrganizationUpdateRequest) (*Organization, *Response, error) + Delete(string) (*Response, error) + ListPaymentMethods(string) ([]PaymentMethod, *Response, error) + ListEvents(string, *ListOptions) ([]Event, *Response, error) +} + +type organizationsRoot struct { + Organizations []Organization `json:"organizations"` + Meta meta `json:"meta"` +} + +// Organization represents a Packet organization +type Organization struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Website string `json:"website,omitempty"` + Twitter string `json:"twitter,omitempty"` + Created string `json:"created_at,omitempty"` + Updated string `json:"updated_at,omitempty"` + Address Address `json:"address,omitempty"` + TaxID string `json:"tax_id,omitempty"` + MainPhone string `json:"main_phone,omitempty"` + BillingPhone string `json:"billing_phone,omitempty"` + CreditAmount float64 `json:"credit_amount,omitempty"` + Logo string `json:"logo,omitempty"` + LogoThumb string `json:"logo_thumb,omitempty"` + Projects []Project `json:"projects,omitempty"` + URL string `json:"href,omitempty"` + Users []User `json:"members,omitempty"` + Owners []User `json:"owners,omitempty"` +} + +func (o Organization) String() string { + return Stringify(o) +} + +// OrganizationCreateRequest type used to create a Packet organization +type OrganizationCreateRequest struct { + Name string `json:"name"` + Description string `json:"description"` + Website string `json:"website"` + Twitter string `json:"twitter"` + Logo string `json:"logo"` +} + +func (o OrganizationCreateRequest) String() string { + return Stringify(o) +} + +// OrganizationUpdateRequest type used to update a Packet organization +type OrganizationUpdateRequest struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Website *string `json:"website,omitempty"` + Twitter *string `json:"twitter,omitempty"` + Logo *string `json:"logo,omitempty"` +} + +func (o OrganizationUpdateRequest) String() string { + return Stringify(o) +} + +// OrganizationServiceOp implements OrganizationService +type OrganizationServiceOp struct { + client *Client +} + +// List returns the user's organizations +func (s *OrganizationServiceOp) List(listOpt *ListOptions) (orgs []Organization, resp *Response, err error) { + params := createListOptionsURL(listOpt) + root := new(organizationsRoot) + + path := fmt.Sprintf("%s?%s", organizationBasePath, params) + + for { + resp, err = s.client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + orgs = append(orgs, root.Organizations...) + + if root.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = root.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + return + } +} + +// Get returns a organization by id +func (s *OrganizationServiceOp) Get(organizationID string, getOpt *GetOptions) (*Organization, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", organizationBasePath, organizationID, params) + organization := new(Organization) + + resp, err := s.client.DoRequest("GET", path, nil, organization) + if err != nil { + return nil, resp, err + } + + return organization, resp, err +} + +// Create creates a new organization +func (s *OrganizationServiceOp) Create(createRequest *OrganizationCreateRequest) (*Organization, *Response, error) { + organization := new(Organization) + + resp, err := s.client.DoRequest("POST", organizationBasePath, createRequest, organization) + if err != nil { + return nil, resp, err + } + + return organization, resp, err +} + +// Update updates an organization +func (s *OrganizationServiceOp) Update(id string, updateRequest *OrganizationUpdateRequest) (*Organization, *Response, error) { + path := fmt.Sprintf("%s/%s", organizationBasePath, id) + organization := new(Organization) + + resp, err := s.client.DoRequest("PATCH", path, updateRequest, organization) + if err != nil { + return nil, resp, err + } + + return organization, resp, err +} + +// Delete deletes an organizationID +func (s *OrganizationServiceOp) Delete(organizationID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", organizationBasePath, organizationID) + + return s.client.DoRequest("DELETE", path, nil, nil) +} + +// ListPaymentMethods returns PaymentMethods for an organization +func (s *OrganizationServiceOp) ListPaymentMethods(organizationID string) ([]PaymentMethod, *Response, error) { + url := fmt.Sprintf("%s/%s%s", organizationBasePath, organizationID, paymentMethodBasePath) + root := new(paymentMethodsRoot) + + resp, err := s.client.DoRequest("GET", url, nil, root) + if err != nil { + return nil, resp, err + } + + return root.PaymentMethods, resp, err +} + +// ListEvents returns list of organization events +func (s *OrganizationServiceOp) ListEvents(organizationID string, listOpt *ListOptions) ([]Event, *Response, error) { + path := fmt.Sprintf("%s/%s%s", organizationBasePath, organizationID, eventBasePath) + + return listEvents(s.client, path, listOpt) +} diff --git a/vendor/github.com/packethost/packngo/packngo.go b/vendor/github.com/packethost/packngo/packngo.go new file mode 100644 index 000000000..01f77805c --- /dev/null +++ b/vendor/github.com/packethost/packngo/packngo.go @@ -0,0 +1,386 @@ +package packngo + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "net/http/httputil" + "net/url" + "os" + "strconv" + "strings" + "time" +) + +const ( + packetTokenEnvVar = "PACKET_AUTH_TOKEN" + libraryVersion = "0.1.0" + baseURL = "https://api.packet.net/" + userAgent = "packngo/" + libraryVersion + mediaType = "application/json" + debugEnvVar = "PACKNGO_DEBUG" + + headerRateLimit = "X-RateLimit-Limit" + headerRateRemaining = "X-RateLimit-Remaining" + headerRateReset = "X-RateLimit-Reset" +) + +type GetOptions struct { + Includes []string + Excludes []string +} + +// ListOptions specifies optional global API parameters +type ListOptions struct { + // for paginated result sets, page of results to retrieve + Page int `url:"page,omitempty"` + // for paginated result sets, the number of results to return per page + PerPage int `url:"per_page,omitempty"` + Includes []string + Excludes []string +} + +func makeSureGetOptionsInclude(g *GetOptions, s string) *GetOptions { + if g == nil { + return &GetOptions{Includes: []string{s}} + } + if !contains(g.Includes, s) { + g.Includes = append(g.Includes, s) + } + return g +} + +func makeSureListOptionsInclude(l *ListOptions, s string) *ListOptions { + if l == nil { + return &ListOptions{Includes: []string{s}} + } + if !contains(l.Includes, s) { + l.Includes = append(l.Includes, s) + } + return l +} + +func createGetOptionsURL(g *GetOptions) (url string) { + if g == nil { + return "" + } + if len(g.Includes) != 0 { + url += fmt.Sprintf("include=%s", strings.Join(g.Includes, ",")) + } + if len(g.Excludes) != 0 { + url += fmt.Sprintf("exclude=%s", strings.Join(g.Excludes, ",")) + } + return + +} + +func createListOptionsURL(l *ListOptions) (url string) { + if l == nil { + return "" + } + if len(l.Includes) != 0 { + url += fmt.Sprintf("include=%s", strings.Join(l.Includes, ",")) + } + if len(l.Excludes) != 0 { + url += fmt.Sprintf("exclude=%s", strings.Join(l.Excludes, ",")) + } + if l.Page != 0 { + if url != "" { + url += "&" + } + url += fmt.Sprintf("page=%d", l.Page) + } + + if l.PerPage != 0 { + if url != "" { + url += "&" + } + url += fmt.Sprintf("per_page=%d", l.PerPage) + } + + return +} + +// meta contains pagination information +type meta struct { + Self *Href `json:"self"` + First *Href `json:"first"` + Last *Href `json:"last"` + Previous *Href `json:"previous,omitempty"` + Next *Href `json:"next,omitempty"` + Total int `json:"total"` + CurrentPageNum int `json:"current_page"` + LastPageNum int `json:"last_page"` +} + +// Response is the http response from api calls +type Response struct { + *http.Response + Rate +} + +// Href is an API link +type Href struct { + Href string `json:"href"` +} + +func (r *Response) populateRate() { + // parse the rate limit headers and populate Response.Rate + if limit := r.Header.Get(headerRateLimit); limit != "" { + r.Rate.RequestLimit, _ = strconv.Atoi(limit) + } + if remaining := r.Header.Get(headerRateRemaining); remaining != "" { + r.Rate.RequestsRemaining, _ = strconv.Atoi(remaining) + } + if reset := r.Header.Get(headerRateReset); reset != "" { + if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 { + r.Rate.Reset = Timestamp{time.Unix(v, 0)} + } + } +} + +// ErrorResponse is the http response used on errors +type ErrorResponse struct { + Response *http.Response + Errors []string `json:"errors"` + SingleError string `json:"error"` +} + +func (r *ErrorResponse) Error() string { + return fmt.Sprintf("%v %v: %d %v %v", + r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, strings.Join(r.Errors, ", "), r.SingleError) +} + +// Client is the base API Client +type Client struct { + client *http.Client + debug bool + + BaseURL *url.URL + + UserAgent string + ConsumerToken string + APIKey string + + RateLimit Rate + + // Packet Api Objects + Plans PlanService + Users UserService + Emails EmailService + SSHKeys SSHKeyService + Devices DeviceService + Projects ProjectService + Facilities FacilityService + OperatingSystems OSService + DeviceIPs DeviceIPService + DevicePorts DevicePortService + ProjectIPs ProjectIPService + ProjectVirtualNetworks ProjectVirtualNetworkService + Volumes VolumeService + VolumeAttachments VolumeAttachmentService + SpotMarket SpotMarketService + SpotMarketRequests SpotMarketRequestService + Organizations OrganizationService + BGPSessions BGPSessionService + BGPConfig BGPConfigService + CapacityService CapacityService + Batches BatchService + TwoFactorAuth TwoFactorAuthService + VPN VPNService + HardwareReservations HardwareReservationService + Events EventService + Notifications NotificationService +} + +// NewRequest inits a new http request with the proper headers +func (c *Client) NewRequest(method, path string, body interface{}) (*http.Request, error) { + // relative path to append to the endpoint url, no leading slash please + rel, err := url.Parse(path) + if err != nil { + return nil, err + } + + u := c.BaseURL.ResolveReference(rel) + + // json encode the request body, if any + buf := new(bytes.Buffer) + if body != nil { + err := json.NewEncoder(buf).Encode(body) + if err != nil { + return nil, err + } + } + + req, err := http.NewRequest(method, u.String(), buf) + if err != nil { + return nil, err + } + + req.Close = true + + req.Header.Add("X-Auth-Token", c.APIKey) + req.Header.Add("X-Consumer-Token", c.ConsumerToken) + + req.Header.Add("Content-Type", mediaType) + req.Header.Add("Accept", mediaType) + req.Header.Add("User-Agent", userAgent) + return req, nil +} + +// Do executes the http request +func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { + resp, err := c.client.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + response := Response{Response: resp} + response.populateRate() + if c.debug { + o, _ := httputil.DumpResponse(response.Response, true) + log.Printf("\n=======[RESPONSE]============\n%s\n\n", string(o)) + } + c.RateLimit = response.Rate + + err = checkResponse(resp) + // if the response is an error, return the ErrorResponse + if err != nil { + return &response, err + } + + if v != nil { + // if v implements the io.Writer interface, return the raw response + if w, ok := v.(io.Writer); ok { + io.Copy(w, resp.Body) + } else { + err = json.NewDecoder(resp.Body).Decode(v) + if err != nil { + return &response, err + } + } + } + + return &response, err +} + +// DoRequest is a convenience method, it calls NewRequest followed by Do +// v is the interface to unmarshal the response JSON into +func (c *Client) DoRequest(method, path string, body, v interface{}) (*Response, error) { + req, err := c.NewRequest(method, path, body) + if c.debug { + o, _ := httputil.DumpRequestOut(req, true) + log.Printf("\n=======[REQUEST]=============\n%s\n", string(o)) + } + if err != nil { + return nil, err + } + return c.Do(req, v) +} + +// DoRequestWithHeader same as DoRequest +func (c *Client) DoRequestWithHeader(method string, headers map[string]string, path string, body, v interface{}) (*Response, error) { + req, err := c.NewRequest(method, path, body) + for k, v := range headers { + req.Header.Add(k, v) + } + + if c.debug { + o, _ := httputil.DumpRequestOut(req, true) + log.Printf("\n=======[REQUEST]=============\n%s\n", string(o)) + } + if err != nil { + return nil, err + } + return c.Do(req, v) +} + +// NewClient initializes and returns a Client +func NewClient() (*Client, error) { + apiToken := os.Getenv(packetTokenEnvVar) + if apiToken == "" { + return nil, fmt.Errorf("you must export %s", packetTokenEnvVar) + } + c := NewClientWithAuth("packngo lib", apiToken, nil) + return c, nil + +} + +// NewClientWithAuth initializes and returns a Client, use this to get an API Client to operate on +// N.B.: Packet's API certificate requires Go 1.5+ to successfully parse. If you are using +// an older version of Go, pass in a custom http.Client with a custom TLS configuration +// that sets "InsecureSkipVerify" to "true" +func NewClientWithAuth(consumerToken string, apiKey string, httpClient *http.Client) *Client { + client, _ := NewClientWithBaseURL(consumerToken, apiKey, httpClient, baseURL) + return client +} + +// NewClientWithBaseURL returns a Client pointing to nonstandard API URL, e.g. +// for mocking the remote API +func NewClientWithBaseURL(consumerToken string, apiKey string, httpClient *http.Client, apiBaseURL string) (*Client, error) { + if httpClient == nil { + // Don't fall back on http.DefaultClient as it's not nice to adjust state + // implicitly. If the client wants to use http.DefaultClient, they can + // pass it in explicitly. + httpClient = &http.Client{} + } + + u, err := url.Parse(apiBaseURL) + if err != nil { + return nil, err + } + + c := &Client{client: httpClient, BaseURL: u, UserAgent: userAgent, ConsumerToken: consumerToken, APIKey: apiKey} + c.debug = os.Getenv(debugEnvVar) != "" + c.Plans = &PlanServiceOp{client: c} + c.Organizations = &OrganizationServiceOp{client: c} + c.Users = &UserServiceOp{client: c} + c.Emails = &EmailServiceOp{client: c} + c.SSHKeys = &SSHKeyServiceOp{client: c} + c.Devices = &DeviceServiceOp{client: c} + c.Projects = &ProjectServiceOp{client: c} + c.Facilities = &FacilityServiceOp{client: c} + c.OperatingSystems = &OSServiceOp{client: c} + c.DeviceIPs = &DeviceIPServiceOp{client: c} + c.DevicePorts = &DevicePortServiceOp{client: c} + c.ProjectVirtualNetworks = &ProjectVirtualNetworkServiceOp{client: c} + c.ProjectIPs = &ProjectIPServiceOp{client: c} + c.Volumes = &VolumeServiceOp{client: c} + c.VolumeAttachments = &VolumeAttachmentServiceOp{client: c} + c.SpotMarket = &SpotMarketServiceOp{client: c} + c.BGPSessions = &BGPSessionServiceOp{client: c} + c.BGPConfig = &BGPConfigServiceOp{client: c} + c.CapacityService = &CapacityServiceOp{client: c} + c.Batches = &BatchServiceOp{client: c} + c.TwoFactorAuth = &TwoFactorAuthServiceOp{client: c} + c.VPN = &VPNServiceOp{client: c} + c.HardwareReservations = &HardwareReservationServiceOp{client: c} + c.SpotMarketRequests = &SpotMarketRequestServiceOp{client: c} + c.Events = &EventServiceOp{client: c} + c.Notifications = &NotificationServiceOp{client: c} + + return c, nil +} + +func checkResponse(r *http.Response) error { + // return if http status code is within 200 range + if c := r.StatusCode; c >= 200 && c <= 299 { + // response is good, return + return nil + } + + errorResponse := &ErrorResponse{Response: r} + data, err := ioutil.ReadAll(r.Body) + // if the response has a body, populate the message in errorResponse + if err == nil && len(data) > 0 { + json.Unmarshal(data, errorResponse) + } + + return errorResponse +} diff --git a/vendor/github.com/packethost/packngo/payment_methods.go b/vendor/github.com/packethost/packngo/payment_methods.go new file mode 100644 index 000000000..0dc98fa0c --- /dev/null +++ b/vendor/github.com/packethost/packngo/payment_methods.go @@ -0,0 +1,72 @@ +package packngo + +// API documentation https://www.packet.net/developers/api/paymentmethods/ +const paymentMethodBasePath = "/payment-methods" + +// ProjectService interface defines available project methods +type PaymentMethodService interface { + List() ([]PaymentMethod, *Response, error) + Get(string) (*PaymentMethod, *Response, error) + Create(*PaymentMethodCreateRequest) (*PaymentMethod, *Response, error) + Update(string, *PaymentMethodUpdateRequest) (*PaymentMethod, *Response, error) + Delete(string) (*Response, error) +} + +type paymentMethodsRoot struct { + PaymentMethods []PaymentMethod `json:"payment_methods"` +} + +// PaymentMethod represents a Packet payment method of an organization +type PaymentMethod struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` + Created string `json:"created_at,omitempty"` + Updated string `json:"updated_at,omitempty"` + Nonce string `json:"nonce,omitempty"` + Default bool `json:"default,omitempty"` + Organization Organization `json:"organization,omitempty"` + Projects []Project `json:"projects,omitempty"` + Type string `json:"type,omitempty"` + CardholderName string `json:"cardholder_name,omitempty"` + ExpMonth string `json:"expiration_month,omitempty"` + ExpYear string `json:"expiration_year,omitempty"` + Last4 string `json:"last_4,omitempty"` + BillingAddress BillingAddress `json:"billing_address,omitempty"` + URL string `json:"href,omitempty"` +} + +func (pm PaymentMethod) String() string { + return Stringify(pm) +} + +// PaymentMethodCreateRequest type used to create a Packet payment method of an organization +type PaymentMethodCreateRequest struct { + Name string `json:"name"` + Nonce string `json:"nonce"` + CardholderName string `json:"cardholder_name,omitempty"` + ExpMonth string `json:"expiration_month,omitempty"` + ExpYear string `json:"expiration_year,omitempty"` + BillingAddress string `json:"billing_address,omitempty"` +} + +func (pm PaymentMethodCreateRequest) String() string { + return Stringify(pm) +} + +// PaymentMethodUpdateRequest type used to update a Packet payment method of an organization +type PaymentMethodUpdateRequest struct { + Name *string `json:"name,omitempty"` + CardholderName *string `json:"cardholder_name,omitempty"` + ExpMonth *string `json:"expiration_month,omitempty"` + ExpYear *string `json:"expiration_year,omitempty"` + BillingAddress *string `json:"billing_address,omitempty"` +} + +func (pm PaymentMethodUpdateRequest) String() string { + return Stringify(pm) +} + +// PaymentMethodServiceOp implements PaymentMethodService +type PaymentMethodServiceOp struct { + client *Client +} diff --git a/vendor/github.com/packethost/packngo/plans.go b/vendor/github.com/packethost/packngo/plans.go new file mode 100644 index 000000000..36b0a2ff2 --- /dev/null +++ b/vendor/github.com/packethost/packngo/plans.go @@ -0,0 +1,126 @@ +package packngo + +import ( + "fmt" +) + +const planBasePath = "/plans" + +// PlanService interface defines available plan methods +type PlanService interface { + List(*ListOptions) ([]Plan, *Response, error) +} + +type planRoot struct { + Plans []Plan `json:"plans"` +} + +// Plan represents a Packet service plan +type Plan struct { + ID string `json:"id"` + Slug string `json:"slug,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Line string `json:"line,omitempty"` + Specs *Specs `json:"specs,omitempty"` + Pricing *Pricing `json:"pricing,omitempty"` + DeploymentTypes []string `json:"deployment_types"` + Class string `json:"class"` + AvailableIn []Facility `json:"available_in"` +} + +func (p Plan) String() string { + return Stringify(p) +} + +// Specs - the server specs for a plan +type Specs struct { + Cpus []*Cpus `json:"cpus,omitempty"` + Memory *Memory `json:"memory,omitempty"` + Drives []*Drives `json:"drives,omitempty"` + Nics []*Nics `json:"nics,omitempty"` + Features *Features `json:"features,omitempty"` +} + +func (s Specs) String() string { + return Stringify(s) +} + +// Cpus - the CPU config details for specs on a plan +type Cpus struct { + Count int `json:"count,omitempty"` + Type string `json:"type,omitempty"` +} + +func (c Cpus) String() string { + return Stringify(c) +} + +// Memory - the RAM config details for specs on a plan +type Memory struct { + Total string `json:"total,omitempty"` +} + +func (m Memory) String() string { + return Stringify(m) +} + +// Drives - the storage config details for specs on a plan +type Drives struct { + Count int `json:"count,omitempty"` + Size string `json:"size,omitempty"` + Type string `json:"type,omitempty"` +} + +func (d Drives) String() string { + return Stringify(d) +} + +// Nics - the network hardware details for specs on a plan +type Nics struct { + Count int `json:"count,omitempty"` + Type string `json:"type,omitempty"` +} + +func (n Nics) String() string { + return Stringify(n) +} + +// Features - other features in the specs for a plan +type Features struct { + Raid bool `json:"raid,omitempty"` + Txt bool `json:"txt,omitempty"` +} + +func (f Features) String() string { + return Stringify(f) +} + +// Pricing - the pricing options on a plan +type Pricing struct { + Hour float32 `json:"hour,omitempty"` + Month float32 `json:"month,omitempty"` +} + +func (p Pricing) String() string { + return Stringify(p) +} + +// PlanServiceOp implements PlanService +type PlanServiceOp struct { + client *Client +} + +// List method returns all available plans +func (s *PlanServiceOp) List(listOpt *ListOptions) ([]Plan, *Response, error) { + root := new(planRoot) + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s?%s", planBasePath, params) + + resp, err := s.client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + return root.Plans, resp, err +} diff --git a/vendor/github.com/packethost/packngo/ports.go b/vendor/github.com/packethost/packngo/ports.go new file mode 100644 index 000000000..a75c12fad --- /dev/null +++ b/vendor/github.com/packethost/packngo/ports.go @@ -0,0 +1,225 @@ +package packngo + +import ( + "fmt" +) + +const portBasePath = "/ports" + +type NetworkType int + +const ( + NetworkL3 NetworkType = iota + NetworkHybrid + NetworkL2Bonded + NetworkL2Individual + NetworkUnknown +) + +// DevicePortService handles operations on a port which belongs to a particular device +type DevicePortService interface { + Assign(*PortAssignRequest) (*Port, *Response, error) + Unassign(*PortAssignRequest) (*Port, *Response, error) + Bond(*BondRequest) (*Port, *Response, error) + Disbond(*DisbondRequest) (*Port, *Response, error) + PortToLayerTwo(string) (*Port, *Response, error) + PortToLayerThree(string) (*Port, *Response, error) + DeviceToLayerTwo(string) (*Device, error) + DeviceToLayerThree(string) (*Device, error) + DeviceNetworkType(string) (NetworkType, error) + GetBondPort(string) (*Port, error) + GetPortByName(string, string) (*Port, error) +} + +type PortData struct { + MAC string `json:"mac"` + Bonded bool `json:"bonded"` +} + +type Port struct { + ID string `json:"id"` + Type string `json:"type"` + Name string `json:"name"` + Data PortData `json:"data"` + AttachedVirtualNetworks []VirtualNetwork `json:"virtual_networks"` +} + +type AddressRequest struct { + AddressFamily int `json:"address_family"` + Public bool `json:"public"` +} + +type BackToL3Request struct { + RequestIPs []AddressRequest `json:"request_ips"` +} + +type DevicePortServiceOp struct { + client *Client +} + +type PortAssignRequest struct { + PortID string `json:"id"` + VirtualNetworkID string `json:"vnid"` +} + +type BondRequest struct { + PortID string `json:"id"` + BulkEnable bool `json:"bulk_enable"` +} + +type DisbondRequest struct { + PortID string `json:"id"` + BulkDisable bool `json:"bulk_disable"` +} + +func (i *DevicePortServiceOp) GetBondPort(deviceID string) (*Port, error) { + device, _, err := i.client.Devices.Get(deviceID, nil) + if err != nil { + return nil, err + } + for _, port := range device.NetworkPorts { + if port.Type == "NetworkBondPort" { + return &port, nil + } + } + + return nil, fmt.Errorf("No bonded port found in device %s", deviceID) +} + +func (i *DevicePortServiceOp) GetPortByName(deviceID, name string) (*Port, error) { + device, _, err := i.client.Devices.Get(deviceID, nil) + if err != nil { + return nil, err + } + for _, port := range device.NetworkPorts { + if port.Name == name { + return &port, nil + } + } + + return nil, fmt.Errorf("Port %s not found in device %s", name, deviceID) +} + +func (i *DevicePortServiceOp) Assign(par *PortAssignRequest) (*Port, *Response, error) { + path := fmt.Sprintf("%s/%s/assign", portBasePath, par.PortID) + return i.portAction(path, par) +} + +func (i *DevicePortServiceOp) Unassign(par *PortAssignRequest) (*Port, *Response, error) { + path := fmt.Sprintf("%s/%s/unassign", portBasePath, par.PortID) + return i.portAction(path, par) +} + +func (i *DevicePortServiceOp) Bond(br *BondRequest) (*Port, *Response, error) { + path := fmt.Sprintf("%s/%s/bond", portBasePath, br.PortID) + return i.portAction(path, br) +} + +func (i *DevicePortServiceOp) Disbond(dr *DisbondRequest) (*Port, *Response, error) { + path := fmt.Sprintf("%s/%s/disbond", portBasePath, dr.PortID) + return i.portAction(path, dr) +} + +func (i *DevicePortServiceOp) portAction(path string, req interface{}) (*Port, *Response, error) { + port := new(Port) + + resp, err := i.client.DoRequest("POST", path, req, port) + if err != nil { + return nil, resp, err + } + + return port, resp, err +} + +func (i *DevicePortServiceOp) PortToLayerTwo(portID string) (*Port, *Response, error) { + path := fmt.Sprintf("%s/%s/convert/layer-2", portBasePath, portID) + port := new(Port) + + resp, err := i.client.DoRequest("POST", path, nil, port) + if err != nil { + return nil, resp, err + } + + return port, resp, err +} + +func (i *DevicePortServiceOp) PortToLayerThree(portID string) (*Port, *Response, error) { + path := fmt.Sprintf("%s/%s/convert/layer-3", portBasePath, portID) + port := new(Port) + + req := BackToL3Request{ + RequestIPs: []AddressRequest{ + AddressRequest{AddressFamily: 4, Public: true}, + AddressRequest{AddressFamily: 4, Public: false}, + AddressRequest{AddressFamily: 6, Public: true}, + }, + } + + resp, err := i.client.DoRequest("POST", path, &req, port) + if err != nil { + return nil, resp, err + } + + return port, resp, err +} + +func (i *DevicePortServiceOp) DeviceNetworkType(deviceID string) (NetworkType, error) { + d, _, err := i.client.Devices.Get(deviceID, nil) + if err != nil { + return NetworkUnknown, err + } + if d.Plan.Slug == "baremetal_0" || d.Plan.Slug == "baremetal_1" { + return NetworkL3, nil + } + if d.Plan.Slug == "baremetal_1e" { + return NetworkHybrid, nil + } + if len(d.NetworkPorts) < 1 { + // really? + return NetworkL2Individual, nil + } + if d.NetworkPorts[0].Data.Bonded { + if d.NetworkPorts[2].Data.Bonded { + for _, ip := range d.Network { + if ip.Management { + return NetworkL3, nil + } + } + return NetworkL2Bonded, nil + } else { + return NetworkHybrid, nil + } + } + return NetworkL2Individual, nil +} + +func (i *DevicePortServiceOp) DeviceToLayerThree(deviceID string) (*Device, error) { + // hopefull all the VLANs are unassigned at this point + bond0, err := i.client.DevicePorts.GetBondPort(deviceID) + if err != nil { + return nil, err + } + + bond0, _, err = i.client.DevicePorts.PortToLayerThree(bond0.ID) + if err != nil { + return nil, err + } + d, _, err := i.client.Devices.Get(deviceID, nil) + return d, err +} + +// DeviceToLayerTwo converts device to L2 networking. Use bond0 to attach VLAN. +func (i *DevicePortServiceOp) DeviceToLayerTwo(deviceID string) (*Device, error) { + bond0, err := i.client.DevicePorts.GetBondPort(deviceID) + if err != nil { + return nil, err + } + + bond0, _, err = i.client.DevicePorts.PortToLayerTwo(bond0.ID) + if err != nil { + return nil, err + } + d, _, err := i.client.Devices.Get(deviceID, nil) + return d, err + +} diff --git a/vendor/github.com/packethost/packngo/projects.go b/vendor/github.com/packethost/packngo/projects.go new file mode 100644 index 000000000..144e3fd98 --- /dev/null +++ b/vendor/github.com/packethost/packngo/projects.go @@ -0,0 +1,172 @@ +package packngo + +import ( + "fmt" +) + +const projectBasePath = "/projects" + +// ProjectService interface defines available project methods +type ProjectService interface { + List(listOpt *ListOptions) ([]Project, *Response, error) + Get(string, *GetOptions) (*Project, *Response, error) + Create(*ProjectCreateRequest) (*Project, *Response, error) + Update(string, *ProjectUpdateRequest) (*Project, *Response, error) + Delete(string) (*Response, error) + ListBGPSessions(projectID string, listOpt *ListOptions) ([]BGPSession, *Response, error) + ListEvents(string, *ListOptions) ([]Event, *Response, error) +} + +type projectsRoot struct { + Projects []Project `json:"projects"` + Meta meta `json:"meta"` +} + +// Project represents a Packet project +type Project struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` + Organization Organization `json:"organization,omitempty"` + Created string `json:"created_at,omitempty"` + Updated string `json:"updated_at,omitempty"` + Users []User `json:"members,omitempty"` + Devices []Device `json:"devices,omitempty"` + SSHKeys []SSHKey `json:"ssh_keys,omitempty"` + URL string `json:"href,omitempty"` + PaymentMethod PaymentMethod `json:"payment_method,omitempty"` +} + +func (p Project) String() string { + return Stringify(p) +} + +// ProjectCreateRequest type used to create a Packet project +type ProjectCreateRequest struct { + Name string `json:"name"` + PaymentMethodID string `json:"payment_method_id,omitempty"` + OrganizationID string `json:"organization_id,omitempty"` +} + +func (p ProjectCreateRequest) String() string { + return Stringify(p) +} + +// ProjectUpdateRequest type used to update a Packet project +type ProjectUpdateRequest struct { + Name *string `json:"name,omitempty"` + PaymentMethodID *string `json:"payment_method_id,omitempty"` +} + +func (p ProjectUpdateRequest) String() string { + return Stringify(p) +} + +// ProjectServiceOp implements ProjectService +type ProjectServiceOp struct { + client *Client +} + +// List returns the user's projects +func (s *ProjectServiceOp) List(listOpt *ListOptions) (projects []Project, resp *Response, err error) { + params := createListOptionsURL(listOpt) + root := new(projectsRoot) + + path := fmt.Sprintf("%s?%s", projectBasePath, params) + + for { + resp, err = s.client.DoRequest("GET", path, nil, root) + if err != nil { + return nil, resp, err + } + + projects = append(projects, root.Projects...) + + if root.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = root.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + + return + } +} + +// Get returns a project by id +func (s *ProjectServiceOp) Get(projectID string, getOpt *GetOptions) (*Project, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", projectBasePath, projectID, params) + project := new(Project) + resp, err := s.client.DoRequest("GET", path, nil, project) + if err != nil { + return nil, resp, err + } + return project, resp, err +} + +// Create creates a new project +func (s *ProjectServiceOp) Create(createRequest *ProjectCreateRequest) (*Project, *Response, error) { + project := new(Project) + + resp, err := s.client.DoRequest("POST", projectBasePath, createRequest, project) + if err != nil { + return nil, resp, err + } + + return project, resp, err +} + +// Update updates a project +func (s *ProjectServiceOp) Update(id string, updateRequest *ProjectUpdateRequest) (*Project, *Response, error) { + path := fmt.Sprintf("%s/%s", projectBasePath, id) + project := new(Project) + + resp, err := s.client.DoRequest("PATCH", path, updateRequest, project) + if err != nil { + return nil, resp, err + } + + return project, resp, err +} + +// Delete deletes a project +func (s *ProjectServiceOp) Delete(projectID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", projectBasePath, projectID) + + return s.client.DoRequest("DELETE", path, nil, nil) +} + +// ListBGPSessions returns all BGP Sessions associated with the project +func (s *ProjectServiceOp) ListBGPSessions(projectID string, listOpt *ListOptions) (bgpSessions []BGPSession, resp *Response, err error) { + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, bgpSessionBasePath, params) + + for { + subset := new(bgpSessionsRoot) + + resp, err = s.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + bgpSessions = append(bgpSessions, subset.Sessions...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + + return + } +} + +// ListEvents returns list of project events +func (s *ProjectServiceOp) ListEvents(projectID string, listOpt *ListOptions) ([]Event, *Response, error) { + path := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, eventBasePath) + + return listEvents(s.client, path, listOpt) +} diff --git a/vendor/github.com/packethost/packngo/rate.go b/vendor/github.com/packethost/packngo/rate.go new file mode 100644 index 000000000..965967d45 --- /dev/null +++ b/vendor/github.com/packethost/packngo/rate.go @@ -0,0 +1,12 @@ +package packngo + +// Rate provides the API request rate limit details +type Rate struct { + RequestLimit int `json:"request_limit"` + RequestsRemaining int `json:"requests_remaining"` + Reset Timestamp `json:"rate_reset"` +} + +func (r Rate) String() string { + return Stringify(r) +} diff --git a/vendor/github.com/packethost/packngo/spotmarket.go b/vendor/github.com/packethost/packngo/spotmarket.go new file mode 100644 index 000000000..5dfb7d559 --- /dev/null +++ b/vendor/github.com/packethost/packngo/spotmarket.go @@ -0,0 +1,39 @@ +package packngo + +const spotMarketBasePath = "/market/spot/prices" + +// SpotMarketService expooses Spot Market methods +type SpotMarketService interface { + Prices() (PriceMap, *Response, error) +} + +// SpotMarketServiceOp implements SpotMarketService +type SpotMarketServiceOp struct { + client *Client +} + +// PriceMap is a map of [facility][plan]-> float Price +type PriceMap map[string]map[string]float64 + +// Prices gets current PriceMap from the API +func (s *SpotMarketServiceOp) Prices() (PriceMap, *Response, error) { + root := new(struct { + SMPs map[string]map[string]struct { + Price float64 `json:"price"` + } `json:"spot_market_prices"` + }) + + resp, err := s.client.DoRequest("GET", spotMarketBasePath, nil, root) + if err != nil { + return nil, resp, err + } + + prices := make(PriceMap) + for facility, planMap := range root.SMPs { + prices[facility] = map[string]float64{} + for plan, v := range planMap { + prices[facility][plan] = v.Price + } + } + return prices, resp, err +} diff --git a/vendor/github.com/packethost/packngo/spotmarketrequest.go b/vendor/github.com/packethost/packngo/spotmarketrequest.go new file mode 100644 index 000000000..31755a8d4 --- /dev/null +++ b/vendor/github.com/packethost/packngo/spotmarketrequest.go @@ -0,0 +1,109 @@ +package packngo + +import ( + "fmt" + "math" +) + +const spotMarketRequestBasePath = "/spot-market-requests" + +type SpotMarketRequestService interface { + List(string) ([]SpotMarketRequest, *Response, error) + Create(*SpotMarketRequestCreateRequest, string) (*SpotMarketRequest, *Response, error) + Delete(string, bool) (*Response, error) + Get(string, *GetOptions) (*SpotMarketRequest, *Response, error) +} + +type SpotMarketRequestCreateRequest struct { + DevicesMax int `json:"devices_max"` + DevicesMin int `json:"devices_min"` + EndAt *Timestamp `json:"end_at,omitempty"` + FacilityIDs []string `json:"facility_ids"` + MaxBidPrice float64 `json:"max_bid_price"` + + Parameters SpotMarketRequestInstanceParameters `json:"instance_parameters"` +} + +type SpotMarketRequest struct { + SpotMarketRequestCreateRequest + ID string `json:"id"` + Devices []Device `json:"devices"` + Facilities []Facility `json:"facilities"` + Project Project `json:"project"` + Href string `json:"href"` +} + +type SpotMarketRequestInstanceParameters struct { + AlwaysPXE bool `json:"always_pxe,omitempty"` + BillingCycle string `json:"billing_cycle"` + CustomData string `json:"customdata,omitempty"` + Description string `json:"description,omitempty"` + Features []string `json:"features,omitempty"` + Hostname string `json:"hostname,omitempty"` + Hostnames []string `json:"hostnames,omitempty"` + Locked bool `json:"locked,omitempty"` + OperatingSystem string `json:"operating_system"` + Plan string `json:"plan"` + ProjectSSHKeys []string `json:"project_ssh_keys,omitempty"` + Tags []string `json:"tags"` + TerminationTime *Timestamp `json:"termination_time,omitempty"` + UserSSHKeys []string `json:"user_ssh_keys,omitempty"` + UserData string `json:"userdata"` +} + +type SpotMarketRequestServiceOp struct { + client *Client +} + +func roundPlus(f float64, places int) float64 { + shift := math.Pow(10, float64(places)) + return math.Floor(f*shift+.5) / shift +} + +func (s *SpotMarketRequestServiceOp) Create(cr *SpotMarketRequestCreateRequest, pID string) (*SpotMarketRequest, *Response, error) { + path := fmt.Sprintf("%s/%s%s?include=devices,project", projectBasePath, pID, spotMarketRequestBasePath) + cr.MaxBidPrice = roundPlus(cr.MaxBidPrice, 2) + smr := new(SpotMarketRequest) + + resp, err := s.client.DoRequest("POST", path, cr, smr) + if err != nil { + return nil, resp, err + } + + return smr, resp, err +} + +func (s *SpotMarketRequestServiceOp) List(pID string) ([]SpotMarketRequest, *Response, error) { + smrRoot := struct { + SMRs []SpotMarketRequest `json:"spot_market_requests"` + }{} + + path := fmt.Sprintf("%s/%s%s?include=devices,project", projectBasePath, pID, spotMarketRequestBasePath) + resp, err := s.client.DoRequest("GET", path, nil, &smrRoot) + if err != nil { + return nil, resp, err + } + return smrRoot.SMRs, resp, nil +} + +func (s *SpotMarketRequestServiceOp) Get(id string, getOpt *GetOptions) (*SpotMarketRequest, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", spotMarketRequestBasePath, id, params) + smr := new(SpotMarketRequest) + + resp, err := s.client.DoRequest("GET", path, nil, &smr) + if err != nil { + return nil, resp, err + } + + return smr, resp, err +} + +func (s *SpotMarketRequestServiceOp) Delete(id string, forceDelete bool) (*Response, error) { + path := fmt.Sprintf("%s/%s", spotMarketRequestBasePath, id) + var params *map[string]bool + if forceDelete { + params = &map[string]bool{"force_termination": true} + } + return s.client.DoRequest("DELETE", path, params, nil) +} diff --git a/vendor/github.com/packethost/packngo/sshkeys.go b/vendor/github.com/packethost/packngo/sshkeys.go new file mode 100644 index 000000000..4b198f571 --- /dev/null +++ b/vendor/github.com/packethost/packngo/sshkeys.go @@ -0,0 +1,139 @@ +package packngo + +import "fmt" + +const ( + sshKeyBasePath = "/ssh-keys" +) + +// SSHKeyService interface defines available device methods +type SSHKeyService interface { + List() ([]SSHKey, *Response, error) + ProjectList(string) ([]SSHKey, *Response, error) + Get(string, *GetOptions) (*SSHKey, *Response, error) + Create(*SSHKeyCreateRequest) (*SSHKey, *Response, error) + Update(string, *SSHKeyUpdateRequest) (*SSHKey, *Response, error) + Delete(string) (*Response, error) +} + +type sshKeyRoot struct { + SSHKeys []SSHKey `json:"ssh_keys"` +} + +// SSHKey represents a user's ssh key +type SSHKey struct { + ID string `json:"id"` + Label string `json:"label"` + Key string `json:"key"` + FingerPrint string `json:"fingerprint"` + Created string `json:"created_at"` + Updated string `json:"updated_at"` + User User `json:"user,omitempty"` + URL string `json:"href,omitempty"` +} + +func (s SSHKey) String() string { + return Stringify(s) +} + +// SSHKeyCreateRequest type used to create an ssh key +type SSHKeyCreateRequest struct { + Label string `json:"label"` + Key string `json:"key"` + ProjectID string `json:"-"` +} + +func (s SSHKeyCreateRequest) String() string { + return Stringify(s) +} + +// SSHKeyUpdateRequest type used to update an ssh key +type SSHKeyUpdateRequest struct { + Label *string `json:"label,omitempty"` + Key *string `json:"key,omitempty"` +} + +func (s SSHKeyUpdateRequest) String() string { + return Stringify(s) +} + +// SSHKeyServiceOp implements SSHKeyService +type SSHKeyServiceOp struct { + client *Client +} + +func (s *SSHKeyServiceOp) list(url string) ([]SSHKey, *Response, error) { + root := new(sshKeyRoot) + + resp, err := s.client.DoRequest("GET", url, nil, root) + if err != nil { + return nil, resp, err + } + + return root.SSHKeys, resp, err +} + +// ProjectList lists ssh keys of a project +func (s *SSHKeyServiceOp) ProjectList(projectID string) ([]SSHKey, *Response, error) { + return s.list(fmt.Sprintf("%s/%s%s", projectBasePath, projectID, sshKeyBasePath)) + +} + +// List returns a user's ssh keys +func (s *SSHKeyServiceOp) List() ([]SSHKey, *Response, error) { + return s.list(sshKeyBasePath) +} + +// Get returns an ssh key by id +func (s *SSHKeyServiceOp) Get(sshKeyID string, getOpt *GetOptions) (*SSHKey, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", sshKeyBasePath, sshKeyID, params) + sshKey := new(SSHKey) + + resp, err := s.client.DoRequest("GET", path, nil, sshKey) + if err != nil { + return nil, resp, err + } + + return sshKey, resp, err +} + +// Create creates a new ssh key +func (s *SSHKeyServiceOp) Create(createRequest *SSHKeyCreateRequest) (*SSHKey, *Response, error) { + path := sshKeyBasePath + if createRequest.ProjectID != "" { + path = fmt.Sprintf("%s/%s%s", projectBasePath, createRequest.ProjectID, sshKeyBasePath) + } + sshKey := new(SSHKey) + + resp, err := s.client.DoRequest("POST", path, createRequest, sshKey) + if err != nil { + return nil, resp, err + } + + return sshKey, resp, err +} + +// Update updates an ssh key +func (s *SSHKeyServiceOp) Update(id string, updateRequest *SSHKeyUpdateRequest) (*SSHKey, *Response, error) { + if updateRequest.Label == nil && updateRequest.Key == nil { + return nil, nil, fmt.Errorf("You must set either Label or Key string for SSH Key update") + } + path := fmt.Sprintf("%s/%s", sshKeyBasePath, id) + + sshKey := new(SSHKey) + + resp, err := s.client.DoRequest("PATCH", path, updateRequest, sshKey) + if err != nil { + return nil, resp, err + } + + return sshKey, resp, err +} + +// Delete deletes an ssh key +func (s *SSHKeyServiceOp) Delete(sshKeyID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", sshKeyBasePath, sshKeyID) + + return s.client.DoRequest("DELETE", path, nil, nil) +} diff --git a/vendor/github.com/packethost/packngo/timestamp.go b/vendor/github.com/packethost/packngo/timestamp.go new file mode 100644 index 000000000..c3320ed62 --- /dev/null +++ b/vendor/github.com/packethost/packngo/timestamp.go @@ -0,0 +1,35 @@ +package packngo + +import ( + "strconv" + "time" +) + +// Timestamp represents a time that can be unmarshalled from a JSON string +// formatted as either an RFC3339 or Unix timestamp. All +// exported methods of time.Time can be called on Timestamp. +type Timestamp struct { + time.Time +} + +func (t Timestamp) String() string { + return t.Time.String() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +// Time is expected in RFC3339 or Unix format. +func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { + str := string(data) + i, err := strconv.ParseInt(str, 10, 64) + if err == nil { + t.Time = time.Unix(i, 0) + } else { + t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str) + } + return +} + +// Equal reports whether t and u are equal based on time.Equal +func (t Timestamp) Equal(u Timestamp) bool { + return t.Time.Equal(u.Time) +} diff --git a/vendor/github.com/packethost/packngo/two_factor_auth.go b/vendor/github.com/packethost/packngo/two_factor_auth.go new file mode 100644 index 000000000..5064b09fe --- /dev/null +++ b/vendor/github.com/packethost/packngo/two_factor_auth.go @@ -0,0 +1,56 @@ +package packngo + +const twoFactorAuthAppPath = "/user/otp/app" +const twoFactorAuthSmsPath = "/user/otp/sms" + +// TwoFactorAuthService interface defines available two factor authentication functions +type TwoFactorAuthService interface { + EnableApp(string) (*Response, error) + DisableApp(string) (*Response, error) + EnableSms(string) (*Response, error) + DisableSms(string) (*Response, error) + ReceiveSms() (*Response, error) + SeedApp() (string, *Response, error) +} + +// TwoFactorAuthServiceOp implements TwoFactorAuthService +type TwoFactorAuthServiceOp struct { + client *Client +} + +// EnableApp function enables two factor auth using authenticatior app +func (s *TwoFactorAuthServiceOp) EnableApp(token string) (resp *Response, err error) { + headers := map[string]string{"x-otp-token": token} + return s.client.DoRequestWithHeader("POST", headers, twoFactorAuthAppPath, nil, nil) +} + +// EnableSms function enables two factor auth using sms +func (s *TwoFactorAuthServiceOp) EnableSms(token string) (resp *Response, err error) { + headers := map[string]string{"x-otp-token": token} + return s.client.DoRequestWithHeader("POST", headers, twoFactorAuthSmsPath, nil, nil) +} + +// ReceiveSms orders the auth service to issue an SMS token +func (s *TwoFactorAuthServiceOp) ReceiveSms() (resp *Response, err error) { + return s.client.DoRequest("POST", twoFactorAuthSmsPath+"/receive", nil, nil) +} + +// DisableApp function disables two factor auth using +func (s *TwoFactorAuthServiceOp) DisableApp(token string) (resp *Response, err error) { + headers := map[string]string{"x-otp-token": token} + return s.client.DoRequestWithHeader("DELETE", headers, twoFactorAuthAppPath, nil, nil) +} + +// DisableSms function disables two factor auth using +func (s *TwoFactorAuthServiceOp) DisableSms(token string) (resp *Response, err error) { + headers := map[string]string{"x-otp-token": token} + return s.client.DoRequestWithHeader("DELETE", headers, twoFactorAuthSmsPath, nil, nil) +} + +// SeedApp orders the auth service to issue a token via google authenticator +func (s *TwoFactorAuthServiceOp) SeedApp() (otpURI string, resp *Response, err error) { + ret := &map[string]string{} + resp, err = s.client.DoRequest("POST", twoFactorAuthAppPath+"/receive", nil, ret) + + return (*ret)["otp_uri"], resp, err +} diff --git a/vendor/github.com/packethost/packngo/user.go b/vendor/github.com/packethost/packngo/user.go new file mode 100644 index 000000000..ef4b25bb6 --- /dev/null +++ b/vendor/github.com/packethost/packngo/user.go @@ -0,0 +1,100 @@ +package packngo + +import "fmt" + +const usersBasePath = "/users" +const userBasePath = "/user" + +// UserService interface defines available user methods +type UserService interface { + List(*ListOptions) ([]User, *Response, error) + Get(string, *GetOptions) (*User, *Response, error) + Current() (*User, *Response, error) +} + +type usersRoot struct { + Users []User `json:"users"` + Meta meta `json:"meta"` +} + +// User represents a Packet user +type User struct { + ID string `json:"id"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + FullName string `json:"full_name,omitempty"` + Email string `json:"email,omitempty"` + TwoFactor string `json:"two_factor_auth,omitempty"` + DefaultOrganizationID string `json:"default_organization_id,omitempty"` + AvatarURL string `json:"avatar_url,omitempty"` + Facebook string `json:"twitter,omitempty"` + Twitter string `json:"facebook,omitempty"` + LinkedIn string `json:"linkedin,omitempty"` + Created string `json:"created_at,omitempty"` + Updated string `json:"updated_at,omitempty"` + TimeZone string `json:"timezone,omitempty"` + Emails []Email `json:"emails,omitempty"` + PhoneNumber string `json:"phone_number,omitempty"` + URL string `json:"href,omitempty"` + VPN bool `json:"vpn"` +} + +func (u User) String() string { + return Stringify(u) +} + +// UserServiceOp implements UserService +type UserServiceOp struct { + client *Client +} + +// Get method gets a user by userID +func (s *UserServiceOp) List(listOpt *ListOptions) (users []User, resp *Response, err error) { + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s?%s", usersBasePath, params) + + for { + subset := new(usersRoot) + + resp, err = s.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + users = append(users, subset.Users...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + return + } +} + +// Returns the user object for the currently logged-in user. +func (s *UserServiceOp) Current() (*User, *Response, error) { + user := new(User) + + resp, err := s.client.DoRequest("GET", userBasePath, nil, user) + if err != nil { + return nil, resp, err + } + + return user, resp, err +} + +func (s *UserServiceOp) Get(userID string, getOpt *GetOptions) (*User, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", usersBasePath, userID, params) + user := new(User) + + resp, err := s.client.DoRequest("GET", path, nil, user) + if err != nil { + return nil, resp, err + } + + return user, resp, err +} diff --git a/vendor/github.com/packethost/packngo/utils.go b/vendor/github.com/packethost/packngo/utils.go new file mode 100644 index 000000000..eb997c809 --- /dev/null +++ b/vendor/github.com/packethost/packngo/utils.go @@ -0,0 +1,115 @@ +package packngo + +import ( + "bytes" + "fmt" + "io" + "reflect" +) + +var ( + timestampType = reflect.TypeOf(Timestamp{}) + Facilities = []string{ + "yyz1", "nrt1", "atl1", "mrs1", "hkg1", "ams1", + "ewr1", "sin1", "dfw1", "lax1", "syd1", "sjc1", + "ord1", "iad1", "fra1", "sea1"} + FacilityFeatures = []string{ + "baremetal", "layer_2", "backend_transfer", "storage", "global_ipv4"} + UtilizationLevels = []string{"unavailable", "critical", "limited", "normal"} + DevicePlans = []string{"c2.medium.x86", "g2.large.x86", + "m2.xlarge.x86", "x2.xlarge.x86", "baremetal_2a", "baremetal_2a2", + "baremetal_1", "baremetal_3", "baremetal_2", "baremetal_s", + "baremetal_0", "baremetal_1e", + } +) + +// Stringify creates a string representation of the provided message +func Stringify(message interface{}) string { + var buf bytes.Buffer + v := reflect.ValueOf(message) + stringifyValue(&buf, v) + return buf.String() +} + +// StreamToString converts a reader to a string +func StreamToString(stream io.Reader) string { + buf := new(bytes.Buffer) + buf.ReadFrom(stream) + return buf.String() +} + +// contains tells whether a contains x. +func contains(a []string, x string) bool { + for _, n := range a { + if x == n { + return true + } + } + return false +} + +// stringifyValue was graciously cargoculted from the goprotubuf library +func stringifyValue(w io.Writer, val reflect.Value) { + if val.Kind() == reflect.Ptr && val.IsNil() { + w.Write([]byte("")) + return + } + + v := reflect.Indirect(val) + + switch v.Kind() { + case reflect.String: + fmt.Fprintf(w, `"%s"`, v) + case reflect.Slice: + w.Write([]byte{'['}) + for i := 0; i < v.Len(); i++ { + if i > 0 { + w.Write([]byte{' '}) + } + + stringifyValue(w, v.Index(i)) + } + + w.Write([]byte{']'}) + return + case reflect.Struct: + if v.Type().Name() != "" { + w.Write([]byte(v.Type().String())) + } + + // special handling of Timestamp values + if v.Type() == timestampType { + fmt.Fprintf(w, "{%s}", v.Interface()) + return + } + + w.Write([]byte{'{'}) + + var sep bool + for i := 0; i < v.NumField(); i++ { + fv := v.Field(i) + if fv.Kind() == reflect.Ptr && fv.IsNil() { + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + continue + } + + if sep { + w.Write([]byte(", ")) + } else { + sep = true + } + + w.Write([]byte(v.Type().Field(i).Name)) + w.Write([]byte{':'}) + stringifyValue(w, fv) + } + + w.Write([]byte{'}'}) + default: + if v.CanInterface() { + fmt.Fprint(w, v.Interface()) + } + } +} diff --git a/vendor/github.com/packethost/packngo/virtualnetworks.go b/vendor/github.com/packethost/packngo/virtualnetworks.go new file mode 100644 index 000000000..5f0f9d0f0 --- /dev/null +++ b/vendor/github.com/packethost/packngo/virtualnetworks.go @@ -0,0 +1,92 @@ +package packngo + +import ( + "fmt" +) + +const virtualNetworkBasePath = "/virtual-networks" + +// DevicePortService handles operations on a port which belongs to a particular device +type ProjectVirtualNetworkService interface { + List(projectID string, listOpt *ListOptions) (*VirtualNetworkListResponse, *Response, error) + Create(*VirtualNetworkCreateRequest) (*VirtualNetwork, *Response, error) + Get(string, *GetOptions) (*VirtualNetwork, *Response, error) + Delete(virtualNetworkID string) (*Response, error) +} + +type VirtualNetwork struct { + ID string `json:"id"` + Description string `json:"description,omitempty"` + VXLAN int `json:"vxlan,omitempty"` + FacilityCode string `json:"facility_code,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Href string `json:"href"` + Project Project `json:"assigned_to"` +} + +type ProjectVirtualNetworkServiceOp struct { + client *Client +} + +type VirtualNetworkListResponse struct { + VirtualNetworks []VirtualNetwork `json:"virtual_networks"` +} + +func (i *ProjectVirtualNetworkServiceOp) List(projectID string, listOpt *ListOptions) (*VirtualNetworkListResponse, *Response, error) { + + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, virtualNetworkBasePath, params) + output := new(VirtualNetworkListResponse) + + resp, err := i.client.DoRequest("GET", path, nil, output) + if err != nil { + return nil, nil, err + } + + return output, resp, nil +} + +type VirtualNetworkCreateRequest struct { + ProjectID string `json:"project_id"` + Description string `json:"description"` + Facility string `json:"facility"` +} + +func (i *ProjectVirtualNetworkServiceOp) Get(vlanID string, getOpt *GetOptions) (*VirtualNetwork, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", virtualNetworkBasePath, vlanID, params) + vlan := new(VirtualNetwork) + + resp, err := i.client.DoRequest("GET", path, nil, vlan) + if err != nil { + return nil, resp, err + } + + return vlan, resp, err +} + +func (i *ProjectVirtualNetworkServiceOp) Create(input *VirtualNetworkCreateRequest) (*VirtualNetwork, *Response, error) { + // TODO: May need to add timestamp to output from 'post' request + // for the 'created_at' attribute of VirtualNetwork struct since + // API response doesn't include it + path := fmt.Sprintf("%s/%s%s", projectBasePath, input.ProjectID, virtualNetworkBasePath) + output := new(VirtualNetwork) + + resp, err := i.client.DoRequest("POST", path, input, output) + if err != nil { + return nil, nil, err + } + + return output, resp, nil +} + +func (i *ProjectVirtualNetworkServiceOp) Delete(virtualNetworkID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", virtualNetworkBasePath, virtualNetworkID) + + resp, err := i.client.DoRequest("DELETE", path, nil, nil) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/vendor/github.com/packethost/packngo/volumes.go b/vendor/github.com/packethost/packngo/volumes.go new file mode 100644 index 000000000..ebaaddf1c --- /dev/null +++ b/vendor/github.com/packethost/packngo/volumes.go @@ -0,0 +1,238 @@ +package packngo + +import ( + "fmt" +) + +const ( + volumeBasePath = "/storage" + attachmentsBasePath = "/attachments" +) + +// VolumeService interface defines available Volume methods +type VolumeService interface { + List(string, *ListOptions) ([]Volume, *Response, error) + Get(string, *GetOptions) (*Volume, *Response, error) + Update(string, *VolumeUpdateRequest) (*Volume, *Response, error) + Delete(string) (*Response, error) + Create(*VolumeCreateRequest, string) (*Volume, *Response, error) + Lock(string) (*Response, error) + Unlock(string) (*Response, error) +} + +// VolumeAttachmentService defines attachment methdods +type VolumeAttachmentService interface { + Get(string, *GetOptions) (*VolumeAttachment, *Response, error) + Create(string, string) (*VolumeAttachment, *Response, error) + Delete(string) (*Response, error) +} + +type volumesRoot struct { + Volumes []Volume `json:"volumes"` + Meta meta `json:"meta"` +} + +// Volume represents a volume +type Volume struct { + Attachments []*VolumeAttachment `json:"attachments,omitempty"` + BillingCycle string `json:"billing_cycle,omitempty"` + Created string `json:"created_at,omitempty"` + Description string `json:"description,omitempty"` + Facility *Facility `json:"facility,omitempty"` + Href string `json:"href,omitempty"` + ID string `json:"id"` + Locked bool `json:"locked,omitempty"` + Name string `json:"name,omitempty"` + Plan *Plan `json:"plan,omitempty"` + Project *Project `json:"project,omitempty"` + Size int `json:"size,omitempty"` + SnapshotPolicies []*SnapshotPolicy `json:"snapshot_policies,omitempty"` + State string `json:"state,omitempty"` + Updated string `json:"updated_at,omitempty"` +} + +// SnapshotPolicy used to execute actions on volume +type SnapshotPolicy struct { + ID string `json:"id"` + Href string `json:"href"` + SnapshotFrequency string `json:"snapshot_frequency,omitempty"` + SnapshotCount int `json:"snapshot_count,omitempty"` +} + +func (v Volume) String() string { + return Stringify(v) +} + +// VolumeCreateRequest type used to create a Packet volume +type VolumeCreateRequest struct { + BillingCycle string `json:"billing_cycle"` + Description string `json:"description,omitempty"` + Locked bool `json:"locked,omitempty"` + Size int `json:"size"` + PlanID string `json:"plan_id"` + FacilityID string `json:"facility_id"` + SnapshotPolicies []*SnapshotPolicy `json:"snapshot_policies,omitempty"` +} + +func (v VolumeCreateRequest) String() string { + return Stringify(v) +} + +// VolumeUpdateRequest type used to update a Packet volume +type VolumeUpdateRequest struct { + Description *string `json:"description,omitempty"` + PlanID *string `json:"plan_id,omitempty"` + Size *int `json:"size,omitempty"` + BillingCycle *string `json:"billing_cycle,omitempty"` +} + +// VolumeAttachment is a type from Packet API +type VolumeAttachment struct { + Href string `json:"href"` + ID string `json:"id"` + Volume Volume `json:"volume"` + Device Device `json:"device"` +} + +func (v VolumeUpdateRequest) String() string { + return Stringify(v) +} + +// VolumeAttachmentServiceOp implements VolumeService +type VolumeAttachmentServiceOp struct { + client *Client +} + +// VolumeServiceOp implements VolumeService +type VolumeServiceOp struct { + client *Client +} + +// List returns the volumes for a project +func (v *VolumeServiceOp) List(projectID string, listOpt *ListOptions) (volumes []Volume, resp *Response, err error) { + params := createListOptionsURL(listOpt) + path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, volumeBasePath, params) + + for { + subset := new(volumesRoot) + + resp, err = v.client.DoRequest("GET", path, nil, subset) + if err != nil { + return nil, resp, err + } + + volumes = append(volumes, subset.Volumes...) + + if subset.Meta.Next != nil && (listOpt == nil || listOpt.Page == 0) { + path = subset.Meta.Next.Href + if params != "" { + path = fmt.Sprintf("%s&%s", path, params) + } + continue + } + + return + } +} + +// Get returns a volume by id +func (v *VolumeServiceOp) Get(volumeID string, getOpt *GetOptions) (*Volume, *Response, error) { + params := createGetOptionsURL(getOpt) + path := fmt.Sprintf("%s/%s?%s", volumeBasePath, volumeID, params) + volume := new(Volume) + + resp, err := v.client.DoRequest("GET", path, nil, volume) + if err != nil { + return nil, resp, err + } + + return volume, resp, err +} + +// Update updates a volume +func (v *VolumeServiceOp) Update(id string, updateRequest *VolumeUpdateRequest) (*Volume, *Response, error) { + path := fmt.Sprintf("%s/%s", volumeBasePath, id) + volume := new(Volume) + + resp, err := v.client.DoRequest("PATCH", path, updateRequest, volume) + if err != nil { + return nil, resp, err + } + + return volume, resp, err +} + +// Delete deletes a volume +func (v *VolumeServiceOp) Delete(volumeID string) (*Response, error) { + path := fmt.Sprintf("%s/%s", volumeBasePath, volumeID) + + return v.client.DoRequest("DELETE", path, nil, nil) +} + +// Create creates a new volume for a project +func (v *VolumeServiceOp) Create(createRequest *VolumeCreateRequest, projectID string) (*Volume, *Response, error) { + url := fmt.Sprintf("%s/%s%s", projectBasePath, projectID, volumeBasePath) + volume := new(Volume) + + resp, err := v.client.DoRequest("POST", url, createRequest, volume) + if err != nil { + return nil, resp, err + } + + return volume, resp, err +} + +// Attachments + +// Create Attachment, i.e. attach volume to a device +func (v *VolumeAttachmentServiceOp) Create(volumeID, deviceID string) (*VolumeAttachment, *Response, error) { + url := fmt.Sprintf("%s/%s%s", volumeBasePath, volumeID, attachmentsBasePath) + volAttachParam := map[string]string{ + "device_id": deviceID, + } + volumeAttachment := new(VolumeAttachment) + + resp, err := v.client.DoRequest("POST", url, volAttachParam, volumeAttachment) + if err != nil { + return nil, resp, err + } + return volumeAttachment, resp, nil +} + +// Get gets attachment by id +func (v *VolumeAttachmentServiceOp) Get(attachmentID string, getOpt *GetOptions) (*VolumeAttachment, *Response, error) { + params := createGetOptionsURL(getOpt) + + path := fmt.Sprintf("%s%s/%s?%s", volumeBasePath, attachmentsBasePath, attachmentID, params) + volumeAttachment := new(VolumeAttachment) + + resp, err := v.client.DoRequest("GET", path, nil, volumeAttachment) + if err != nil { + return nil, resp, err + } + + return volumeAttachment, resp, nil +} + +// Delete deletes attachment by id +func (v *VolumeAttachmentServiceOp) Delete(attachmentID string) (*Response, error) { + path := fmt.Sprintf("%s%s/%s", volumeBasePath, attachmentsBasePath, attachmentID) + + return v.client.DoRequest("DELETE", path, nil, nil) +} + +// Lock sets a volume to "locked" +func (s *VolumeServiceOp) Lock(id string) (*Response, error) { + path := fmt.Sprintf("%s/%s", volumeBasePath, id) + action := lockType{Locked: true} + + return s.client.DoRequest("PATCH", path, action, nil) +} + +// Unlock sets a volume to "unlocked" +func (s *VolumeServiceOp) Unlock(id string) (*Response, error) { + path := fmt.Sprintf("%s/%s", volumeBasePath, id) + action := lockType{Locked: false} + + return s.client.DoRequest("PATCH", path, action, nil) +} diff --git a/vendor/github.com/packethost/packngo/vpn.go b/vendor/github.com/packethost/packngo/vpn.go new file mode 100644 index 000000000..f228f7d43 --- /dev/null +++ b/vendor/github.com/packethost/packngo/vpn.go @@ -0,0 +1,50 @@ +package packngo + +import "fmt" + +const vpnBasePath = "/user/vpn" + +// VPNConfig struct +type VPNConfig struct { + Config string `json:"config,omitempty"` +} + +// VPNService interface defines available VPN functions +type VPNService interface { + Enable() (*Response, error) + Disable() (*Response, error) + Get(code string, getOpt *GetOptions) (*VPNConfig, *Response, error) +} + +// VPNServiceOp implements VPNService +type VPNServiceOp struct { + client *Client +} + +// Enable VPN for current user +func (s *VPNServiceOp) Enable() (resp *Response, err error) { + return s.client.DoRequest("POST", vpnBasePath, nil, nil) +} + +// Disable VPN for current user +func (s *VPNServiceOp) Disable() (resp *Response, err error) { + return s.client.DoRequest("DELETE", vpnBasePath, nil, nil) + +} + +// Get returns the client vpn config for the currently logged-in user. +func (s *VPNServiceOp) Get(code string, getOpt *GetOptions) (config *VPNConfig, resp *Response, err error) { + params := createGetOptionsURL(getOpt) + config = &VPNConfig{} + path := fmt.Sprintf("%s?code=%s", vpnBasePath, code) + if params != "" { + path += params + } + + resp, err = s.client.DoRequest("GET", path, nil, config) + if err != nil { + return nil, resp, err + } + + return config, resp, err +}