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 }