traefik/vendor/github.com/sacloud/libsacloud/api/disk.go
2019-04-26 11:26:04 +02:00

350 lines
9.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package api
import (
"fmt"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
var (
// allowDiskEditTags ディスクの編集可否判定に用いるタグ
allowDiskEditTags = []string{
"os-unix",
"os-linux",
}
// bundleInfoWindowsHostClass ディスクの編集可否判定に用いる、BundleInfoでのWindows判定文字列
bundleInfoWindowsHostClass = "ms_windows"
)
// DiskAPI ディスクAPI
type DiskAPI struct {
*baseAPI
}
// NewDiskAPI ディスクAPI作成
func NewDiskAPI(client *Client) *DiskAPI {
return &DiskAPI{
&baseAPI{
client: client,
// FuncGetResourceURL
FuncGetResourceURL: func() string {
return "disk"
},
},
}
}
// SortByConnectionOrder 接続順でのソート
func (api *DiskAPI) SortByConnectionOrder(reverse bool) *DiskAPI {
api.sortBy("ConnectionOrder", reverse)
return api
}
// WithServerID サーバーID条件
func (api *DiskAPI) WithServerID(id int64) *DiskAPI {
api.FilterBy("Server.ID", id)
return api
}
// Create 新規作成
func (api *DiskAPI) Create(value *sacloud.Disk) (*sacloud.Disk, error) {
//HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないため文字列で受ける
type diskResponse struct {
*sacloud.Response
// Success
Success string `json:",omitempty"`
}
res := &diskResponse{}
rawBody := &sacloud.Request{}
rawBody.Disk = value
if len(value.DistantFrom) > 0 {
rawBody.DistantFrom = value.DistantFrom
value.DistantFrom = []int64{}
}
err := api.create(rawBody, res)
if err != nil {
return nil, err
}
return res.Disk, nil
}
// CreateWithConfig ディスク作成とディスクの修正、サーバ起動(指定されていれば)を回のAPI呼び出しで実行
func (api *DiskAPI) CreateWithConfig(value *sacloud.Disk, config *sacloud.DiskEditValue, bootAtAvailable bool) (*sacloud.Disk, error) {
//HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないため文字列で受ける("Accepted"などが返る)
type diskResponse struct {
*sacloud.Response
// Success
Success string `json:",omitempty"`
}
res := &diskResponse{}
type diskRequest struct {
*sacloud.Request
Config *sacloud.DiskEditValue `json:",omitempty"`
BootAtAvailable bool `json:",omitempty"`
}
rawBody := &diskRequest{
Request: &sacloud.Request{},
BootAtAvailable: bootAtAvailable,
}
rawBody.Disk = value
rawBody.Config = config
if len(value.DistantFrom) > 0 {
rawBody.DistantFrom = value.DistantFrom
value.DistantFrom = []int64{}
}
err := api.create(rawBody, res)
if err != nil {
return nil, err
}
return res.Disk, nil
}
// NewCondig ディスクの修正用パラメーター作成
func (api *DiskAPI) NewCondig() *sacloud.DiskEditValue {
return &sacloud.DiskEditValue{}
}
// Config ディスクの修正
func (api *DiskAPI) Config(id int64, disk *sacloud.DiskEditValue) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/config", api.getResourceURL(), id)
)
return api.modify(method, uri, disk)
}
func (api *DiskAPI) install(id int64, body *sacloud.Disk) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/install", api.getResourceURL(), id)
)
//HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないため文字列で受ける
type diskResponse struct {
*sacloud.ResultFlagValue
// Success
Success string `json:",omitempty"`
}
res := &diskResponse{}
rawBody := &sacloud.Request{}
rawBody.Disk = body
if len(body.DistantFrom) > 0 {
rawBody.DistantFrom = body.DistantFrom
body.DistantFrom = []int64{}
}
err := api.baseAPI.request(method, uri, rawBody, res)
if err != nil {
return false, err
}
return res.IsOk, nil
}
// ReinstallFromBlank ブランクディスクから再インストール
func (api *DiskAPI) ReinstallFromBlank(id int64, sizeMB int) (bool, error) {
var body = &sacloud.Disk{}
body.SetSizeMB(sizeMB)
return api.install(id, body)
}
// ReinstallFromArchive アーカイブからの再インストール
func (api *DiskAPI) ReinstallFromArchive(id int64, archiveID int64, distantFrom ...int64) (bool, error) {
var body = &sacloud.Disk{}
body.SetSourceArchive(archiveID)
if len(distantFrom) > 0 {
body.SetDistantFrom(distantFrom)
}
return api.install(id, body)
}
// ReinstallFromDisk ディスクからの再インストール
func (api *DiskAPI) ReinstallFromDisk(id int64, diskID int64, distantFrom ...int64) (bool, error) {
var body = &sacloud.Disk{}
body.SetSourceDisk(diskID)
if len(distantFrom) > 0 {
body.SetDistantFrom(distantFrom)
}
return api.install(id, body)
}
// ToBlank ディスクを空にする
func (api *DiskAPI) ToBlank(diskID int64) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/to/blank", api.getResourceURL(), diskID)
)
return api.modify(method, uri, nil)
}
// ResizePartition パーティションのリサイズ
func (api *DiskAPI) ResizePartition(diskID int64) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/resize-partition", api.getResourceURL(), diskID)
)
return api.modify(method, uri, nil)
}
// DisconnectFromServer サーバーとの接続解除
func (api *DiskAPI) DisconnectFromServer(diskID int64) (bool, error) {
var (
method = "DELETE"
uri = fmt.Sprintf("%s/%d/to/server", api.getResourceURL(), diskID)
)
return api.modify(method, uri, nil)
}
// ConnectToServer サーバーとの接続
func (api *DiskAPI) ConnectToServer(diskID int64, serverID int64) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/to/server/%d", api.getResourceURL(), diskID, serverID)
)
return api.modify(method, uri, nil)
}
// State ディスクの状態を取得し有効な状態か判定
func (api *DiskAPI) State(diskID int64) (bool, error) {
disk, err := api.Read(diskID)
if err != nil {
return false, err
}
return disk.IsAvailable(), nil
}
// SleepWhileCopying コピー終了まで待機
func (api *DiskAPI) SleepWhileCopying(id int64, timeout time.Duration) error {
handler := waitingForAvailableFunc(func() (hasAvailable, error) {
return api.Read(id)
}, 0)
return blockingPoll(handler, timeout)
}
// AsyncSleepWhileCopying コピー終了まで待機(非同期)
func (api *DiskAPI) AsyncSleepWhileCopying(id int64, timeout time.Duration) (chan (interface{}), chan (interface{}), chan (error)) {
handler := waitingForAvailableFunc(func() (hasAvailable, error) {
return api.Read(id)
}, 0)
return poll(handler, timeout)
}
// Monitor アクティビティーモニター取得
func (api *DiskAPI) Monitor(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
return api.baseAPI.monitor(id, body)
}
// CanEditDisk ディスクの修正が可能か判定
func (api *DiskAPI) CanEditDisk(id int64) (bool, error) {
disk, err := api.Read(id)
if err != nil {
return false, err
}
if disk == nil {
return false, nil
}
// BundleInfoがあれば編集不可
if disk.BundleInfo != nil && disk.BundleInfo.HostClass == bundleInfoWindowsHostClass {
// Windows
return false, nil
}
// SophosUTMであれば編集不可
if disk.HasTag("pkg-sophosutm") || disk.IsSophosUTM() {
return false, nil
}
// OPNsenseであれば編集不可
if disk.HasTag("distro-opnsense") {
return false, nil
}
// Netwiser VEであれば編集不可
if disk.HasTag("pkg-netwiserve") {
return false, nil
}
// ソースアーカイブ/ソースディスクともに持っていない場合
if disk.SourceArchive == nil && disk.SourceDisk == nil {
//ブランクディスクがソース
return false, nil
}
for _, t := range allowDiskEditTags {
if disk.HasTag(t) {
// 対応OSインストール済みディスク
return true, nil
}
}
// ここまできても判定できないならソースに投げる
if disk.SourceDisk != nil && disk.SourceDisk.Availability != "discontinued" {
return api.client.Disk.CanEditDisk(disk.SourceDisk.ID)
}
if disk.SourceArchive != nil && disk.SourceArchive.Availability != "discontinued" {
return api.client.Archive.CanEditDisk(disk.SourceArchive.ID)
}
return false, nil
}
// GetPublicArchiveIDFromAncestors 祖先の中からパブリックアーカイブのIDを検索
func (api *DiskAPI) GetPublicArchiveIDFromAncestors(id int64) (int64, bool) {
emptyID := int64(0)
disk, err := api.Read(id)
if err != nil {
return emptyID, false
}
if disk == nil {
return emptyID, false
}
// BundleInfoがあれば編集不可
if disk.BundleInfo != nil && disk.BundleInfo.HostClass == bundleInfoWindowsHostClass {
// Windows
return emptyID, false
}
// SophosUTMであれば編集不可
if disk.HasTag("pkg-sophosutm") || disk.IsSophosUTM() {
return emptyID, false
}
// OPNsenseであれば編集不可
if disk.HasTag("distro-opnsense") {
return emptyID, false
}
// Netwiser VEであれば編集不可
if disk.HasTag("pkg-netwiserve") {
return emptyID, false
}
for _, t := range allowDiskEditTags {
if disk.HasTag(t) {
// 対応OSインストール済みディスク
return disk.ID, true
}
}
// ここまできても判定できないならソースに投げる
if disk.SourceDisk != nil && disk.SourceDisk.Availability != "discontinued" {
return api.client.Disk.GetPublicArchiveIDFromAncestors(disk.SourceDisk.ID)
}
if disk.SourceArchive != nil && disk.SourceArchive.Availability != "discontinued" {
return api.client.Archive.GetPublicArchiveIDFromAncestors(disk.SourceArchive.ID)
}
return emptyID, false
}