Upclapi/storage.go
2021-08-28 14:45:05 +01:00

281 lines
8.4 KiB
Go

package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"os"
"strconv"
"strings"
"time"
"github.com/UpCloudLtd/upcloud-go-api/upcloud"
"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
"github.com/UpCloudLtd/upcloud-go-api/upcloud/service"
"gopkg.in/yaml.v3"
)
func NewStoreConfig(dataPath string) (*StoreConfig, error) {
// Create config structure
storeConfig := &StoreConfig{}
// Open config file
file, err := os.Open(dataPath)
if err != nil {
return nil, err
}
defer file.Close()
// Init new YAML decode
d := yaml.NewDecoder(file)
// Start YAML decoding from file
if err := d.Decode(&storeConfig); err != nil {
return nil, err
}
return storeConfig, nil
}
func loadStoreConfig(dataCfgPath string) (*StoreConfig, error) {
// datacfg := &DataConfig{}
storecfg, err := NewStoreConfig(dataCfgPath)
if err != nil {
log.Fatal(err)
return storecfg, err
}
return storecfg, nil
}
func getStorageDevices(srv ServerConfig) []request.CreateServerStorageDevice {
var storageDevices []request.CreateServerStorageDevice
for _,storage := range srv.StorageDevices {
storageDevices = append(storageDevices,request.CreateServerStorageDevice{
Action : storage.Action,
Title : storage.Title,
Storage : storage.Storage,
Size : storage.Size,
Tier : storage.Tier,
})
}
return storageDevices
}
func deleteStorage(s *service.Service, uuid string) error {
fmt.Println("Getting storage")
storages, err := s.GetStorages(&request.GetStoragesRequest{
Access: upcloud.StorageAccessPrivate,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to get storages: %#v\n", err)
return err
}
fmt.Printf("Retrieved %d storages\n", len(storages.Storages))
if len(storages.Storages) > 0 {
for _, storage := range storages.Storages {
if storage.UUID == uuid {
fmt.Printf("Deleting storage %s", storage.UUID)
err := errors.New("Dummy")
for i := 0; err != nil && i < 5; i++ {
fmt.Printf("%d: Deleting %s (%s)\n", i, storage.Title, storage.UUID)
err = s.DeleteStorage(&request.DeleteStorageRequest{
UUID: storage.UUID,
})
}
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to delete storage: %#v (%s)\n", err, err.Error())
return err
}
fmt.Printf("Successfully deleted %s (%s)\n", storage.Title, storage.UUID)
}
}
}
return nil
}
func modifyStorage(s *service.Service, storecfg *StoreConfig) error {
if len(storecfg.Uuid) == 0 {
fmt.Printf("Unable to get storages uuid from data file \n")
return nil
}
for _, item := range storecfg.Servers {
s.StopServer(&request.StopServerRequest{
UUID: item,
StopType: request.ServerStopTypeHard,
})
}
fmt.Println("Getting storage")
storages, err := s.GetStorages(&request.GetStoragesRequest{
Access: upcloud.StorageAccessPrivate,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to get storages: %#v\n", err)
return err
}
fmt.Printf("Retrieved %d storages\n", len(storages.Storages))
if len(storages.Storages) > 0 {
for _, storage := range storages.Storages {
if storage.UUID == storecfg.Uuid {
fmt.Printf("Modify storage %s (%s)\n",storage.Title, storage.UUID)
err := errors.New("Dummy")
for i := 0; err != nil && i < 5; i++ {
fmt.Printf("%d: Modify %s (%s)\n", i, storage.Title, storage.UUID)
_, err = s.ModifyStorage(&request.ModifyStorageRequest{
UUID: storecfg.Uuid,
// Title: datacfg.Title,
Size: storecfg.Size,
// BackupRule *upcloud.BackupRule `json:"backup_rule,omitempty"`
})
}
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to modify storage: %#v (%s)\n", err, err.Error())
// return err
}
fmt.Printf("Successfully modified %s (%s)\n", storage.Title, storage.UUID)
}
}
}
for _, item := range storecfg.Servers {
s.StartServer(&request.StartServerRequest{
UUID: item,
// StopType: request.ServerStopTypeHard,
})
}
return nil
}
func fixStorageDevices(s *service.Service,srvrCfg ServerConfig, serverDetails *upcloud.ServerDetails, targetSize string) {
if len(serverDetails.StorageDevices) == 0 {
return
}
err := errors.New("Dummy")
// fmt.Fprintf(os.Stderr, "%#v: %#v\n", serverDetails.StorageDevices, srvrCfg)
for i, storage := range serverDetails.StorageDevices {
store_size := 0
switch targetSize {
case "size":
store_size = srvrCfg.StorageDevices[i].Size
case "part0":
s := strings.Split(srvrCfg.StorageDevices[i].PartSizes, ",")
store_size, err = strconv.Atoi(s[0])
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to get partsize 0 to create image storage for %s: %#v (%s)\n", storage.Title, err, err.Error())
return
}
case "part1":
s := strings.Split(srvrCfg.StorageDevices[i].PartSizes, ",")
store_size, err = strconv.Atoi(s[1])
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to get partsize 1 to create image storage for %s: %#v (%s)\n", storage.Title, err, err.Error())
return
}
case "final":
store_size = srvrCfg.StorageDevices[i].FinalSize
}
if store_size == 0 {
fmt.Printf("No targetSize found [size|final] for %s (%s) %dGB == %dGB\n",storage.Title, storage.UUID, storage.Size, store_size)
continue
}
if store_size== storage.Size {
fmt.Printf("%s (%s) %dGB == %dGB\n",storage.Title, storage.UUID, storage.Size, store_size)
continue
}
fmt.Printf("FixStorage %s (%s) %dGB to %dGB\n",storage.Title, storage.UUID, storage.Size, store_size)
if serverDetails.Server.State != upcloud.ServerStateStopped {
err = stopOneServer(s, serverDetails.Server)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to stop server %#v: %#v\n", serverDetails.Server.UUID, err)
continue
}
}
_, err = s.ModifyStorage(&request.ModifyStorageRequest{
UUID: storage.UUID,
// Title: srvrCfg.StorageDevices[i].Title,
Size: store_size,
// BackupRule *upcloud.BackupRule `json:"backup_rule,omitempty"`
})
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to modify storage: %#v (%s)\n", err, err.Error())
} else {
fmt.Printf("Successfully modified %s (%s) to %dGB\n", storage.Title, storage.UUID, store_size)
}
}
info,err := s.GetServerDetails(&request.GetServerDetailsRequest{
UUID: serverDetails.UUID,
})
if info.Server.State != upcloud.ServerStateStarted {
startOneServer(s, serverDetails.Server)
}
}
func createStorageImage(s *service.Service, target_uuid string, title string) error {
info,err := s.TemplatizeStorage(&request.TemplatizeStorageRequest{
UUID: target_uuid,
Title: strings.Trim(title, "\""),
})
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to create image storage: %#v (%s)\n", err, err.Error())
} else {
fmt.Printf("Successfully created %s (%s)\n", title, target_uuid)
}
s.WaitForStorageState(&request.WaitForStorageStateRequest{
UUID: target_uuid,
DesiredState: "online",
Timeout: 1 * time.Minute,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to wait for storage to reach desired online state: %#v", err)
return err
}
enc := json.NewEncoder(os.Stdout)
enc.Encode(info)
return nil
}
func listStorages(s *service.Service, dataCfg *DataConfig, target string) error {
storages, err := s.GetStorages(&request.GetStoragesRequest{
Access: upcloud.StorageAccessPrivate,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to get storages: %#v\n", err)
return err
}
servers, _ := s.GetServers()
fmt.Printf("Scanning over %d storages and %d servers \n", len(storages.Storages), len(servers.Servers))
if len(storages.Storages) > 0 {
for _, storage := range storages.Storages {
storage_out := fmt.Sprintf("title: \"%s\", id: %s, size: %d, plan: %s, state: %s, zone: %s, type: %s",
storage.Title, storage.UUID, storage.Size, storage.PartOfPlan, storage.State, storage.Zone, storage.Type)
is_attached := false
for _, server := range servers.Servers {
isInGroup := false
for _, srv := range dataCfg.Servers {
if server.Hostname == srv.Hostname {
isInGroup = true
break
}
}
info,err := s.GetServerDetails(&request.GetServerDetailsRequest{
UUID: server.UUID,
})
if err == nil {
for _, srv_storage := range info.StorageDevices {
if srv_storage.UUID == storage.UUID {
is_attached=true
if isInGroup {
fmt.Printf("%s, attached: \"%s\", id: %s\n", storage_out, server.Title, server.UUID)
}
}
}
}
}
if ! is_attached {
fmt.Printf("%s, attached: none\n", storage_out)
}
if target != "" && storage.UUID == target {
break
}
}
}
return nil
}