2018-06-21 19:24:45 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
2018-12-06 21:50:17 +00:00
|
|
|
|
|
|
|
"github.com/sacloud/libsacloud/sacloud"
|
2018-06-21 19:24:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
//HACK: さくらのAPI側仕様: Applianceの内容によってJSONフォーマットが異なるため
|
|
|
|
// ロードバランサ/VPCルータそれぞれでリクエスト/レスポンスデータ型を定義する。
|
|
|
|
|
|
|
|
// SearchVPCRouterResponse VPCルーター検索レスポンス
|
|
|
|
type SearchVPCRouterResponse struct {
|
|
|
|
// Total 総件数
|
|
|
|
Total int `json:",omitempty"`
|
|
|
|
// From ページング開始位置
|
|
|
|
From int `json:",omitempty"`
|
|
|
|
// Count 件数
|
|
|
|
Count int `json:",omitempty"`
|
|
|
|
// VPCRouters VPCルーター リスト
|
|
|
|
VPCRouters []sacloud.VPCRouter `json:"Appliances,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type vpcRouterRequest struct {
|
|
|
|
VPCRouter *sacloud.VPCRouter `json:"Appliance,omitempty"`
|
|
|
|
From int `json:",omitempty"`
|
|
|
|
Count int `json:",omitempty"`
|
|
|
|
Sort []string `json:",omitempty"`
|
|
|
|
Filter map[string]interface{} `json:",omitempty"`
|
|
|
|
Exclude []string `json:",omitempty"`
|
|
|
|
Include []string `json:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type vpcRouterResponse struct {
|
|
|
|
*sacloud.ResultFlagValue
|
|
|
|
*sacloud.VPCRouter `json:"Appliance,omitempty"`
|
|
|
|
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type vpcRouterStatusResponse struct {
|
|
|
|
*sacloud.ResultFlagValue
|
|
|
|
*sacloud.VPCRouterStatus `json:"Router"`
|
|
|
|
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type vpcRouterS2sConnInfoResponse struct {
|
|
|
|
*sacloud.ResultFlagValue
|
|
|
|
*sacloud.SiteToSiteConnectionInfo
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
// VPCRouterAPI VPCルーターAPI
|
|
|
|
type VPCRouterAPI struct {
|
|
|
|
*baseAPI
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewVPCRouterAPI VPCルーターAPI作成
|
|
|
|
func NewVPCRouterAPI(client *Client) *VPCRouterAPI {
|
|
|
|
return &VPCRouterAPI{
|
|
|
|
&baseAPI{
|
|
|
|
client: client,
|
|
|
|
FuncGetResourceURL: func() string {
|
|
|
|
return "appliance"
|
|
|
|
},
|
|
|
|
FuncBaseSearchCondition: func() *sacloud.Request {
|
|
|
|
res := &sacloud.Request{}
|
|
|
|
res.AddFilter("Class", "vpcrouter")
|
|
|
|
return res
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find 検索
|
|
|
|
func (api *VPCRouterAPI) Find() (*SearchVPCRouterResponse, error) {
|
|
|
|
data, err := api.client.newRequest("GET", api.getResourceURL(), api.getSearchState())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var res SearchVPCRouterResponse
|
|
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *VPCRouterAPI) request(f func(*vpcRouterResponse) error) (*sacloud.VPCRouter, error) {
|
|
|
|
res := &vpcRouterResponse{}
|
|
|
|
err := f(res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.VPCRouter, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *VPCRouterAPI) createRequest(value *sacloud.VPCRouter) *vpcRouterResponse {
|
|
|
|
return &vpcRouterResponse{VPCRouter: value}
|
|
|
|
}
|
|
|
|
|
|
|
|
// New 新規作成用パラメーター作成
|
|
|
|
func (api *VPCRouterAPI) New() *sacloud.VPCRouter {
|
|
|
|
return sacloud.CreateNewVPCRouter()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create 新規作成
|
|
|
|
func (api *VPCRouterAPI) Create(value *sacloud.VPCRouter) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.request(func(res *vpcRouterResponse) error {
|
|
|
|
return api.create(api.createRequest(value), res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read 読み取り
|
|
|
|
func (api *VPCRouterAPI) Read(id int64) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.request(func(res *vpcRouterResponse) error {
|
|
|
|
return api.read(id, nil, res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update 更新
|
|
|
|
func (api *VPCRouterAPI) Update(id int64, value *sacloud.VPCRouter) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.request(func(res *vpcRouterResponse) error {
|
|
|
|
return api.update(id, api.createRequest(value), res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateSetting 設定更新
|
|
|
|
func (api *VPCRouterAPI) UpdateSetting(id int64, value *sacloud.VPCRouter) (*sacloud.VPCRouter, error) {
|
|
|
|
req := &sacloud.VPCRouter{
|
|
|
|
// Settings
|
|
|
|
Settings: value.Settings,
|
|
|
|
}
|
|
|
|
return api.request(func(res *vpcRouterResponse) error {
|
|
|
|
return api.update(id, api.createRequest(req), res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete 削除
|
|
|
|
func (api *VPCRouterAPI) Delete(id int64) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.request(func(res *vpcRouterResponse) error {
|
|
|
|
return api.delete(id, nil, res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Config 設定変更の反映
|
|
|
|
func (api *VPCRouterAPI) Config(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/config", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConnectToSwitch 指定のインデックス位置のNICをスイッチへ接続
|
|
|
|
func (api *VPCRouterAPI) ConnectToSwitch(id int64, switchID int64, nicIndex int) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/interface/%d/to/switch/%d", api.getResourceURL(), id, nicIndex, switchID)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisconnectFromSwitch 指定のインデックス位置のNICをスイッチから切断
|
|
|
|
func (api *VPCRouterAPI) DisconnectFromSwitch(id int64, nicIndex int) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/interface/%d/to/switch", api.getResourceURL(), id, nicIndex)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsUp 起動しているか判定
|
|
|
|
func (api *VPCRouterAPI) IsUp(id int64) (bool, error) {
|
|
|
|
router, err := api.Read(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return router.Instance.IsUp(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsDown ダウンしているか判定
|
|
|
|
func (api *VPCRouterAPI) IsDown(id int64) (bool, error) {
|
|
|
|
router, err := api.Read(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return router.Instance.IsDown(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Boot 起動
|
|
|
|
func (api *VPCRouterAPI) Boot(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/power", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown シャットダウン(graceful)
|
|
|
|
func (api *VPCRouterAPI) Shutdown(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/power", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop シャットダウン(force)
|
|
|
|
func (api *VPCRouterAPI) Stop(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "DELETE"
|
|
|
|
uri = fmt.Sprintf("%s/%d/power", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, map[string]bool{"Force": true})
|
|
|
|
}
|
|
|
|
|
|
|
|
// RebootForce 再起動
|
|
|
|
func (api *VPCRouterAPI) RebootForce(id int64) (bool, error) {
|
|
|
|
var (
|
|
|
|
method = "PUT"
|
|
|
|
uri = fmt.Sprintf("%s/%d/reset", api.getResourceURL(), id)
|
|
|
|
)
|
|
|
|
|
|
|
|
return api.modify(method, uri, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SleepUntilUp 起動するまで待機
|
|
|
|
func (api *VPCRouterAPI) SleepUntilUp(id int64, timeout time.Duration) error {
|
|
|
|
handler := waitingForUpFunc(func() (hasUpDown, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, 0)
|
|
|
|
return blockingPoll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SleepUntilDown ダウンするまで待機
|
|
|
|
func (api *VPCRouterAPI) SleepUntilDown(id int64, timeout time.Duration) error {
|
|
|
|
handler := waitingForDownFunc(func() (hasUpDown, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, 0)
|
|
|
|
return blockingPoll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SleepWhileCopying コピー終了まで待機
|
|
|
|
//
|
|
|
|
// maxRetry: リクエストタイミングによって、コピー完了までの間に404エラーとなる場合がある。
|
|
|
|
// 通常そのまま待てばコピー完了するため、404エラーが発生してもmaxRetryで指定した回数分は待機する。
|
|
|
|
func (api *VPCRouterAPI) SleepWhileCopying(id int64, timeout time.Duration, maxRetry int) error {
|
|
|
|
handler := waitingForAvailableFunc(func() (hasAvailable, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, maxRetry)
|
|
|
|
return blockingPoll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AsyncSleepWhileCopying コピー終了まで待機(非同期)
|
|
|
|
func (api *VPCRouterAPI) AsyncSleepWhileCopying(id int64, timeout time.Duration, maxRetry int) (chan (interface{}), chan (interface{}), chan (error)) {
|
|
|
|
handler := waitingForAvailableFunc(func() (hasAvailable, error) {
|
|
|
|
return api.Read(id)
|
|
|
|
}, maxRetry)
|
|
|
|
return poll(handler, timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddStandardInterface スタンダードプランでのインターフェース追加
|
|
|
|
func (api *VPCRouterAPI) AddStandardInterface(routerID int64, switchID int64, ipaddress string, maskLen int) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.addInterface(routerID, switchID, &sacloud.VPCRouterInterface{
|
|
|
|
IPAddress: []string{ipaddress},
|
|
|
|
NetworkMaskLen: maskLen,
|
|
|
|
VirtualIPAddress: "",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddPremiumInterface プレミアムプランでのインターフェース追加
|
|
|
|
func (api *VPCRouterAPI) AddPremiumInterface(routerID int64, switchID int64, ipaddresses []string, maskLen int, virtualIP string) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.addInterface(routerID, switchID, &sacloud.VPCRouterInterface{
|
|
|
|
IPAddress: ipaddresses,
|
|
|
|
NetworkMaskLen: maskLen,
|
|
|
|
VirtualIPAddress: virtualIP,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *VPCRouterAPI) addInterface(routerID int64, switchID int64, routerNIC *sacloud.VPCRouterInterface) (*sacloud.VPCRouter, error) {
|
|
|
|
router, err := api.Read(routerID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req := &sacloud.VPCRouter{Settings: &sacloud.VPCRouterSettings{}}
|
|
|
|
|
|
|
|
if router.Settings == nil {
|
|
|
|
req.Settings = &sacloud.VPCRouterSettings{
|
|
|
|
Router: &sacloud.VPCRouterSetting{
|
|
|
|
Interfaces: []*sacloud.VPCRouterInterface{nil},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
req.Settings.Router = router.Settings.Router
|
|
|
|
}
|
|
|
|
|
|
|
|
index := len(req.Settings.Router.Interfaces) // add to last
|
|
|
|
return api.addInterfaceAt(routerID, switchID, routerNIC, index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddStandardInterfaceAt スタンダードプランでの指定位置へのインターフェース追加
|
|
|
|
func (api *VPCRouterAPI) AddStandardInterfaceAt(routerID int64, switchID int64, ipaddress string, maskLen int, index int) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.addInterfaceAt(routerID, switchID, &sacloud.VPCRouterInterface{
|
|
|
|
IPAddress: []string{ipaddress},
|
|
|
|
NetworkMaskLen: maskLen,
|
|
|
|
VirtualIPAddress: "",
|
|
|
|
}, index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddPremiumInterfaceAt プレミアムプランでの指定位置へのインターフェース追加
|
|
|
|
func (api *VPCRouterAPI) AddPremiumInterfaceAt(routerID int64, switchID int64, ipaddresses []string, maskLen int, virtualIP string, index int) (*sacloud.VPCRouter, error) {
|
|
|
|
return api.addInterfaceAt(routerID, switchID, &sacloud.VPCRouterInterface{
|
|
|
|
IPAddress: ipaddresses,
|
|
|
|
NetworkMaskLen: maskLen,
|
|
|
|
VirtualIPAddress: virtualIP,
|
|
|
|
}, index)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (api *VPCRouterAPI) addInterfaceAt(routerID int64, switchID int64, routerNIC *sacloud.VPCRouterInterface, index int) (*sacloud.VPCRouter, error) {
|
|
|
|
router, err := api.Read(routerID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req := &sacloud.VPCRouter{Settings: &sacloud.VPCRouterSettings{}}
|
|
|
|
|
|
|
|
if router.Settings == nil {
|
|
|
|
req.Settings = &sacloud.VPCRouterSettings{
|
|
|
|
Router: &sacloud.VPCRouterSetting{
|
|
|
|
Interfaces: []*sacloud.VPCRouterInterface{nil},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
req.Settings.Router = router.Settings.Router
|
|
|
|
}
|
|
|
|
|
|
|
|
//connect to switch
|
|
|
|
_, err = api.ConnectToSwitch(routerID, switchID, index)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < index; i++ {
|
|
|
|
if len(req.Settings.Router.Interfaces) < index {
|
|
|
|
req.Settings.Router.Interfaces = append(req.Settings.Router.Interfaces, nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(req.Settings.Router.Interfaces) < index+1 {
|
|
|
|
req.Settings.Router.Interfaces = append(req.Settings.Router.Interfaces, routerNIC)
|
|
|
|
} else {
|
|
|
|
req.Settings.Router.Interfaces[index] = routerNIC
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := api.UpdateSetting(routerID, req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteInterfaceAt 指定位置のインターフェース削除
|
|
|
|
func (api *VPCRouterAPI) DeleteInterfaceAt(routerID int64, index int) (*sacloud.VPCRouter, error) {
|
|
|
|
router, err := api.Read(routerID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req := &sacloud.VPCRouter{Settings: &sacloud.VPCRouterSettings{}}
|
|
|
|
|
|
|
|
if router.Settings == nil {
|
|
|
|
req.Settings = &sacloud.VPCRouterSettings{
|
|
|
|
// Router
|
|
|
|
Router: &sacloud.VPCRouterSetting{
|
|
|
|
// Interfaces
|
|
|
|
Interfaces: []*sacloud.VPCRouterInterface{nil},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
req.Settings.Router = router.Settings.Router
|
|
|
|
}
|
|
|
|
|
|
|
|
//disconnect to switch
|
|
|
|
_, err = api.DisconnectFromSwitch(routerID, index)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if index < len(req.Settings.Router.Interfaces) {
|
|
|
|
req.Settings.Router.Interfaces[index] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := api.UpdateSetting(routerID, req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// MonitorBy 指定位置のインターフェースのアクティビティーモニター取得
|
|
|
|
func (api *VPCRouterAPI) MonitorBy(id int64, nicIndex int, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
|
|
|
|
return api.baseAPI.applianceMonitorBy(id, "interface", nicIndex, body)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Status ログなどのステータス情報 取得
|
|
|
|
func (api *VPCRouterAPI) Status(id int64) (*sacloud.VPCRouterStatus, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/status", api.getResourceURL(), id)
|
|
|
|
res = &vpcRouterStatusResponse{}
|
|
|
|
)
|
|
|
|
err := api.baseAPI.request(method, uri, nil, res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.VPCRouterStatus, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SiteToSiteConnectionDetails サイト間VPN接続情報を取得
|
|
|
|
func (api *VPCRouterAPI) SiteToSiteConnectionDetails(id int64) (*sacloud.SiteToSiteConnectionInfo, error) {
|
|
|
|
var (
|
|
|
|
method = "GET"
|
|
|
|
uri = fmt.Sprintf("%s/%d/vpcrouter/sitetosite/connectiondetails", api.getResourceURL(), id)
|
|
|
|
res = &vpcRouterS2sConnInfoResponse{}
|
|
|
|
)
|
|
|
|
err := api.baseAPI.request(method, uri, nil, res)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res.SiteToSiteConnectionInfo, nil
|
|
|
|
}
|