resolve conflict

This commit is contained in:
屈轩
2018-11-26 21:20:16 +08:00
106 changed files with 7650 additions and 2156 deletions
Generated
+8 -7
View File
@@ -120,7 +120,7 @@
revision = "e59b73d3c2bf1c328ccb78e683c0462fa1a473c7"
[[projects]]
digest = "1:55bf2a4da68caa693d660683e53bab3e651a940cd46354b997ab68bec7920e23"
digest = "1:ae41c49d4812dd31a848045447637fd0f10cac09af75e1d20825a241c626f3fa"
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
@@ -158,6 +158,8 @@
"service/ec2",
"service/iam",
"service/s3",
"service/s3/s3iface",
"service/s3/s3manager",
"service/sts",
]
pruneopts = "UT"
@@ -1329,7 +1331,7 @@
[[projects]]
branch = "master"
digest = "1:bf987f904fd821c6395fefdab956d070596eb401657fff40420014a3a8e3f45c"
digest = "1:8c4d781aafefb667511de3e0e9fe02170519f63d75a69e34045bd417f25d5523"
name = "yunion.io/x/pkg"
packages = [
"gotypes",
@@ -1353,7 +1355,6 @@
"util/secrules",
"util/sets",
"util/stringutils",
"util/sysutils",
"util/timeutils",
"util/trace",
"util/ttlpool",
@@ -1363,7 +1364,7 @@
"utils",
]
pruneopts = "UT"
revision = "7614d751299a6703a05f757a13e6dc900332e31b"
revision = "883ea57a4b57d551bbf2fb7d1876d6ab9355c486"
[[projects]]
branch = "master"
@@ -1375,11 +1376,11 @@
[[projects]]
branch = "master"
digest = "1:f07a1ef9758f56186dd9039a8608bc9d537070a7c04479dbab6aeb42501001b7"
digest = "1:bbaf572e68e5dad4045e1e424af29838882c620df391fa1631dd8dc851c87a95"
name = "yunion.io/x/structarg"
packages = ["."]
pruneopts = "UT"
revision = "e0cc2c73375327d401b100bd8988fa340c2687ee"
revision = "c95bf78846decd8dea379e925410f2895fb20076"
[solve-meta]
analyzer-name = "dep"
@@ -1406,6 +1407,7 @@
"github.com/aws/aws-sdk-go/service/ec2",
"github.com/aws/aws-sdk-go/service/iam",
"github.com/aws/aws-sdk-go/service/s3",
"github.com/aws/aws-sdk-go/service/s3/s3manager",
"github.com/bitly/go-simplejson",
"github.com/c-bata/go-prompt",
"github.com/coredns/coredns/core/dnsserver",
@@ -1493,7 +1495,6 @@
"yunion.io/x/pkg/util/secrules",
"yunion.io/x/pkg/util/sets",
"yunion.io/x/pkg/util/stringutils",
"yunion.io/x/pkg/util/sysutils",
"yunion.io/x/pkg/util/timeutils",
"yunion.io/x/pkg/util/trace",
"yunion.io/x/pkg/util/ttlpool",
+16
View File
@@ -0,0 +1,16 @@
package shell
import (
"yunion.io/x/onecloud/pkg/mcclient"
)
func init() {
type CloudmetaOptions struct {
PROVIDER_ID string `help:"provider_id"`
REGION_ID string `help:"region_id"`
ZONE_ID string `help:"zone_id"`
}
R(&CloudmetaOptions{}, "instance-type-list", "query backend service for its version", func(s *mcclient.ClientSession, args *CloudmetaOptions) error {
return nil
})
}
+117
View File
@@ -0,0 +1,117 @@
package shell
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
printRouteTableList := func(list *modules.ListResult, columns []string) {
data := list.Data
for _, jsonObj := range data {
jd := jsonObj.(*jsonutils.JSONDict)
routesObj, err := jd.GetArray("routes")
if err != nil {
continue
}
routes := []string{}
for _, routeObj := range routesObj {
typ, _ := routeObj.GetString("type")
cidr, _ := routeObj.GetString("cidr")
next_hop_type, _ := routeObj.GetString("next_hop_type")
next_hop, _ := routeObj.GetString("next_hop")
route := fmt.Sprintf("%8s: %18s %s", typ, cidr, next_hop_type)
if len(next_hop) > 0 {
route += fmt.Sprintf(":%s", next_hop)
}
routes = append(routes, route)
}
s := strings.Join(routes, "\n")
jd.Set("routes", jsonutils.NewString(s))
}
printList(list, columns)
}
R(&options.RouteTableCreateOptions{}, "routetable-create", "Create routetable", func(s *mcclient.ClientSession, opts *options.RouteTableCreateOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
routetable, err := modules.RouteTables.Create(s, params)
if err != nil {
return err
}
printObjectRecursive(routetable)
return nil
})
R(&options.RouteTableGetOptions{}, "routetable-show", "Show routetable", func(s *mcclient.ClientSession, opts *options.RouteTableGetOptions) error {
routetable, err := modules.RouteTables.Get(s, opts.ID, nil)
if err != nil {
return err
}
printObjectRecursive(routetable)
return nil
})
R(&options.RouteTableListOptions{}, "routetable-list", "List routetables", func(s *mcclient.ClientSession, opts *options.RouteTableListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.RouteTables.List(s, params)
if err != nil {
return err
}
printRouteTableList(result, modules.RouteTables.GetColumns(s))
return nil
})
R(&options.RouteTableUpdateOptions{}, "routetable-update", "Update routetable", func(s *mcclient.ClientSession, opts *options.RouteTableUpdateOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
routetable, err := modules.RouteTables.Update(s, opts.ID, params)
if err != nil {
return err
}
printObjectRecursive(routetable)
return nil
})
R(&options.RouteTableAddRoutesOptions{}, "routetable-add-routes", "Add routes to routetable", func(s *mcclient.ClientSession, opts *options.RouteTableAddRoutesOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
routetable, err := modules.RouteTables.PerformAction(s, opts.ID, "add-routes", params)
if err != nil {
return err
}
printObjectRecursive(routetable)
return nil
})
R(&options.RouteTableDelRoutesOptions{}, "routetable-del-routes", "Del routes to routetable", func(s *mcclient.ClientSession, opts *options.RouteTableDelRoutesOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
routetable, err := modules.RouteTables.PerformAction(s, opts.ID, "del-routes", params)
if err != nil {
return err
}
printObjectRecursive(routetable)
return nil
})
R(&options.RouteTableDeleteOptions{}, "routetable-delete", "Show routetable", func(s *mcclient.ClientSession, opts *options.RouteTableDeleteOptions) error {
routetable, err := modules.RouteTables.Delete(s, opts.ID, nil)
if err != nil {
return err
}
printObjectRecursive(routetable)
return nil
})
}
+12
View File
@@ -139,6 +139,18 @@ func init() {
return nil
})
R(&options.ServerIdsOptions{}, "server-switch-to-backup", "Switch geust master to backup host", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error {
ret := modules.Servers.BatchPerformAction(s, opts.ID, "switch-to-backup", nil)
printBatchResults(ret, modules.Servers.GetColumns(s))
return nil
})
R(&options.ServerIdsOptions{}, "server-create-backup", "Create backup guest", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error {
ret := modules.Servers.BatchPerformAction(s, opts.ID, "create-backup", nil)
printBatchResults(ret, modules.Servers.GetColumns(s))
return nil
})
R(&options.ServerStopOptions{}, "server-stop", "Stop servers", func(s *mcclient.ClientSession, opts *options.ServerStopOptions) error {
params, err := options.StructToParams(opts)
if err != nil {
+131
View File
@@ -0,0 +1,131 @@
package shell
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type ServerSkusListOptions struct {
options.BaseListOptions
}
R(&ServerSkusListOptions{}, "server-sku-list", "List all avaiable Server SKU", func(s *mcclient.ClientSession, args *ServerSkusListOptions) error {
params, err := options.ListStructToParams(args)
if err != nil {
return err
}
results, err := modules.ServerSkus.List(s, params)
if err != nil {
return err
}
printList(results, modules.ServerSkus.GetColumns(s))
return nil
})
type ServerSkusShowOptions struct {
ID string `help:"ID or Name of SKU to show"`
}
R(&ServerSkusShowOptions{}, "server-sku-show", "show details of a avaiable Server SKU", func(s *mcclient.ClientSession, args *ServerSkusShowOptions) error {
result, err := modules.ServerSkus.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type ServerSkusCreateOptions struct {
Name string `help:"Name ID of SKU" required:"true" positional:"true"`
CpuCoreCount int `help:"Cpu Count" required:"true" positional:"true"`
MemorySizeMB int `help:"Memory MB" required:"true" positional:"true"`
SkuFamily *string `help:"sku family"`
SkuCategory *string `help:"sku category" choices:"general_purpose|compute_optimized|memory_optimized|storage_optimized|hardware_accelerated|high_memory|high_storage"`
SysDiskResizable *bool `help:"system disk is resizable"`
SysDiskMaxSizeGB *int `help:"system disk maximal size in gb"`
AttachedDiskType *string `help:"attached data disk type"`
AttachedDiskSizeGB *int `help:"attached data disk size in GB"`
AttachedDiskCount *int `help:"attached data disk count"`
MaxDataDiskCount *int `help:"maximal allowed data disk count"`
NicType *string `help:"nic type"`
MaxNicCount *int `help:"maximal nic count"`
GPUSpec *string `help:"GPU spec"`
GPUCount *int `help:"GPU count"`
GPUAttachable *bool `help:"Allow attach GPU"`
Zone *string `help:"Zone ID or name"`
Region *string `help:"Region ID or name"`
}
R(&ServerSkusCreateOptions{}, "server-sku-create", "Create a server sku record", func(s *mcclient.ClientSession, args *ServerSkusCreateOptions) error {
params, err := options.StructToParams(args)
if err != nil {
return err
}
result, err := modules.ServerSkus.Create(s, params)
if err != nil {
return err
}
printObject(result)
return nil
})
type ServerSkusUpdateOptions struct {
ID string `help:"Name or ID of SKU" json:"-"`
Name *string `help:"new name of SKU"`
CpuCoreCount *int `help:"Cpu Count"`
MemorySizeMB *int `help:"Memory MB"`
SkuFamily *string `help:"sku family"`
SkuCategory *string `help:"sku category" choices:"general_purpose|compute_optimized|memory_optimized|storage_optimized|hardware_accelerated|high_memory|high_storage"`
SysDiskResizable *bool `help:"system disk is resizable"`
SysDiskMaxSizeGB *int `help:"system disk maximal size in gb"`
AttachedDiskType *string `help:"attached data disk type"`
AttachedDiskSizeGB *int `help:"attached data disk size in GB"`
AttachedDiskCount *int `help:"attached data disk count"`
MaxDataDiskCount *int `help:"maximal allowed data disk count"`
NicType *string `help:"nic type"`
MaxNicCount *int `help:"maximal nic count"`
GPUSpec *string `help:"GPU spec"`
GPUCount *int `help:"GPU count"`
GPUAttachable *bool `help:"Allow attach GPU"`
Zone *string `help:"Zone ID or name"`
Region *string `help:"Region ID or name"`
}
R(&ServerSkusUpdateOptions{}, "server-sku-update", "Update server sku attributes", func(s *mcclient.ClientSession, args *ServerSkusUpdateOptions) error {
params, err := options.StructToParams(args)
if err != nil {
return err
}
result, err := modules.ServerSkus.Update(s, args.ID, params)
if err != nil {
return err
}
printObject(result)
return nil
})
type ServerSkusDeleteOptions struct {
ID string `help:"Id or name of server sku"`
}
R(&ServerSkusDeleteOptions{}, "server-sku-delete", "Delete a server sku", func(s *mcclient.ClientSession, args *ServerSkusDeleteOptions) error {
result, err := modules.ServerSkus.Delete(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+35 -7
View File
@@ -99,17 +99,21 @@ func init() {
})
type StorageCreateOptions struct {
NAME string `help:"Name of the Storage"`
Capacity int64 `help:"Capacity of the Storage"`
MediumType string `help:"Medium type, either ssd or rotate" choices:"ssd|rotate"`
StorageType string `help:"Storage type" choices:"local|nas|vsan|rbd|baremetal"`
MonHost string `helo:"Ceph mon_host config"`
Key string `helo:"Ceph key config"`
Pool string `helo:"Ceph Poll Name"`
NAME string `help:"Name of the Storage"`
ZONE string `help:"Zone id of storage"`
Capacity int64 `help:"Capacity of the Storage"`
MediumType string `help:"Medium type, either ssd or rotate" choices:"ssd|rotate"`
StorageType string `help:"Storage type" choices:"local|nas|vsan|rbd|nfs|baremetal"`
MonHost string `help:"Ceph mon_host config"`
Key string `help:"Ceph key config"`
Pool string `help:"Ceph Poll Name"`
NfsHost string `help:"NFS host"`
NfsSharedDir string `help:"NFS shared dir"`
}
R(&StorageCreateOptions{}, "storage-create", "Create a Storage", func(s *mcclient.ClientSession, args *StorageCreateOptions) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.NAME), "name")
params.Add(jsonutils.NewString(args.ZONE), "zone")
params.Add(jsonutils.NewInt(args.Capacity), "capacity")
params.Add(jsonutils.NewString(args.StorageType), "storage_type")
params.Add(jsonutils.NewString(args.MediumType), "medium_type")
@@ -120,6 +124,12 @@ func init() {
params.Add(jsonutils.NewString(args.MonHost), "rbd_mon_host")
params.Add(jsonutils.NewString(args.Key), "rbd_key")
params.Add(jsonutils.NewString(args.Pool), "rbd_pool")
} else if args.StorageType == "nfs" {
if len(args.NfsHost) == 0 || len(args.NfsSharedDir) == 0 {
return fmt.Errorf("Storage type nfs missing conf host or shared dir")
}
params.Add(jsonutils.NewString(args.NfsHost), "nfs_host")
params.Add(jsonutils.NewString(args.NfsSharedDir), "nfs_shared_dir")
}
storage, err := modules.Storages.Create(s, params)
if err != nil {
@@ -168,6 +178,24 @@ func init() {
return nil
})
R(&StorageShowOptions{}, "storage-online", "Online a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error {
result, err := modules.Storages.PerformAction(s, args.ID, "online", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&StorageShowOptions{}, "storage-offline", "Offline a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error {
result, err := modules.Storages.PerformAction(s, args.ID, "offline", nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type StorageCacheImageActionOptions struct {
ID string `help:"ID or name of storage"`
IMAGE string `help:"ID or name of image"`
+32 -1
View File
@@ -2,15 +2,17 @@ package shell
import (
"fmt"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type VersionOptions struct {
SERVICE string `help:"Service type"`
}
R(&VersionOptions{}, "version-show", "Show version of a backend service", func(s *mcclient.ClientSession, args *VersionOptions) error {
R(&VersionOptions{}, "version-show", "query backend service for its version", func(s *mcclient.ClientSession, args *VersionOptions) error {
body, err := modules.GetVersion(s, args.SERVICE)
if err != nil {
return err
@@ -18,4 +20,33 @@ func init() {
fmt.Println(body)
return nil
})
R(&options.VersionListOptions{}, "yunionagent-version-list", "show versions of backend services", func(s *mcclient.ClientSession, opts *options.VersionListOptions) error {
if len(opts.Region) == 0 {
opts.Region = s.GetRegion()
}
params, err := options.StructToParams(opts)
if err != nil {
return err
}
result, err := modules.Version.List(s, params)
if err != nil {
return err
}
printList(result, []string{})
return nil
})
R(&options.VersionGetOptions{}, "yunionagent-version-show", "Show service version", func(s *mcclient.ClientSession, opts *options.VersionGetOptions) error {
result, err := modules.Version.Get(s, opts.Service, nil)
if err != nil {
return err
}
ver, err := result.GetString()
if err != nil {
return err
}
fmt.Printf("%s\n", ver)
return nil
})
}
+2
View File
@@ -304,6 +304,8 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
fmt.Sprintf("No request key: %s", manager.Keyword()))
return
}
} else {
data = jsonutils.NewDict()
}
result, err := manager.Delete(ctx, params["<resid>"], mergeQueryParams(params, query, "<resid>"), data)
if err != nil {
+18 -7
View File
@@ -27,11 +27,16 @@ const (
ACT_ATTACH = "attach"
ACT_DETACH = "detach"
ACT_UPDATE_STATUS = "updatestatus"
ACT_START_CREATE_BACKUP = "start_create_backup"
ACT_CREATE_BACKUP = "create_backup"
ACT_CREATE_BACKUP_FAILED = "create_backup_failed"
ACT_STARTING = "starting"
ACT_START = "start"
ACT_START_FAIL = "start_fail"
ACT_UPDATE_STATUS = "updatestatus"
ACT_STARTING = "starting"
ACT_START = "start"
ACT_START_FAIL = "start_fail"
ACT_BACKUP_START = "backup_start"
ACT_BACKUP_START_FAILED = "backup_start_fail"
ACT_STOPPING = "stopping"
ACT_STOP = "stop"
@@ -49,6 +54,9 @@ const (
ACT_SAVE = "save"
ACT_SAVE_FAIL = "save_fail"
ACT_SWITCHED = "switched"
ACT_SWITCH_FAILED = "switch_failed"
ACT_SNAPSHOTING = "snapshoting"
ACT_SNAPSHOT_STREAM = "snapshot_stream"
ACT_SNAPSHOT_DONE = "snapshot"
@@ -63,9 +71,12 @@ const (
ACT_DISK_CLEAN_UP_SNAPSHOTS = "disk_clean_up_snapshots"
ACT_DISK_CLEAN_UP_SNAPSHOTS_FAIL = "disk_clean_up_snapshots_fail"
ACT_ALLOCATING = "allocating"
ACT_ALLOCATE = "allocate"
ACT_ALLOCATE_FAIL = "alloc_fail"
ACT_ALLOCATING = "allocating"
ACT_BACKUP_ALLOCATING = "backup_allocating"
ACT_ALLOCATE = "allocate"
ACT_BACKUP_ALLOCATE = "backup_allocate"
ACT_ALLOCATE_FAIL = "alloc_fail"
ACT_BACKUP_ALLOCATE_FAIL = "backup_alloc_fail"
ACT_DELOCATING = "delocating"
ACT_DELOCATE = "delocate"
+19
View File
@@ -226,6 +226,24 @@ type ICloudSecurityGroup interface {
GetVpcId() string
}
type ICloudRouteTable interface {
ICloudResource
GetManagerId() string
GetDescription() string
GetRegionId() string
GetVpcId() string
GetType() string
GetIRoutes() ([]ICloudRoute, error)
}
type ICloudRoute interface {
GetType() string
GetCidr() string
GetNextHopType() string
GetNextHop() string
}
type ICloudDisk interface {
ICloudResource
IBillingResource
@@ -271,6 +289,7 @@ type ICloudVpc interface {
// GetStatus() string
GetIWires() ([]ICloudWire, error)
GetISecurityGroups() ([]ICloudSecurityGroup, error)
GetIRouteTables() ([]ICloudRouteTable, error)
GetManagerId() string
+5 -2
View File
@@ -175,8 +175,11 @@ func (self *SBaremetalGuestDriver) RequestStartOnHost(ctx context.Context, guest
return host.BaremetalSyncRequest(ctx, "POST", url, headers, config)
}
func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
host := guest.GetHost()
func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest,
host *models.SHost, task taskman.ITask) error {
if host == nil {
host = guest.GetHost()
}
guestStatus, _ := task.GetParams().GetString("guest_status")
overridePendingDelete := jsonutils.QueryBoolean(task.GetParams(), "override_pending_delete", false)
purge := jsonutils.QueryBoolean(task.GetParams(), "purge", false)
+4
View File
@@ -184,6 +184,10 @@ func (self *SBaseGuestDriver) RequestReloadDiskSnapshot(ctx context.Context, gue
return fmt.Errorf("Not Implement")
}
func (self *SBaseGuestDriver) RequestSyncToBackup(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
return fmt.Errorf("Not Implement")
}
func (self *SBaseGuestDriver) getTaskRequestHeader(task taskman.ITask) http.Header {
header := http.Header{}
header.Set(mcclient.AUTH_TOKEN, task.GetUserCred().GetTokenString())
+1 -1
View File
@@ -87,7 +87,7 @@ func (self *SContainerDriver) OnGuestDeployTaskDataReceived(ctx context.Context,
return nil
}
func (self *SContainerDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
func (self *SContainerDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
// do nothing, call next stage
task.ScheduleRun(nil)
return nil
+14 -5
View File
@@ -164,7 +164,7 @@ func (self *SKVMGuestDriver) RequestUndeployGuestOnHost(ctx context.Context, gue
body := jsonutils.NewDict()
// XXXXXXXX
if guest.HostId != host.Id {
if guest.HostId != host.Id && guest.BackupHostId != host.Id {
body.Set("migrated", jsonutils.JSONTrue)
}
_, res, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "DELETE", url, header, body, false)
@@ -283,10 +283,6 @@ func (self *SKVMGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *mode
return nil
}
func (self *SKVMGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error {
return disk.StartDiskDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), isPurge)
}
func (self *SKVMGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
desc := guest.GetDriver().GetJsonDescAtHost(ctx, guest, host)
body := jsonutils.NewDict()
@@ -324,3 +320,16 @@ func (self *SKVMGuestDriver) RequestRebuildRootDisk(ctx context.Context, guest *
subtask.ScheduleRun(nil)
return nil
}
func (self *SKVMGuestDriver) RequestSyncToBackup(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
body := jsonutils.NewDict()
body.Set("backup_nbd_server_uri", jsonutils.NewString(guest.GetMetadata("backup_nbd_server_uri", task.GetUserCred())))
host := guest.GetHost()
url := fmt.Sprintf("%s/server/%s/drive-mirror", host.ManagerUri, guest.Id)
header := self.getTaskRequestHeader(task)
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
if err != nil {
return err
}
return nil
}
@@ -271,10 +271,6 @@ func (self *SManagedVirtualizedGuestDriver) DoGuestCreateDisksTask(ctx context.C
return nil
}
func (self *SManagedVirtualizedGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error {
return disk.StartDiskDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), isPurge)
}
type SManagedVMChangeConfig struct {
InstanceId string
Cpu int
+1 -2
View File
@@ -9,7 +9,6 @@ import (
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/pkg/util/sysutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -74,7 +73,7 @@ func (self *SQcloudGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *m
if !utils.IsInStringArray(guest.Status, []string{models.VM_READY, models.VM_RUNNING}) {
return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status)
}
if utils.IsInStringArray(storage.StorageType, []string{sysutils.STORAGE_LOCAL_BASIC, sysutils.STORAGE_LOCAL_SSD}) {
if utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_LOCAL_BASIC, models.STORAGE_LOCAL_SSD}) {
return fmt.Errorf("Cannot resize %s disk", storage.StorageType)
}
return nil
+10 -2
View File
@@ -143,6 +143,11 @@ func (self *SVirtualizedGuestDriver) StartGuestRestartTask(guest *models.SGuest,
return nil
}
func (self *SVirtualizedGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error {
return disk.StartDiskDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), isPurge,
jsonutils.QueryBoolean(task.GetParams(), "override_pending_delete", false))
}
func (self *SVirtualizedGuestDriver) OnGuestDeployTaskComplete(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
if jsonutils.QueryBoolean(task.GetParams(), "restart", false) {
task.SetStage("OnDeployStartGuestComplete", nil)
@@ -161,8 +166,11 @@ func (self *SVirtualizedGuestDriver) StartGuestSyncstatusTask(guest *models.SGue
return nil
}
func (self *SVirtualizedGuestDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
host := guest.GetHost()
func (self *SVirtualizedGuestDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest,
host *models.SHost, task taskman.ITask) error {
if host == nil {
host = guest.GetHost()
}
if host != nil && host.Enabled && host.HostStatus == models.HOST_ONLINE {
return guest.StartGuestStopTask(ctx, task.GetUserCred(), true, task.GetTaskId())
}
+3
View File
@@ -72,9 +72,12 @@ func InitHandlers(app *appsrv.Application) {
models.LoadbalancerCertificateManager,
models.LoadbalancerAclManager,
models.LoadbalancerAgentManager,
models.RouteTableManager,
models.SchedpolicyManager,
models.DynamicschedtagManager,
models.ServerSkuManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
+16
View File
@@ -188,6 +188,22 @@ func (self *SAwsHostDriver) RequestResizeDiskOnHost(host *models.SHost, storage
return nil
}
func (self *SAwsHostDriver) RequestResetDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error {
iDisk, err := disk.GetIDisk()
if err != nil {
return err
}
snapshotId, err := params.GetString("snapshot_id")
if err != nil {
return err
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
err := iDisk.Reset(snapshotId)
return nil, err
})
return nil
}
func init() {
driver := SAwsHostDriver{}
models.RegisterHostDriver(&driver)
+1
View File
@@ -147,6 +147,7 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use
if err == cloudprovider.ErrNoSuchProvder {
return nil, httperrors.NewResourceNotFoundError("no such provider %s", provider)
}
log.Debugf("ValidateCreateData %s", err.Error())
return nil, httperrors.NewInputParameterError("invalid cloud account info")
}
+1 -1
View File
@@ -412,7 +412,7 @@ func (self *SCloudprovider) SaveSysInfo(info jsonutils.JSONObject) {
func (manager *SCloudproviderManager) FetchCloudproviderById(providerId string) *SCloudprovider {
providerObj, err := manager.FetchById(providerId)
if err != nil {
log.Errorf("%s", err)
log.Errorf("fetch cloud provider %s: %s", providerId, err)
return nil
}
return providerObj.(*SCloudprovider)
+9 -7
View File
@@ -19,6 +19,8 @@ import (
const (
CLOUD_REGION_STATUS_INSERVER = "inservice"
CLOUD_REGION_STATUS_OUTOFSERVICE = "outofservice"
DEFAULT_REGION_ID = "default"
)
type SCloudregionManager struct {
@@ -64,7 +66,7 @@ func (self *SCloudregion) ValidateDeleteCondition(ctx context.Context) error {
if self.GetZoneCount() > 0 || self.GetVpcCount() > 0 {
return httperrors.NewNotEmptyError("not empty cloud region")
}
if self.Id == "default" {
if self.Id == DEFAULT_REGION_ID {
return httperrors.NewProtectedResourceError("not allow to delete default cloud region")
}
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
@@ -72,7 +74,7 @@ func (self *SCloudregion) ValidateDeleteCondition(ctx context.Context) error {
func (self *SCloudregion) GetZoneCount() int {
zones := ZoneManager.Query()
if self.Id == "default" {
if self.Id == DEFAULT_REGION_ID {
return zones.Filter(sqlchemy.OR(sqlchemy.IsNull(zones.Field("cloudregion_id")),
sqlchemy.IsEmpty(zones.Field("cloudregion_id")),
sqlchemy.Equals(zones.Field("cloudregion_id"), self.Id))).Count()
@@ -83,7 +85,7 @@ func (self *SCloudregion) GetZoneCount() int {
func (self *SCloudregion) GetGuestCount(increment bool) int {
zoneTable := ZoneManager.Query("id")
if self.Id == "default" {
if self.Id == DEFAULT_REGION_ID {
zoneTable = zoneTable.Filter(sqlchemy.OR(sqlchemy.IsNull(zoneTable.Field("cloudregion_id")),
sqlchemy.IsEmpty(zoneTable.Field("cloudregion_id")),
sqlchemy.Equals(zoneTable.Field("cloudregion_id"), self.Id)))
@@ -102,7 +104,7 @@ func (self *SCloudregion) GetGuestCount(increment bool) int {
func (self *SCloudregion) GetVpcCount() int {
vpcs := VpcManager.Query()
if self.Id == "default" {
if self.Id == DEFAULT_REGION_ID {
return vpcs.Filter(sqlchemy.OR(sqlchemy.IsNull(vpcs.Field("cloudregion_id")),
sqlchemy.IsEmpty(vpcs.Field("cloudregion_id")),
sqlchemy.Equals(vpcs.Field("cloudregion_id"), self.Id))).Count()
@@ -286,7 +288,7 @@ func (self *SCloudregion) PerformDefaultVpc(ctx context.Context, userCred mcclie
func (manager *SCloudregionManager) FetchRegionById(id string) *SCloudregion {
obj, err := manager.FetchById(id)
if err != nil {
log.Errorf("%s", err)
log.Errorf("region %s %s", id, err)
return nil
}
return obj.(*SCloudregion)
@@ -294,11 +296,11 @@ func (manager *SCloudregionManager) FetchRegionById(id string) *SCloudregion {
func (manager *SCloudregionManager) InitializeData() error {
// check if default region exists
_, err := manager.FetchById("default")
_, err := manager.FetchById(DEFAULT_REGION_ID)
if err != nil {
if err == sql.ErrNoRows {
defRegion := SCloudregion{}
defRegion.Id = "default"
defRegion.Id = DEFAULT_REGION_ID
defRegion.Name = "Default"
defRegion.Enabled = true
defRegion.Description = "Default Region"
+48 -19
View File
@@ -15,7 +15,6 @@ import (
"yunion.io/x/pkg/util/fileutils"
"yunion.io/x/pkg/util/osprofile"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/sysutils"
"yunion.io/x/pkg/util/timeutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -32,18 +31,20 @@ import (
)
const (
DISK_INIT = "init"
DISK_REBUILD = "rebuild"
DISK_ALLOC_FAILED = "alloc_failed"
DISK_STARTALLOC = "start_alloc"
DISK_ALLOCATING = "allocating"
DISK_READY = "ready"
DISK_RESET = "reset"
DISK_DEALLOC = "deallocating"
DISK_DEALLOC_FAILED = "dealloc_failed"
DISK_UNKNOWN = "unknown"
DISK_DETACHING = "detaching"
DISK_ATTACHING = "attaching"
DISK_INIT = "init"
DISK_REBUILD = "rebuild"
DISK_ALLOC_FAILED = "alloc_failed"
DISK_STARTALLOC = "start_alloc"
DISK_BACKUP_STARTALLOC = "backup_start_alloc"
DISK_BACKUP_ALLOC_FAILED = "backup_alloc_failed"
DISK_ALLOCATING = "allocating"
DISK_READY = "ready"
DISK_RESET = "reset"
DISK_DEALLOC = "deallocating"
DISK_DEALLOC_FAILED = "dealloc_failed"
DISK_UNKNOWN = "unknown"
DISK_DETACHING = "detaching"
DISK_ATTACHING = "attaching"
DISK_START_SAVE = "start_save"
DISK_SAVING = "saving"
@@ -93,7 +94,8 @@ type SDisk struct {
AutoDelete bool `nullable:"false" default:"false" get:"user" update:"user"` // Column(Boolean, nullable=False, default=False)
StorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin"` // Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=True)
StorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"required"` // Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=False)
BackupStorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"required"`
// # backing template id and type
TemplateId string `width:"256" charset:"ascii" nullable:"true" list:"user"` // Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=True)
@@ -725,6 +727,11 @@ func (self *SDisk) GetPathAtHost(host *SHost) string {
hostStorage := host.GetHoststorageOfId(self.StorageId)
if hostStorage != nil {
return path.Join(hostStorage.MountPoint, self.Id)
} else if len(self.BackupStorageId) > 0 {
hostStorage = host.GetHoststorageOfId(self.BackupStorageId)
if hostStorage != nil {
return path.Join(hostStorage.MountPoint, self.Id)
}
}
return ""
}
@@ -1022,7 +1029,7 @@ func parseDiskInfo(ctx context.Context, userCred mcclient.TokenCredential, info
diskConfig.Mountpoint = p
} else if p == "autoextend" {
diskConfig.Size = -1
} else if utils.IsInStringArray(p, sysutils.STORAGE_TYPES) {
} else if utils.IsInStringArray(p, STORAGE_TYPES) {
diskConfig.Backend = p
} else if len(p) > 0 {
if userCred == nil {
@@ -1148,11 +1155,12 @@ func (self *SDisk) PerformPurge(ctx context.Context, userCred mcclient.TokenCred
if err != nil {
return nil, err
}
return nil, self.StartDiskDeleteTask(ctx, userCred, "", true)
return nil, self.StartDiskDeleteTask(ctx, userCred, "", true, false)
}
func (self *SDisk) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartDiskDeleteTask(ctx, userCred, "", false)
return self.StartDiskDeleteTask(ctx, userCred, "", false,
jsonutils.QueryBoolean(query, "override_pending_delete", false))
}
func (self *SDisk) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict {
@@ -1209,11 +1217,14 @@ func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.To
return nil
}
func (self *SDisk) StartDiskDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, isPurge bool) error {
func (self *SDisk) StartDiskDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, isPurge, overridePendingDelete bool) error {
params := jsonutils.NewDict()
if isPurge {
params.Add(jsonutils.JSONTrue, "purge")
}
if overridePendingDelete {
params.Add(jsonutils.JSONTrue, "override_pending_delete")
}
task, err := taskman.TaskManager.NewTask(ctx, "DiskDeleteTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
log.Errorf("%s", err)
@@ -1250,6 +1261,14 @@ func (self *SDisk) SetDiskReady(ctx context.Context, userCred mcclient.TokenCred
}
}
func (self *SDisk) SwitchToBackup() error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.StorageId, self.BackupStorageId = self.BackupStorageId, self.StorageId
return nil
})
return err
}
func (self *SDisk) ClearHostSchedCache() error {
storage := self.GetStorage()
hosts := storage.GetAllAttachingHosts()
@@ -1349,7 +1368,7 @@ func (manager *SDiskManager) CleanPendingDeleteDisks(ctx context.Context, userCr
return
}
for i := 0; i < len(disks); i += 1 {
disks[i].StartDiskDeleteTask(ctx, userCred, "", false)
disks[i].StartDiskDeleteTask(ctx, userCred, "", false, false)
}
}
@@ -1392,3 +1411,13 @@ func (manager *SDiskManager) AutoDiskSnapshot(ctx context.Context, userCred mccl
guests[0].StartDiskSnapshot(ctx, userCred, disk.Id, snap.Id)
}
}
func (disk *SDisk) StratCreateBackupTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
if task, err := taskman.TaskManager.NewTask(ctx, "DiskCreateBackupTask", disk, userCred, nil, parentTaskId, "", nil); err != nil {
log.Errorf(err.Error())
return err
} else {
task.ScheduleRun(nil)
}
return nil
}
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -146,7 +146,8 @@ func (self *SGuestdisk) GetJsonDescAtHost(host *SHost) jsonutils.JSONObject {
}
}
storage := disk.GetStorage()
if host.HostType == HOST_TYPE_HYPERVISOR && disk.IsLocal() || (storage != nil && storage.StorageType == STORAGE_RBD) {
// XXX ???
if host.HostType == HOST_TYPE_HYPERVISOR {
desc.Add(jsonutils.NewString(disk.StorageId), "storage_id")
localpath := disk.GetPathAtHost(host)
if len(localpath) == 0 {
+2 -1
View File
@@ -67,7 +67,7 @@ type IGuestDriver interface {
StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, params *jsonutils.JSONDict, parentTaskId string) error
RequestStopGuestForDelete(ctx context.Context, guest *SGuest, task taskman.ITask) error
RequestStopGuestForDelete(ctx context.Context, guest *SGuest, host *SHost, task taskman.ITask) error
RequestDetachDisksFromGuestForDelete(ctx context.Context, guest *SGuest, task taskman.ITask) error
@@ -110,6 +110,7 @@ type IGuestDriver interface {
RequestDiskSnapshot(ctx context.Context, guest *SGuest, task taskman.ITask, snapshotId, diskId string) error
RequestDeleteSnapshot(ctx context.Context, guest *SGuest, task taskman.ITask, params *jsonutils.JSONDict) error
RequestReloadDiskSnapshot(ctx context.Context, guest *SGuest, task taskman.ITask, params *jsonutils.JSONDict) error
RequestSyncToBackup(ctx context.Context, guest *SGuest, task taskman.ITask) error
}
var guestDrivers map[string]IGuestDriver
+110 -1653
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -17,7 +17,6 @@ import (
"yunion.io/x/pkg/util/fileutils"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/sysutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -467,7 +466,7 @@ func (self *SHost) GetBaremetalstorage() *SHoststorage {
q := hoststorages.Query()
q = q.Join(storages, sqlchemy.AND(sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id")),
sqlchemy.IsFalse(storages.Field("deleted"))))
q = q.Filter(sqlchemy.Equals(storages.Field("storage_type"), sysutils.STORAGE_BAREMETAL))
q = q.Filter(sqlchemy.Equals(storages.Field("storage_type"), STORAGE_BAREMETAL))
q = q.Filter(sqlchemy.Equals(hoststorages.Field("host_id"), self.Id))
if q.Count() == 1 {
hs := SHoststorage{}
@@ -1703,7 +1702,9 @@ func (self *SHost) getGuestsResource(status string) *SHostGuestResourceUsage {
q := guests.Query(sqlchemy.COUNT("guest_count"),
sqlchemy.SUM("guest_vcpu_count", guests.Field("vcpu_count")),
sqlchemy.SUM("guest_vmem_size", guests.Field("vmem_size")))
q = q.Equals("host_id", self.Id)
cond := sqlchemy.OR(sqlchemy.Equals(q.Field("host_id"), self.Id),
sqlchemy.Equals(q.Field("backup_host_id"), self.Id))
q = q.Filter(cond)
if len(status) > 0 {
q = q.Equals("status", status)
}
+90 -5
View File
@@ -3,12 +3,16 @@ package models
import (
"context"
"fmt"
"net/http"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
)
@@ -97,12 +101,89 @@ func (manager *SHoststorageManager) ValidateCreateData(ctx context.Context, user
return manager.SJointResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
}
func (self *SHoststorage) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SHostJointsBase.PostCreate(ctx, userCred, ownerProjId, query, data)
storage := self.GetStorage()
if !utils.IsInStringArray(storage.StorageType, STORAGE_LOCAL_TYPES) {
host := storage.GetMasterHost()
log.Infof("Attach SharedStorage[%s] on host %s ...", storage.Name, host.Name)
url := fmt.Sprintf("%s/storages/attach", host.ManagerUri)
headers := http.Header{}
headers.Set("X-Auth-Token", userCred.GetTokenString())
body := jsonutils.NewDict()
body.Set("mount_point", jsonutils.NewString(self.MountPoint))
body.Set("name", jsonutils.NewString(storage.Name))
body.Set("storage_id", jsonutils.NewString(storage.Id))
body.Set("storage_conf", storage.StorageConf)
body.Set("storage_type", jsonutils.NewString(storage.StorageType))
if len(storage.StoragecacheId) > 0 {
storagecache := StoragecacheManager.FetchStoragecacheById(storage.StoragecacheId)
if storagecache != nil {
body.Set("imagecache_path", jsonutils.NewString(
storage.GetStorageCachePath(self.MountPoint, storagecache.Path)))
body.Set("storagecache_id", jsonutils.NewString(storagecache.Id))
}
}
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(),
ctx, "POST", url, headers, body, false)
if err != nil {
log.Errorf("Host Storage Post Create Error: %s", err)
// panic(err) ???
}
self.SyncStorageStatus()
}
}
func (self *SHoststorage) PreDelete(ctx context.Context, userCred mcclient.TokenCredential) {
storage := self.GetStorage()
if !utils.IsInStringArray(storage.StorageType, STORAGE_LOCAL_TYPES) {
host := storage.GetMasterHost()
log.Infof("Attach SharedStorage[%s] on host %s ...", storage.Name, host.Name)
url := fmt.Sprintf("%s/storages/detach", host.ManagerUri)
headers := http.Header{}
headers.Set("X-Auth-Token", userCred.GetTokenString())
body := jsonutils.NewDict()
body.Set("mount_point", jsonutils.NewString(self.MountPoint))
body.Set("name", jsonutils.NewString(storage.Name))
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(),
ctx, "POST", url, headers, body, false)
if err != nil {
log.Errorf("Host Storage Post Create Error: %s", err)
// panic(err) ???
}
self.SyncStorageStatus()
}
}
func (self *SHoststorage) SyncStorageStatus() {
storage := self.GetStorage()
hostQuery := HostManager.Query().SubQuery()
count := HoststorageManager.Query().Join(hostQuery,
sqlchemy.AND(sqlchemy.Equals(hostQuery.Field("id"), self.HostId),
sqlchemy.Equals(hostQuery.Field("host_status"), "online"))).Count()
status := storage.Status
if count >= 1 {
status = STORAGE_ONLINE
} else {
status = STORAGE_OFFLINE
}
if status != storage.Status {
storage.GetModelManager().TableSpec().Update(storage, func() error {
storage.Status = status
return nil
})
}
}
func (self *SHoststorage) getExtraDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict {
host := self.GetHost()
extra.Add(jsonutils.NewString(host.Name), "host")
storage := self.GetStorage()
extra.Add(jsonutils.NewString(storage.Name), "storage")
extra.Add(jsonutils.NewInt(int64(storage.Capacity)), "capacity")
if storage.StorageConf != nil {
extra.Set("storage_conf", storage.StorageConf)
}
used := storage.GetUsedCapacity(tristate.True)
wasted := storage.GetUsedCapacity(tristate.False)
extra.Add(jsonutils.NewInt(int64(used)), "used_capacity")
@@ -110,12 +191,16 @@ func (self *SHoststorage) getExtraDetails(extra *jsonutils.JSONDict) *jsonutils.
extra.Add(jsonutils.NewInt(int64(storage.Capacity-used-wasted)), "free_capacity")
extra.Add(jsonutils.NewString(storage.StorageType), "storage_type")
extra.Add(jsonutils.NewString(storage.MediumType), "medium_type")
if storage.Enabled {
extra.Add(jsonutils.JSONTrue, "enabled")
} else {
extra.Add(jsonutils.JSONFalse, "enabled")
}
extra.Add(jsonutils.NewBool(storage.Enabled), "enabled")
extra.Add(jsonutils.NewFloat(float64(storage.GetOvercommitBound())), "cmtbound")
extra.Add(jsonutils.NewInt(int64(self.GetGuestDiskCount())), "guest_disk_count")
if len(storage.StoragecacheId) > 0 {
storagecache := StoragecacheManager.FetchStoragecacheById(storage.StoragecacheId)
if storagecache != nil {
extra.Set("imagecache_path", jsonutils.NewString(storage.GetStorageCachePath(self.MountPoint, storagecache.Path)))
extra.Set("storagecache_id", jsonutils.NewString(storagecache.Id))
}
}
return extra
}
+376
View File
@@ -0,0 +1,376 @@
package models
import (
"context"
"net"
"reflect"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SRoute struct {
Type string
Cidr string
NextHopType string
NextHopId string
}
func (route *SRoute) Validate(data *jsonutils.JSONDict) error {
if strings.Index(route.Cidr, "/") > 0 {
_, ipNet, err := net.ParseCIDR(route.Cidr)
if err != nil {
return err
}
// normalize from 192.168.1.3/24 to 192.168.1.0/24
route.Cidr = ipNet.String()
} else {
ip := net.ParseIP(route.Cidr).To4()
if ip == nil {
return httperrors.NewInputParameterError("invalid addr %s", route.Cidr)
}
}
return nil
}
type SRoutes []*SRoute
func (routes *SRoutes) String() string {
return jsonutils.Marshal(routes).String()
}
func (routes *SRoutes) IsZero() bool {
if len([]*SRoute(*routes)) == 0 {
return true
}
return false
}
func (routes *SRoutes) Validate(data *jsonutils.JSONDict) error {
found := map[string]bool{}
for _, route := range *routes {
if err := route.Validate(data); err != nil {
return err
}
if _, ok := found[route.Cidr]; ok {
// error so that the user has a chance to deal with comments
return httperrors.NewInputParameterError("duplicate route cidr %s", route.Cidr)
}
// TODO aliyun: check overlap with System type route
found[route.Cidr] = true
}
return nil
}
type SRouteTableManager struct {
db.SVirtualResourceBaseManager
}
var RouteTableManager *SRouteTableManager
func init() {
gotypes.RegisterSerializable(reflect.TypeOf(&SRoutes{}), func() gotypes.ISerializable {
return &SRoutes{}
})
RouteTableManager = &SRouteTableManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SRouteTable{},
"route_tables_tbl",
"route_table",
"route_tables",
),
}
}
type SRouteTable struct {
db.SVirtualResourceBase
SManagedResourceBase
VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
Type string `width:"16" charset:"ascii" nullable:"false" list:"user"`
Routes *SRoutes `list:"user" update:"user" create:"required"`
}
func (man *SRouteTableManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
userProjId := userCred.GetProjectId()
data := query.(*jsonutils.JSONDict)
for _, key := range []string{"vpc", "cloudregion"} {
v := validators.NewModelIdOrNameValidator(key, key, userProjId)
v.Optional(true)
q, err = v.QueryFilter(q, data)
if err != nil {
return nil, err
}
}
return q, nil
}
func (man *SRouteTableManager) validateRoutes(data *jsonutils.JSONDict, update bool) (*jsonutils.JSONDict, error) {
routes := SRoutes{}
routesV := validators.NewStructValidator("routes", &routes)
if update {
routesV.Optional(true)
}
err := routesV.Validate(data)
if err != nil {
return nil, err
}
return data, nil
}
func (man *SRouteTableManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
data, err := man.validateRoutes(data, false)
if err != nil {
return nil, err
}
vpcV := validators.NewModelIdOrNameValidator("vpc", "vpc", ownerProjId)
if err := vpcV.Validate(data); err != nil {
return nil, err
}
vpc := vpcV.Model.(*SVpc)
cloudregion := vpc.GetRegion()
if cloudregion == nil {
return nil, httperrors.NewConflictError("failed fetching cloudregion of vpc %s(%s)", vpc.Name, vpc.Id)
}
data.Set("cloudregion_id", jsonutils.NewString(cloudregion.Id))
return man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
}
func (rt *SRouteTable) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
data, err := RouteTableManager.validateRoutes(data, true)
if err != nil {
return nil, err
}
return rt.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
}
func (rt *SRouteTable) AllowPerformAddRoutes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) bool {
return rt.IsOwner(userCred) || userCred.IsSystemAdmin()
}
func (rt *SRouteTable) AllowPerformDelRoutes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) bool {
return rt.AllowPerformAddRoutes(ctx, userCred, query, data)
}
// PerformAddRoutes patches acl entries by adding then deleting the specified acls.
// This is intended mainly for command line operations.
func (rt *SRouteTable) PerformAddRoutes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
routes := gotypes.DeepCopy(rt.Routes).(SRoutes)
{
adds := SRoutes{}
addsV := validators.NewStructValidator("routes", &adds)
addsV.Optional(true)
err := addsV.Validate(data)
if err != nil {
return nil, err
}
for _, add := range adds {
found := false
for _, route := range routes {
if route.Cidr == add.Cidr {
found = true
break
}
}
if !found {
routes = append(routes, add)
}
}
}
_, err := rt.GetModelManager().TableSpec().Update(rt, func() error {
rt.Routes = &routes
return nil
})
if err != nil {
return nil, err
}
return nil, nil
}
func (rt *SRouteTable) PerformDelRoutes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
routes := gotypes.DeepCopy(rt.Routes).(SRoutes)
{
cidrs := []string{}
err := data.Unmarshal(&cidrs, "cidrs")
if err != nil {
return nil, httperrors.NewInputParameterError("unmarshaling cidrs failed: %s", err)
}
for _, cidr := range cidrs {
for i := len(routes) - 1; i >= 0; i-- {
route := routes[i]
if route.Type == "system" {
continue
}
if route.Cidr == cidr {
routes = append(routes[:i], routes[i+1:]...)
break
}
}
}
}
_, err := rt.GetModelManager().TableSpec().Update(rt, func() error {
rt.Routes = &routes
return nil
})
if err != nil {
return nil, err
}
return nil, nil
}
func (rt *SRouteTable) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := rt.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query)
vpcM, err := VpcManager.FetchById(rt.VpcId)
if err != nil {
log.Errorf("route table %s(%s): fetch vpc (%s) error: %s",
rt.Name, rt.Id, rt.VpcId, err)
return extra
}
cloudregionM, err := CloudregionManager.FetchById(rt.CloudregionId)
if err != nil {
log.Errorf("route table %s(%s): fetch cloud region (%s) error: %s",
rt.Name, rt.Id, rt.CloudregionId, err)
return extra
}
extra.Set("vpc", jsonutils.NewString(vpcM.GetName()))
extra.Set("cloudregion", jsonutils.NewString(cloudregionM.GetName()))
return extra
}
func (rt *SRouteTable) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := rt.GetCustomizeColumns(ctx, userCred, query)
extra = rt.SManagedResourceBase.getExtraDetails(ctx, extra)
return extra
}
func (man *SRouteTableManager) SyncRouteTables(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTables []cloudprovider.ICloudRouteTable) ([]SRouteTable, []cloudprovider.ICloudRouteTable, compare.SyncResult) {
localRouteTables := make([]SRouteTable, 0)
remoteRouteTables := make([]cloudprovider.ICloudRouteTable, 0)
syncResult := compare.SyncResult{}
dbRouteTables := []SRouteTable{}
if err := db.FetchModelObjects(man, man.Query(), &dbRouteTables); err != nil {
syncResult.Error(err)
return nil, nil, syncResult
}
removed := make([]SRouteTable, 0)
commondb := make([]SRouteTable, 0)
commonext := make([]cloudprovider.ICloudRouteTable, 0)
added := make([]cloudprovider.ICloudRouteTable, 0)
if false {
for _, rt := range cloudRouteTables {
log.Errorf("%s, %s", rt.GetName(), rt.GetGlobalId())
routes, err := rt.GetIRoutes()
if err != nil {
log.Errorf("get routes err: %s", err)
continue
}
for i, route := range routes {
log.Errorf("route %d: %#v ", i, route)
}
}
}
if err := compare.CompareSets(dbRouteTables, cloudRouteTables, &removed, &commondb, &commonext, &added); err != nil {
syncResult.Error(err)
return nil, nil, syncResult
}
for i := 0; i < len(commondb); i += 1 {
err := commondb[i].SyncWithCloudRouteTable(userCred, vpc, commonext[i])
if err != nil {
syncResult.UpdateError(err)
continue
}
localRouteTables = append(localRouteTables, commondb[i])
remoteRouteTables = append(remoteRouteTables, commonext[i])
syncResult.Update()
}
for i := 0; i < len(added); i += 1 {
routeTableNew, err := man.insertFromCloud(userCred, vpc, added[i])
if err != nil {
syncResult.AddError(err)
continue
}
localRouteTables = append(localRouteTables, *routeTableNew)
remoteRouteTables = append(remoteRouteTables, added[i])
syncResult.Add()
}
return localRouteTables, remoteRouteTables, syncResult
}
func (man *SRouteTableManager) newRouteTableFromCloud(userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTable cloudprovider.ICloudRouteTable) (*SRouteTable, error) {
routes := []*SRoute{}
{
cloudRoutes, err := cloudRouteTable.GetIRoutes()
if err != nil {
return nil, err
}
for _, cloudRoute := range cloudRoutes {
route := &SRoute{
Type: cloudRoute.GetType(),
Cidr: cloudRoute.GetCidr(),
NextHopType: cloudRoute.GetNextHopType(),
NextHopId: cloudRoute.GetNextHop(),
}
routes = append(routes, route)
}
}
routeTable := &SRouteTable{
CloudregionId: vpc.CloudregionId,
VpcId: vpc.Id,
Type: cloudRouteTable.GetType(),
Routes: (*SRoutes)(&routes),
}
routeTable.Name = cloudRouteTable.GetName()
routeTable.ManagerId = vpc.ManagerId
routeTable.ExternalId = cloudRouteTable.GetGlobalId()
routeTable.Description = cloudRouteTable.GetDescription()
routeTable.ProjectId = userCred.GetProjectId()
routeTable.SetModelManager(man)
return routeTable, nil
}
func (man *SRouteTableManager) insertFromCloud(userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTable cloudprovider.ICloudRouteTable) (*SRouteTable, error) {
routeTable, err := man.newRouteTableFromCloud(userCred, vpc, cloudRouteTable)
if err != nil {
return nil, err
}
if err := man.TableSpec().Insert(routeTable); err != nil {
return nil, err
}
return routeTable, nil
}
func (self *SRouteTable) SyncWithCloudRouteTable(userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTable cloudprovider.ICloudRouteTable) error {
man := self.GetModelManager().(*SRouteTableManager)
routeTable, err := man.newRouteTableFromCloud(userCred, vpc, cloudRouteTable)
if err != nil {
return err
}
_, err = man.TableSpec().Update(self, func() error {
self.CloudregionId = routeTable.CloudregionId
self.VpcId = vpc.Id
self.Type = routeTable.Type
self.Routes = routeTable.Routes
return nil
})
if err != nil {
return err
}
return nil
}
+132
View File
@@ -0,0 +1,132 @@
package models
import (
"context"
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
const (
SkuCategoryGeneralPurpose = "general_purpose" // 通用型
SkuCategoryBurstable = "burstable" // 突发性能型
SkuCategoryComputeOptimized = "compute_optimized" // 计算优化型
SkuCategoryMemoryOptimized = "memory_optimized" // 内存优化型
SkuCategoryStorageIOOptimized = "storage_optimized" // 存储IO优化型
SkuCategoryHardwareAccelerated = "hardware_accelerated" // 硬件加速型
SkuCategoryHighStorage = "high_storage" // 高存储型
SkuCategoryHighMemory = "high_memory" // 高内存型
)
type SServerSkuManager struct {
db.SStandaloneResourceBaseManager
SInfrastructureManager
}
var ServerSkuManager *SServerSkuManager
func init() {
ServerSkuManager = &SServerSkuManager{
SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager(
SServerSku{},
"serverskus_tbl",
"serversku",
"serverskus",
),
}
ServerSkuManager.NameRequireAscii = false
}
type SServerSku struct {
db.SStandaloneResourceBase
SInfrastructure
// SkuId string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"admin_required"`
SkuFamily string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
SkuCategory string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
CpuCoreCount int `nullable:"false" list:"user" create:"admin_required" update:"admin"`
MemorySizeMB int `nullable:"false" list:"user" create:"admin_required" update:"admin"`
SysDiskResizable bool `default:"true" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
SysDiskMaxSizeGB int `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
AttachedDiskType string `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
AttachedDiskSizeGB int `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
AttachedDiskCount int `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
MaxDataDiskCount int `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
NicType string `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
MaxNicCount int `default:"1" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
GpuAttachable bool `default:"true" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
GpuSpec string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
GpuCount int `nullable:"false" list:"user" create:"admin_optional" update:"admin"`
CloudregionId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"`
ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
}
func (self *SServerSkuManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return true
}
func (self *SServerSku) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return true
}
func (self *SServerSkuManager) ValidateCreateData(ctx context.Context,
userCred mcclient.TokenCredential,
ownerProjId string,
query jsonutils.JSONObject,
data *jsonutils.JSONDict,
) (*jsonutils.JSONDict, error) {
regionStr := jsonutils.GetAnyString(data, []string{"region", "region_id", "cloudregion", "cloudregion_id"})
if len(regionStr) > 0 {
regionObj, err := CloudregionManager.FetchByIdOrName(userCred, regionStr)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("region %s not found", regionStr)
}
return nil, httperrors.NewGeneralError(err)
}
data.Add(jsonutils.NewString(regionObj.GetId()), "cloudregion_id")
} else {
data.Add(jsonutils.NewString(DEFAULT_REGION_ID), "cloudregion_id")
}
zoneStr := jsonutils.GetAnyString(data, []string{"zone", "zone_id"})
if len(zoneStr) > 0 {
zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zoneStr)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("zone %s not found", zoneStr)
}
return nil, httperrors.NewGeneralError(err)
}
data.Add(jsonutils.NewString(zoneObj.GetId()), "zone_id")
}
return self.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
}
func (self *SServerSku) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
zoneStr := jsonutils.GetAnyString(data, []string{"zone", "zone_id"})
if len(zoneStr) > 0 {
zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zoneStr)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("zone %s not found", zoneStr)
}
return nil, httperrors.NewGeneralError(err)
}
data.Add(jsonutils.NewString(zoneObj.GetId()), "zone_id")
}
return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
}
+17
View File
@@ -284,6 +284,23 @@ func (manager *SStoragecacheManager) ListItemFilter(ctx context.Context, q *sqlc
return q, nil
}
func (manager *SStoragecacheManager) FetchStoragecacheById(storageCacheId string) *SStoragecache {
iStorageCache, _ := manager.FetchById(storageCacheId)
if iStorageCache == nil {
return nil
}
return iStorageCache.(*SStoragecache)
}
func (manager *SStoragecacheManager) GetCachePathById(storageCacheId string) string {
iStorageCache, _ := manager.FetchById(storageCacheId)
if iStorageCache == nil {
return ""
}
sc := iStorageCache.(*SStoragecache)
return sc.Path
}
func (self *SStoragecache) ValidateDeleteCondition(ctx context.Context) error {
if self.getCachedImageCount() > 0 {
return httperrors.NewNotEmptyError("storage cache not empty")
+257 -39
View File
@@ -2,6 +2,10 @@ package models
import (
"context"
"fmt"
"path"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -10,31 +14,51 @@ import (
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/sysutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
)
const (
STORAGE_LOCAL = "local"
STORAGE_BAREMETAL = "baremetal"
STORAGE_SHEEPDOG = "sheepdog"
STORAGE_RBD = "rbd"
STORAGE_DOCKER = "docker"
STORAGE_NAS = "nas"
STORAGE_VSAN = "vsan"
STORAGE_LOCAL = "local"
STORAGE_BAREMETAL = "baremetal"
STORAGE_SHEEPDOG = "sheepdog"
STORAGE_RBD = "rbd"
STORAGE_DOCKER = "docker"
STORAGE_NAS = "nas"
STORAGE_VSAN = "vsan"
STORAGE_NFS = "nfs"
STORAGE_PUBLIC_CLOUD = "cloud"
STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency"
STORAGE_CLOUD_SSD = "cloud_ssd"
STORAGE_EPHEMERAL_SSD = "ephemeral_ssd"
STORAGE_GP2_SSD = "gp2" // aws general purpose ssd
STORAGE_IO1_SSD = "io1" // aws Provisioned IOPS SSD
STORAGE_ST1_HDD = "st1" // aws Throughput Optimized HDD
STORAGE_SC1_SSD = "sc1" // aws Cold HDD
STORAGE_STANDARD_SSD = "standard" // aws Magnetic volumes
STORAGE_CLOUD_ESSD = "cloud_essd" //增强型(Enhanced)SSD 云盘
//Azure hdd and ssd storagetype
STORAGE_STANDARD_GRS = "standard_grs"
STORAGE_STANDARD_LRS = "standard_lrs"
STORAGE_STANDARD_RAGRS = "standard_ragrs"
STORAGE_STANDARD_ZRS = "standard_zrs"
STORAGE_PREMIUM_LRS = "premium_lrs"
// aws storage type
STORAGE_GP2_SSD = "gp2" // aws general purpose ssd
STORAGE_IO1_SSD = "io1" // aws Provisioned IOPS SSD
STORAGE_ST1_HDD = "st1" // aws Throughput Optimized HDD
STORAGE_SC1_SSD = "sc1" // aws Cold HDD
STORAGE_STANDARD_SSD = "standard" // aws Magnetic volumes
// qcloud storage type
// STORAGE_CLOUD_SSD ="cloud_ssd"
STORAGE_LOCAL_BASIC = "local_basic"
STORAGE_LOCAL_SSD = "local_ssd"
STORAGE_CLOUD_BASIC = "cloud_basic"
STORAGE_CLOUD_PERMIUM = "cloud_permium"
)
const (
STORAGE_ENABLED = "enabled"
STORAGE_DISABLED = "disabled"
STORAGE_OFFLINE = "offline"
@@ -47,17 +71,26 @@ const (
var (
DISK_TYPES = []string{DISK_TYPE_ROTATE, DISK_TYPE_SSD, DISK_TYPE_HYBRID}
STORAGE_LOCAL_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS}
STORAGE_LOCAL_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL}
STORAGE_SUPPORT_TYPES = STORAGE_LOCAL_TYPES
STORAGE_ALL_TYPES = []string{
STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG,
STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN,
STORAGE_NFS,
}
STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD}
STORAGE_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG,
STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, STORAGE_NFS,
STORAGE_PUBLIC_CLOUD, STORAGE_CLOUD_SSD, STORAGE_CLOUD_ESSD, STORAGE_CLOUD_EFFICIENCY,
STORAGE_STANDARD_GRS, STORAGE_STANDARD_LRS, STORAGE_STANDARD_RAGRS, STORAGE_STANDARD_ZRS, STORAGE_PREMIUM_LRS,
STORAGE_GP2_SSD, STORAGE_IO1_SSD, STORAGE_ST1_HDD, STORAGE_SC1_SSD, STORAGE_STANDARD_SSD,
STORAGE_LOCAL_BASIC, STORAGE_LOCAL_SSD, STORAGE_CLOUD_BASIC, STORAGE_CLOUD_PERMIUM,
}
STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS}
)
type SStorageManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
db.SStandaloneResourceBaseManager
SInfrastructureManager
}
@@ -65,7 +98,7 @@ var StorageManager *SStorageManager
func init() {
StorageManager = &SStorageManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager(
SStorage{},
"storages_tbl",
"storage",
@@ -75,7 +108,7 @@ func init() {
}
type SStorage struct {
db.SEnabledStatusStandaloneResourceBase
db.SStandaloneResourceBase
SInfrastructure
SManagedResourceBase
@@ -89,6 +122,9 @@ type SStorage struct {
ZoneId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"admin_required"`
StoragecacheId string `width:"36" charset:"ascii" nullable:"true" list:"admin" get:"admin"`
Enabled bool `nullable:"false" default:"true" list:"user" create:"optional"`
Status string `width:"36" charset:"ascii" nullable:"false" default:"offline" list:"user" create:"optional"`
}
func (manager *SStorageManager) GetContextManager() []db.IModelManager {
@@ -98,7 +134,12 @@ func (manager *SStorageManager) GetContextManager() []db.IModelManager {
func (manager *SStorageManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
storageType, _ := data.GetString("storage_type")
mediumType, _ := data.GetString("medium_type")
if !utils.IsInStringArray(storageType, STORAGE_ALL_TYPES) {
capacity, _ := data.Int("capacity")
if capacity <= 0 {
return nil, httperrors.NewInputParameterError("Invalid capacity")
}
data.Set("capacity", jsonutils.NewInt(capacity))
if !utils.IsInStringArray(storageType, STORAGE_TYPES) {
return nil, httperrors.NewInputParameterError("Invalid storage type %s", storageType)
}
if !utils.IsInStringArray(mediumType, DISK_TYPES) {
@@ -113,27 +154,196 @@ func (manager *SStorageManager) ValidateCreateData(ctx context.Context, userCred
return nil, httperrors.NewResourceNotFoundError("zone %s", zoneId)
}
data.Set("zone_id", jsonutils.NewString(zone.GetId()))
// TODO: ValidateRdbConfData
// if storageType == STORAGE_RBD {
// conf := jsonutils.NewDict()
// for k, v := range data.Value() {
// if strings.HasPrefix(k, fmt.Sprintf("%s_", storageType)) {
// k = k[len(storageType)+1:]
// if len(k) > 0 {
// conf.Set(k, v)
// }
// }
// }
// data.Set("capacity", manager.ValidateRdbConfData(conf))
// }
return manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
if storageType == STORAGE_RBD {
conf, err := manager.ValidateRbdConfData(data)
if err != nil {
return nil, httperrors.NewBadRequestError("Vaildata rbd conf error: %s", err.Error())
}
data.Set("storage_conf", conf)
// data.Set("capacity", rbdConf)
} else if storageType == STORAGE_NFS {
conf, err := manager.ValidataNfsConfdata(data)
if err != nil {
return nil, httperrors.NewBadRequestError("Vaildata nfs conf error: %s", err.Error())
}
data.Set("storage_conf", conf)
}
return manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
}
func (manager *SStorageManager) ValidataNfsConfdata(data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
conf := jsonutils.NewDict()
if nfsHost, err := data.GetString("nfs_host"); err != nil {
return nil, httperrors.NewInputParameterError("Get nfs conf host error: %s", err.Error())
} else {
conf.Set("nfs_host", jsonutils.NewString(nfsHost))
}
if nfsSharedDir, err := data.GetString("nfs_shared_dir"); err != nil {
return nil, httperrors.NewInputParameterError("Get nfs conf shared dir error: %s", err.Error())
} else {
conf.Set("nfs_shared_dir", jsonutils.NewString(nfsSharedDir))
}
return conf, nil
}
func (manager *SStorageManager) ValidateRbdConfData(data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
conf := jsonutils.NewDict()
for k, v := range data.Value() {
if strings.HasPrefix(k, fmt.Sprintf("%s_", STORAGE_RBD)) {
k = k[len(STORAGE_RBD)+1:]
if len(k) > 0 {
conf.Set(k, v)
}
}
}
requireFields := []string{"mon_host", "key", "pool"}
for _, field := range requireFields {
if !conf.Contains(field) {
return nil, httperrors.NewMissingParameterError(field)
}
}
storages := make([]SStorage, 0)
err := manager.Query().Equals("storage_type", STORAGE_RBD).All(&storages)
if err != nil {
return nil, err
}
for i := 0; i < len(storages); i++ {
if conf.Equals(storages[i].StorageConf) {
return nil, httperrors.NewDuplicateResourceError("This RBD Storage[%s/%s] has already exist", storages[i].Name, conf.String())
}
}
// TODO??? ensure rbd pool can use and get capacity
return conf, nil
}
func (self *SStorage) ValidateDeleteCondition(ctx context.Context) error {
if self.GetHostCount() > 0 || self.GetDiskCount() > 0 || self.GetSnapshotCount() > 0 {
return httperrors.NewNotEmptyError("Not an empty storage provider")
}
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
return self.SStandaloneResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SStorage) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerProjId, query, data)
if self.StorageType == STORAGE_RBD {
// TODO
} else if self.StorageType == STORAGE_NFS {
sc := &SStoragecache{}
sc.Path = options.Options.NfsDefaultImageCacheDir
sc.ExternalId = self.Id
sc.Name = "nfs-" + self.Name + time.Now().Format("2006-01-02 15:04:05")
err := StoragecacheManager.TableSpec().Insert(sc)
if err != nil {
log.Errorln(err)
return
}
err = StoragecacheManager.Query().Equals("external_id", self.Id).First(sc)
if err != nil {
log.Errorln(err)
return
}
_, err = self.GetModelManager().TableSpec().Update(self, func() error {
self.StoragecacheId = sc.Id
self.Status = STORAGE_ONLINE
return nil
})
if err != nil {
log.Errorln(err)
}
}
}
func (self *SStorage) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error {
if self.Status == status {
return nil
}
oldStatus := self.Status
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.Status = status
return nil
})
if err != nil {
return err
}
if userCred != nil {
notes := fmt.Sprintf("%s=>%s", oldStatus, status)
if len(reason) > 0 {
notes = fmt.Sprintf("%s: %s", notes, reason)
}
db.OpsLog.LogEvent(self, db.ACT_UPDATE_STATUS, notes, userCred)
if strings.Contains(notes, "fail") {
logclient.AddActionLog(self, logclient.ACT_VM_SYNC_STATUS, notes, userCred, false)
}
}
return nil
}
func (self *SStorage) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return userCred.IsSystemAdmin()
}
func (self *SStorage) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if !self.Enabled {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.Enabled = true
return nil
})
if err != nil {
log.Errorf("PerformEnable save update fail %s", err)
return nil, err
}
db.OpsLog.LogEvent(self, db.ACT_ENABLE, "", userCred)
}
return nil, nil
}
func (self *SStorage) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return userCred.IsSystemAdmin()
}
func (self *SStorage) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if self.Enabled {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.Enabled = false
return nil
})
if err != nil {
log.Errorf("PerformDisable save update fail %s", err)
return nil, err
}
db.OpsLog.LogEvent(self, db.ACT_DISABLE, "", userCred)
}
return nil, nil
}
func (self *SStorage) AllowPerformOnline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return userCred.IsSystemAdmin()
}
func (self *SStorage) PerformOnline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if self.Status != STORAGE_ONLINE {
err := self.SetStatus(userCred, STORAGE_ONLINE, "")
if err != nil {
return nil, err
}
db.OpsLog.LogEvent(self, db.ACT_ONLINE, "", userCred)
}
return nil, nil
}
func (self *SStorage) AllowPerformOffline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return userCred.IsSystemAdmin()
}
func (self *SStorage) PerformOffline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if self.Status != STORAGE_OFFLINE {
err := self.SetStatus(userCred, STORAGE_OFFLINE, "")
if err != nil {
return nil, err
}
db.OpsLog.LogEvent(self, db.ACT_OFFLINE, "", userCred)
}
return nil, nil
}
func (self *SStorage) GetHostCount() int {
@@ -156,6 +366,14 @@ func (manager *SStorageManager) AllowListItems(ctx context.Context, userCred mcc
return true
}
func (self *SStorage) GetStorageCachePath(mountPoint, imageCachePath string) string {
if self.StorageType == STORAGE_NFS {
return path.Join(mountPoint, imageCachePath)
} else {
return imageCachePath
}
}
func (self *SStorage) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict {
used := self.GetUsedCapacity(tristate.True)
waste := self.GetUsedCapacity(tristate.False)
@@ -176,7 +394,7 @@ func (self *SStorage) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSOND
}
func (self *SStorage) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := self.SEnabledStatusStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query)
extra := self.SStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query)
return self.getMoreDetails(extra)
}
@@ -761,7 +979,7 @@ func (manager *SStorageManager) InitializeData() error {
}
func (manager *SStorageManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
@@ -777,11 +995,11 @@ func (manager *SStorageManager) ListItemFilter(ctx context.Context, q *sqlchemy.
}
if jsonutils.QueryBoolean(query, "share", false) {
q = q.Filter(sqlchemy.NotIn(q.Field("storage_type"), sysutils.LOCAL_STORAGE_TYPES))
q = q.Filter(sqlchemy.NotIn(q.Field("storage_type"), STORAGE_LOCAL_TYPES))
}
if jsonutils.QueryBoolean(query, "local", false) {
q = q.Filter(sqlchemy.In(q.Field("storage_type"), sysutils.LOCAL_STORAGE_TYPES))
q = q.Filter(sqlchemy.In(q.Field("storage_type"), STORAGE_LOCAL_TYPES))
}
if jsonutils.QueryBoolean(query, "usable", false) {
+8 -6
View File
@@ -29,6 +29,8 @@ const (
VPC_STATUS_UNKNOWN = "unknown"
MAX_VPC_PER_REGION = 3
DEFAULT_VPC_ID = "default"
)
type SVpcManager struct {
@@ -67,7 +69,7 @@ func (manager *SVpcManager) GetContextManager() []db.IModelManager {
func (self *SVpc) GetCloudRegionId() string {
if len(self.CloudregionId) == 0 {
return "default"
return DEFAULT_REGION_ID
} else {
return self.CloudregionId
}
@@ -85,7 +87,7 @@ func (self *SVpc) ValidateDeleteCondition(ctx context.Context) error {
if self.GetNetworkCount() > 0 {
return httperrors.NewNotEmptyError("VPC not empty")
}
if self.Id == "default" {
if self.Id == DEFAULT_VPC_ID {
return httperrors.NewProtectedResourceError("not allow to delete default vpc")
}
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
@@ -93,7 +95,7 @@ func (self *SVpc) ValidateDeleteCondition(ctx context.Context) error {
func (self *SVpc) getWireQuery() *sqlchemy.SQuery {
wires := WireManager.Query()
if self.Id == "default" {
if self.Id == DEFAULT_VPC_ID {
return wires.Filter(sqlchemy.OR(sqlchemy.IsNull(wires.Field("vpc_id")),
sqlchemy.IsEmpty(wires.Field("vpc_id")),
sqlchemy.Equals(wires.Field("vpc_id"), self.Id)))
@@ -308,15 +310,15 @@ func (self *SVpc) markAllNetworksUnknown(userCred mcclient.TokenCredential) erro
}
func (manager *SVpcManager) InitializeData() error {
vpcObj, err := manager.FetchById("default")
vpcObj, err := manager.FetchById(DEFAULT_VPC_ID)
if err != nil {
if err == sql.ErrNoRows {
defVpc := SVpc{}
defVpc.SetModelManager(VpcManager)
defVpc.Id = "default"
defVpc.Id = DEFAULT_VPC_ID
defVpc.Name = "Default"
defVpc.CloudregionId = "default"
defVpc.CloudregionId = DEFAULT_REGION_ID
defVpc.Description = "Default VPC"
defVpc.Status = VPC_STATUS_AVAILABLE
defVpc.IsDefault = true
+2
View File
@@ -65,6 +65,8 @@ type ComputeOptions struct {
ConvertEsxiDefaultTemplate string `default:"Default template" help:"ESXI baremetal convert option"`
ConvertKubeletDockerVolumeSize string `default:"256g" help:"Docker volume size"`
NfsDefaultImageCacheDir string `default:"image_cache"`
cloudcommon.DBOptions
}
@@ -209,6 +209,7 @@ func syncRegionVPCs(ctx context.Context, provider *models.SCloudprovider, task *
for j := 0; j < len(localVpcs); j += 1 {
syncVpcWires(ctx, provider, task, &localVpcs[j], remoteVpcs[j], syncRange)
syncVpcSecGroup(ctx, provider, task, &localVpcs[j], remoteVpcs[j], syncRange)
syncVpcRouteTables(ctx, provider, task, &localVpcs[j], remoteVpcs[j], syncRange)
}
}
@@ -230,6 +231,24 @@ func syncVpcSecGroup(ctx context.Context, provider *models.SCloudprovider, task
}
}
func syncVpcRouteTables(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localVpc *models.SVpc, remoteVpc cloudprovider.ICloudVpc, syncRange *models.SSyncRange) {
routeTables, err := remoteVpc.GetIRouteTables()
if err != nil {
msg := fmt.Sprintf("GetIRouteTables for vpc %s failed %s", remoteVpc.GetId(), err)
log.Errorf(msg)
logSyncFailed(provider, task, msg)
return
}
_, _, result := models.RouteTableManager.SyncRouteTables(ctx, task.GetUserCred(), localVpc, routeTables)
msg := result.Result()
notes := fmt.Sprintf("SyncRouteTables for VPC %s result: %s", localVpc.Name, msg)
log.Infof(notes)
if result.IsError() {
logSyncFailed(provider, task, msg)
return
}
}
func syncVpcWires(ctx context.Context, provider *models.SCloudprovider, task taskman.ITask, localVpc *models.SVpc, remoteVpc cloudprovider.ICloudVpc, syncRange *models.SSyncRange) {
wires, err := remoteVpc.GetIWires()
if err != nil {
+10 -2
View File
@@ -34,8 +34,7 @@ func (self *SDiskBaseTask) finalReleasePendingUsage(ctx context.Context) {
}
}
func (self *SDiskBaseTask) CleanHostSchedCache(disk *models.SDisk) {
storage := disk.GetStorage()
func (self *SDiskBaseTask) CleanStorageSchedCache(storage *models.SStorage) {
if hosts := storage.GetAllAttachingHosts(); hosts == nil {
log.Errorf("get attaching host error")
} else {
@@ -46,3 +45,12 @@ func (self *SDiskBaseTask) CleanHostSchedCache(disk *models.SDisk) {
}
}
}
func (self *SDiskBaseTask) CleanHostSchedCache(disk *models.SDisk) {
storage := disk.GetStorage()
self.CleanStorageSchedCache(storage)
if len(disk.BackupStorageId) > 0 {
bkStorage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
self.CleanStorageSchedCache(bkStorage)
}
}
+3 -2
View File
@@ -13,7 +13,7 @@ import (
)
type DiskBatchCreateTask struct {
taskman.STask
SSchedTask
}
func init() {
@@ -44,7 +44,8 @@ func (self *DiskBatchCreateTask) OnInit(ctx context.Context, objs []db.IStandalo
StartScheduleObjects(ctx, self, toSchedDisks)
}
func (self *DiskBatchCreateTask) OnScheduleFailCallback(obj IScheduleModel) {
func (self *DiskBatchCreateTask) OnScheduleFailCallback(obj IScheduleModel, reason string) {
self.SSchedTask.OnScheduleFailCallback(obj, reason)
disk := obj.(*models.SDisk)
log.Errorf("Schedule disk %s failed", disk.Name)
}
+67 -6
View File
@@ -2,6 +2,7 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -15,23 +16,31 @@ type DiskCreateTask struct {
SDiskBaseTask
}
func init() {
taskman.RegisterTask(DiskCreateTask{})
}
func (self *DiskCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
disk := obj.(*models.SDisk)
storagecache := disk.GetStorage().GetStoragecache()
imageId := disk.GetTemplateId()
if len(imageId) > 0 {
self.SetStage("on_storage_cache_image_complete", nil)
if len(disk.BackupStorageId) > 0 {
self.SetStage("OnMasterStorageCacheImageComplete", nil)
} else {
self.SetStage("OnStorageCacheImageComplete", nil)
}
storagecache.StartImageCacheTask(ctx, self.UserCred, imageId, false, self.GetTaskId())
} else {
self.OnStorageCacheImageComplete(ctx, disk, nil)
}
}
func (self *DiskCreateTask) OnMasterStorageCacheImageComplete(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
storage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
storagecache := storage.GetStoragecache()
imageId := disk.GetTemplateId()
self.SetStage("OnStorageCacheImageComplete", nil)
storagecache.StartImageCacheTask(ctx, self.UserCred, imageId, false, self.GetTaskId())
}
func (self *DiskCreateTask) OnStorageCacheImageComplete(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
rebuild, _ := self.GetParams().Bool("rebuild")
snapshot, _ := self.GetParams().GetString("snapshot")
@@ -42,12 +51,34 @@ func (self *DiskCreateTask) OnStorageCacheImageComplete(ctx context.Context, dis
host := storage.GetMasterHost()
db.OpsLog.LogEvent(disk, db.ACT_ALLOCATING, disk.GetShortDesc(), self.GetUserCred())
disk.SetStatus(self.GetUserCred(), models.DISK_STARTALLOC, "")
self.SetStage("on_disk_ready", nil)
if len(disk.BackupStorageId) > 0 {
self.SetStage("OnMasterStorageCreateDiskComplete", nil)
} else {
self.SetStage("OnDiskReady", nil)
}
if err := disk.StartAllocate(ctx, host, storage, self.GetTaskId(), self.GetUserCred(), rebuild, snapshot, self); err != nil {
self.OnStartAllocateFailed(ctx, disk, jsonutils.NewString(err.Error()))
}
}
func (self *DiskCreateTask) OnMasterStorageCreateDiskComplete(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
rebuild, _ := self.GetParams().Bool("rebuild")
snapshot, _ := self.GetParams().GetString("snapshot")
storage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
host := storage.GetMasterHost()
db.OpsLog.LogEvent(disk, db.ACT_BACKUP_ALLOCATING, disk.GetShortDesc(), self.GetUserCred())
disk.SetStatus(self.UserCred, models.DISK_BACKUP_STARTALLOC, "")
self.SetStage("OnDiskReady", nil)
if err := disk.StartAllocate(ctx, host, storage, self.GetTaskId(), self.GetUserCred(), rebuild, snapshot, self); err != nil {
self.OnBackupAllocateFailed(ctx, disk, jsonutils.NewString(fmt.Sprintf("Backup disk alloctate failed: %s", err.Error())))
}
}
func (self *DiskCreateTask) OnBackupAllocateFailed(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
disk.SetStatus(self.UserCred, models.DISK_BACKUP_ALLOC_FAILED, data.String())
self.SetStageFailed(ctx, data.String())
}
func (self *DiskCreateTask) OnStartAllocateFailed(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
disk.SetStatus(self.UserCred, models.DISK_ALLOC_FAILED, data.String())
self.SetStageFailed(ctx, data.String())
@@ -74,3 +105,33 @@ func (self *DiskCreateTask) OnDiskReadyFailed(ctx context.Context, disk *models.
disk.SetStatus(self.UserCred, models.DISK_ALLOC_FAILED, data.String())
self.SetStageFailed(ctx, data.String())
}
type DiskCreateBackupTask struct {
DiskCreateTask
}
func (self *DiskCreateBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
disk := obj.(*models.SDisk)
storage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
storagecache := storage.GetStoragecache()
imageId := disk.GetTemplateId()
if len(imageId) > 0 {
self.SetStage("OnMasterStorageCreateDiskComplete", nil)
storagecache.StartImageCacheTask(ctx, self.UserCred, imageId, false, self.GetTaskId())
} else {
self.OnMasterStorageCreateDiskComplete(ctx, disk, nil)
}
}
func (self *DiskCreateBackupTask) OnDiskReady(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
bkStorage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
self.CleanStorageSchedCache(bkStorage)
disk.SetStatus(self.UserCred, models.DISK_READY, "")
db.OpsLog.LogEvent(disk, db.ACT_BACKUP_ALLOCATE, disk.GetShortDesc(), self.UserCred)
self.SetStageComplete(ctx, nil)
}
func init() {
taskman.RegisterTask(DiskCreateTask{})
taskman.RegisterTask(DiskCreateBackupTask{})
}
+18 -3
View File
@@ -2,13 +2,13 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
)
type DiskDeleteTask struct {
@@ -51,15 +51,30 @@ func (self *DiskDeleteTask) startDeleteDisk(ctx context.Context, disk *models.SD
if isPurge {
self.OnGuestDiskDeleteSucc(ctx, disk, nil)
} else {
self.SetStage("on_guest_disk_delete_succ", nil)
if len(disk.BackupStorageId) > 0 {
self.SetStage("OnMasterStorageDeleteDiskSucc", nil)
} else {
self.SetStage("OnGuestDiskDeleteSucc", nil)
}
if host == nil {
self.OnGuestDiskDeleteFailed(ctx, disk, httperrors.NewNotFoundError("fail to find master host"))
self.OnGuestDiskDeleteFailed(ctx, disk, fmt.Errorf("fail to find master host"))
} else if err := host.GetHostDriver().RequestDeallocateDiskOnHost(host, storage, disk, self); err != nil {
self.OnGuestDiskDeleteFailed(ctx, disk, err)
}
}
}
func (self *DiskDeleteTask) OnMasterStorageDeleteDiskSucc(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
self.SetStage("OnGuestDiskDeleteSucc", nil)
storage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
host := storage.GetMasterHost()
if host == nil {
self.OnGuestDiskDeleteFailed(ctx, disk, fmt.Errorf("backup storage %s fail to find master host", disk.BackupStorageId))
} else if err := host.GetHostDriver().RequestDeallocateDiskOnHost(host, storage, disk, self); err != nil {
self.OnGuestDiskDeleteFailed(ctx, disk, err)
}
}
func (self *DiskDeleteTask) startPendingDeleteDisk(ctx context.Context, disk *models.SDisk) {
disk.DoPendingDelete(ctx, self.UserCred)
self.SetStageComplete(ctx, nil)
+244
View File
@@ -0,0 +1,244 @@
package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/pkg/utils"
)
type GuestSwitchToBackupTask struct {
SGuestBaseTask
}
/*
0. ensure master guest stopped
1. stop backup guest
2. switch guest master host to backup host
3. start guest with new master
*/
func (self *GuestSwitchToBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
host := guest.GetHost()
self.Params.Set("is_force", jsonutils.JSONTrue)
self.SetStage("OnEnsureMasterGuestStoped", nil)
err := guest.GetDriver().RequestStopOnHost(ctx, guest, host, self)
if err != nil {
// In case of master host crash
self.OnEnsureMasterGuestStoped(ctx, guest, nil)
}
}
func (self *GuestSwitchToBackupTask) OnEnsureMasterGuestStoped(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
backupHost := models.HostManager.FetchHostById(guest.BackupHostId)
self.Params.Set("is_force", jsonutils.JSONTrue)
self.SetStage("OnBackupGuestStoped", nil)
err := guest.GetDriver().RequestStopOnHost(ctx, guest, backupHost, self)
if err != nil {
self.SetStageFailed(ctx, fmt.Sprintf("Stop backup guest error: %s", err))
}
}
func (self *GuestSwitchToBackupTask) OnBackupGuestStoped(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
disks := guest.GetDisks()
for i := 0; i < len(disks); i++ {
disk := disks[i].GetDisk()
err := disk.SwitchToBackup()
if err != nil {
if i > 0 {
for j := 0; j < i; j++ {
disk = disks[j].GetDisk()
disk.SwitchToBackup()
}
}
db.OpsLog.LogEvent(guest, db.ACT_SWITCH_FAILED, fmt.Sprintf("Switch to backup disk error: %s", err), self.UserCred)
self.SetStageFailed(ctx, fmt.Sprintf("Switch to backup disk error: %s", err))
}
}
err := guest.SwitchToBackup()
if err != nil {
db.OpsLog.LogEvent(guest, db.ACT_SWITCH_FAILED, fmt.Sprintf("Switch to backup guest error: %s", err), self.UserCred)
self.SetStageFailed(ctx, fmt.Sprintf("Switch to backup guest error: %s", err))
}
db.OpsLog.LogEvent(guest, db.ACT_SWITCHED, fmt.Sprintf("Switch to backup guest error: %s", err), self.UserCred)
self.SetStage("OnNewMasterStarted", nil)
guest.StartGueststartTask(ctx, self.UserCred, nil, self.GetTaskId())
}
func (self *GuestSwitchToBackupTask) OnNewMasterStarted(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
/********************* GuestStartAndSyncToBackupTask *********************/
type GuestStartAndSyncToBackupTask struct {
SGuestBaseTask
}
func (self *GuestStartAndSyncToBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
self.SetStage("OnCheckTemplete", nil)
self.checkTemplete(ctx, guest)
}
func (self *GuestStartAndSyncToBackupTask) checkTemplete(ctx context.Context, guest *models.SGuest) {
diskCat := guest.CategorizeDisks()
if diskCat.Root != nil && len(diskCat.Root.GetTemplateId()) > 0 {
err := guest.GetDriver().CheckDiskTemplateOnStorage(ctx, self.UserCred, diskCat.Root.GetTemplateId(),
diskCat.Root.BackupStorageId, self)
if err != nil {
self.SetStageFailed(ctx, err.Error())
}
} else {
self.OnCheckTemplete(ctx, guest, nil)
}
}
func (self *GuestStartAndSyncToBackupTask) OnCheckTemplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnStartBackupGuest", nil)
host := models.HostManager.FetchHostById(guest.BackupHostId)
guest.GetDriver().RequestStartOnHost(ctx, guest, host, self.UserCred, self)
}
func (self *GuestStartAndSyncToBackupTask) OnStartBackupGuest(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(guest, db.ACT_BACKUP_START, "", self.UserCred)
if utils.IsInStringArray(guest.Status, models.VM_RUNNING_STATUS) {
self.SetStage("OnRequestSyncToBackup", nil)
err := guest.GetDriver().RequestSyncToBackup(ctx, guest, self)
if err != nil {
self.SetStageFailed(ctx, fmt.Sprintf("Guest Request Sync to backup failed %s", err))
}
} else {
self.SetStageComplete(ctx, nil)
}
}
func (self *GuestStartAndSyncToBackupTask) OnStartBackupGuestFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(guest, db.ACT_BACKUP_START_FAILED, "", self.UserCred)
self.SetStageFailed(ctx, data.String())
}
func (self *GuestStartAndSyncToBackupTask) OnRequestSyncToBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
type GuestCreateBackupTask struct {
SSchedTask
}
func (self *GuestCreateBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
StartScheduleObjects(ctx, self, []db.IStandaloneModel{obj})
}
func (self *GuestCreateBackupTask) OnStartSchedule(obj IScheduleModel) {
guest := obj.(*models.SGuest)
guest.SetStatus(self.UserCred, models.VM_BACKUP_CREATING, "")
db.OpsLog.LogEvent(guest, db.ACT_START_CREATE_BACKUP, "", self.UserCred)
}
func (self *GuestCreateBackupTask) GetSchedParams() *jsonutils.JSONDict {
obj := self.GetObject()
guest := obj.(*models.SGuest)
schedDesc := guest.ToSchedDesc()
if self.Params.Contains("prefer_host_id") {
preferHostId, _ := self.Params.Get("prefer_host_id")
schedDesc.Set("prefer_host_id", preferHostId)
}
return schedDesc
}
func (self *GuestCreateBackupTask) OnScheduleFailCallback(obj IScheduleModel, reason string) {
// do nothing
}
func (self *GuestCreateBackupTask) OnScheduleFailed(ctx context.Context, reason string) {
obj := self.GetObject()
guest := obj.(*models.SGuest)
self.TaskFailed(ctx, guest, reason)
}
func (self *GuestCreateBackupTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, targetHostId string) {
guest := obj.(*models.SGuest)
targetHost := models.HostManager.FetchHostById(targetHostId)
if targetHost == nil {
self.TaskFailed(ctx, guest, "target host not found?")
return
}
guest.SetHostIdWithBackup(guest.HostId, targetHostId)
db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP, fmt.Sprintf("guest backup start create on host %s", targetHostId), self.UserCred)
// backup disk only support disk backend local
storage := guest.GetDriver().ChooseHostStorage(targetHost, models.STORAGE_LOCAL)
if storage == nil {
self.TaskFailed(ctx, guest, "Get backup storage error")
return
}
self.StartCreateBackupDisks(ctx, guest, storage.Id)
}
func (self *GuestCreateBackupTask) StartCreateBackupDisks(ctx context.Context, guest *models.SGuest, storageId string) {
guestDisks := guest.GetDisks()
for i := 0; i < len(guestDisks); i++ {
disk := guestDisks[i].GetDisk()
disk.GetModelManager().TableSpec().Update(disk, func() error {
disk.BackupStorageId = storageId
return nil
})
}
self.SetStage("OnCreateBackupDisks", nil)
err := guest.CreateBackupDisks(ctx, self.UserCred, self.GetTaskId())
if err != nil {
self.TaskFailed(ctx, guest, err.Error())
}
}
func (self *GuestCreateBackupTask) OnCreateBackupDisks(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnCreateBackup", nil)
guest.StartCreateBackup(ctx, self.UserCred, self.GetTaskId(), nil)
}
func (self *GuestCreateBackupTask) OnCreateBackupDisksFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.TaskFailed(ctx, guest, fmt.Sprintf("Create Backup Disks failed %s", data.String()))
}
func (self *GuestCreateBackupTask) OnCreateBackupFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.TaskFailed(ctx, guest, fmt.Sprintf("Deploy Backup failed %s", data.String()))
}
func (self *GuestCreateBackupTask) OnCreateBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
guestStatus, _ := self.Params.GetString("guest_status")
guest.SetStatus(self.UserCred, guestStatus, "")
if utils.IsInStringArray(guestStatus, models.VM_RUNNING_STATUS) {
self.OnGuestStart(ctx, guest, nil)
} else {
self.SetStageComplete(ctx, nil)
}
}
func (self *GuestCreateBackupTask) OnGuestStart(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnSyncToBackup", nil)
err := guest.GuestStartAndSyncToBackup(ctx, self.UserCred, nil, self.GetTaskId())
if err != nil {
self.SetStageFailed(ctx, fmt.Sprintf("Guest sycn to backup error %s", err.Error()))
}
}
func (self *GuestCreateBackupTask) OnSyncToBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func (self *GuestCreateBackupTask) TaskFailed(ctx context.Context, guest *models.SGuest, reason string) {
guest.SetStatus(self.UserCred, models.VM_BACKUP_CREATE_FAILED, reason)
db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP_FAILED, reason, self.UserCred)
self.SetStageFailed(ctx, reason)
}
func init() {
taskman.RegisterTask(GuestSwitchToBackupTask{})
taskman.RegisterTask(GuestStartAndSyncToBackupTask{})
taskman.RegisterTask(GuestCreateBackupTask{})
}
+13 -3
View File
@@ -13,7 +13,7 @@ import (
)
type GuestBatchCreateTask struct {
taskman.STask
SSchedTask
}
func init() {
@@ -24,13 +24,20 @@ func (self *GuestBatchCreateTask) OnInit(ctx context.Context, objs []db.IStandal
StartScheduleObjects(ctx, self, objs)
}
func (self *GuestBatchCreateTask) OnScheduleFailCallback(obj IScheduleModel) {
func (self *GuestBatchCreateTask) OnScheduleFailCallback(obj IScheduleModel, reason string) {
self.SSchedTask.OnScheduleFailCallback(obj, reason)
guest := obj.(*models.SGuest)
if guest.DisableDelete.IsTrue() {
guest.SetDisableDelete(false)
}
}
func (self *GuestBatchCreateTask) SaveScheduleResultWithBackup(ctx context.Context, obj IScheduleModel, master, slave string) {
guest := obj.(*models.SGuest)
guest.SetHostIdWithBackup(master, slave)
self.SaveScheduleResult(ctx, obj, master)
}
func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, hostId string) {
var err error
guest := obj.(*models.SGuest)
@@ -39,7 +46,10 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS
if err != nil {
log.Errorf("GetPendingUsage fail %s", err)
}
guest.SetHostId(hostId)
if len(guest.HostId) == 0 {
guest.SetHostId(hostId)
}
quotaCpuMem := models.SQuota{Cpu: int(guest.VcpuCount), Memory: guest.VmemSize}
err = models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, guest.ProjectId, &pendingUsage, &quotaCpuMem)
self.SetPendingUsage(&pendingUsage)
@@ -226,7 +226,37 @@ func (self *ManagedGuestCreateDiskTask) AttachManagedDisks(ctx context.Context,
self.SetStageComplete(ctx, nil)
}
type GuestCreateBackupDisksTask struct {
SGuestBaseTask
}
func (self *GuestCreateBackupDisksTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
self.CreateBackups(ctx, guest, nil)
}
func (self *GuestCreateBackupDisksTask) CreateBackups(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
body := jsonutils.NewDict()
var diskIndex int64 = 0
if self.Params.Contains("disk_index") {
diskIndex, _ = self.Params.Int("disk_index")
}
body.Set("disk_index", jsonutils.NewInt(diskIndex+1))
self.SetStage("CreateBackups", body)
guestDisks := guest.GetDisks()
if int(diskIndex) == len(guestDisks) {
self.SetStageComplete(ctx, nil)
} else {
err := guestDisks[diskIndex].GetDisk().StratCreateBackupTask(ctx, self.UserCred, self.GetTaskId())
if err != nil {
self.SetStageFailed(ctx, err.Error())
}
}
}
func init() {
taskman.RegisterTask(GuestCreateBackupDisksTask{})
taskman.RegisterTask(GuestCreateDiskTask{})
taskman.RegisterTask(KVMGuestCreateDiskTask{})
taskman.RegisterTask(ManagedGuestCreateDiskTask{})
+3 -3
View File
@@ -42,7 +42,7 @@ func (self *GuestCreateTask) OnWaitGuestNetworksReady(ctx context.Context, obj d
func (self *GuestCreateTask) OnGuestNetworkReady(ctx context.Context, guest *models.SGuest) {
guest.SetStatus(self.UserCred, models.VM_CREATE_DISK, "")
self.SetStage("on_disk_prepared", nil)
self.SetStage("OnDiskPrepared", nil)
guest.GetDriver().RequestGuestCreateAllDisks(ctx, guest, self)
}
@@ -59,7 +59,7 @@ func (self *GuestCreateTask) OnDiskPrepared(ctx context.Context, obj db.IStandal
guest := obj.(*models.SGuest)
cdrom, _ := self.Params.GetString("cdrom")
if len(cdrom) > 0 {
self.SetStage("on_cdrom_prepared", nil)
self.SetStage("OnCdromPrepared", nil)
guest.GetDriver().RequestGuestCreateInsertIso(ctx, cdrom, guest, self)
} else {
self.OnCdromPrepared(ctx, obj, data)
@@ -85,7 +85,7 @@ func (self *GuestCreateTask) OnCdromPreparedFailed(ctx context.Context, obj db.I
}
func (self *GuestCreateTask) StartDeployGuest(ctx context.Context, guest *models.SGuest) {
self.SetStage("on_deploy_guest_desc_complete", nil)
self.SetStage("OnDeployGuestDescComplete", nil)
guest.StartGuestDeployTask(ctx, self.UserCred, self.Params, "create", self.GetId())
}
+25 -6
View File
@@ -30,16 +30,35 @@ func (self *GuestDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel
self.OnGuestStopComplete(ctx, obj, data)
return
}
self.SetStage("on_guest_stop_complete", nil)
err := guest.GetDriver().RequestStopGuestForDelete(ctx, guest, self)
if len(guest.BackupHostId) > 0 {
self.SetStage("OnMasterHostStopGuestComplete", nil)
if err := guest.GetDriver().RequestStopGuestForDelete(ctx, guest, nil, self); err != nil {
log.Errorf("RequestStopGuestForDelete fail %s", err)
self.OnMasterHostStopGuestComplete(ctx, guest, nil)
}
} else {
self.SetStage("OnGuestStopComplete", nil)
if err := guest.GetDriver().RequestStopGuestForDelete(ctx, guest, nil, self); err != nil {
log.Errorf("RequestStopGuestForDelete fail %s", err)
self.OnGuestStopComplete(ctx, guest, nil)
}
}
}
func (self *GuestDeleteTask) OnMasterHostStopGuestComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnGuestStopComplete", nil)
host := models.HostManager.FetchHostById(guest.BackupHostId)
err := guest.GetDriver().RequestStopGuestForDelete(ctx, guest, host, self)
if err != nil {
log.Errorf("RequestStopGuestForDelete fail %s", err)
// errMsg := jsonutils.NewString(err.Error())
// self.OnGuestStopCompleteFailed(ctx, obj, errMsg)
self.OnGuestStopComplete(ctx, obj, data)
self.OnGuestStopComplete(ctx, guest, nil)
}
}
func (self *GuestDeleteTask) OnMasterHostStopGuestCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.OnGuestStopComplete(ctx, guest, nil) // ignore stop error
}
func (self *GuestDeleteTask) OnGuestStopComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
@@ -119,7 +138,7 @@ func (self *GuestDeleteTask) OnSyncGuestConfCompleteFailed(ctx context.Context,
func (self *GuestDeleteTask) StartDeleteGuest(ctx context.Context, guest *models.SGuest) {
// No snapshot
self.SetStage("on_guest_detach_disks_complete", nil)
self.SetStage("OnGuestDetachDisksComplete", nil)
guest.GetDriver().RequestDetachDisksFromGuestForDelete(ctx, guest, self)
}
+61 -11
View File
@@ -16,10 +16,6 @@ type GuestDeployTask struct {
SGuestBaseTask
}
func init() {
taskman.RegisterTask(GuestDeployTask{})
}
func (self *GuestDeployTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
if !guest.IsNetworkAllocated() {
@@ -31,25 +27,41 @@ func (self *GuestDeployTask) OnInit(ctx context.Context, obj db.IStandaloneModel
func (self *GuestDeployTask) OnGuestNetworkReady(ctx context.Context, guest *models.SGuest) {
if jsonutils.QueryBoolean(self.Params, "restart", false) {
self.SetStage("on_deploy_wait_server_stop", nil)
self.SetStage("OnDeployWaitServerStop", nil)
guest.StartGuestStopTask(ctx, self.UserCred, false, self.GetTaskId())
} else {
self.OnDeployWaitServerStop(ctx, guest, nil)
}
}
func (self *GuestDeployTask) OnDeployWaitServerStop(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
func (self *GuestDeployTask) OnDeployWaitServerStop(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnDeployGuestComplete", nil)
targetHostId, _ := self.Params.GetString("target_host_id")
if len(targetHostId) == 0 {
targetHostId = guest.HostId
if len(guest.BackupHostId) > 0 {
self.SetStage("OnSlaveHostDeployComplete", nil)
self.DeployBackup(ctx, guest, nil)
return
} else {
targetHostId = guest.HostId
}
}
host := models.HostManager.FetchHostById(targetHostId)
self.StartDeployGuestOnHost(ctx, guest, host)
self.DeployOnHost(ctx, guest, host)
}
func (self *GuestDeployTask) StartDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost) {
self.SetStage("on_deploy_guest_complete", nil)
func (self *GuestDeployTask) DeployBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
host := models.HostManager.FetchHostById(guest.BackupHostId)
err := guest.GetDriver().RequestDeployGuestOnHost(ctx, guest, host, self)
if err != nil {
log.Errorf("request_deploy_guest_on_host %s", err)
self.OnDeployGuestFail(ctx, guest, err)
} else {
guest.SetStatus(self.UserCred, models.VM_DEPLOYING_BACKUP, "")
}
}
func (self *GuestDeployTask) DeployOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost) {
err := guest.GetDriver().RequestDeployGuestOnHost(ctx, guest, host, self)
if err != nil {
log.Errorf("request_deploy_guest_on_host %s", err)
@@ -59,6 +71,22 @@ func (self *GuestDeployTask) StartDeployGuestOnHost(ctx context.Context, guest *
}
}
func (self *GuestDeployTask) OnSlaveHostDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
host := guest.GetHost()
self.SetStage("OnDeployGuestComplete", nil)
self.DeployOnHost(ctx, guest, host)
}
func (self *GuestDeployTask) OnSlaveHostDeployCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
guest.SetStatus(self.UserCred, models.VM_DEPLOYING_BACKUP_FAILED, "")
self.SetStage("OnUndeployBackupGuest", nil)
guest.StartUndeployGuestTask(ctx, self.UserCred, self.GetId(), guest.BackupHostId)
}
func (self *GuestDeployTask) OnUndeployBackupGuest(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageFailed(ctx, "deploy backup failed")
}
func (self *GuestDeployTask) OnDeployGuestFail(ctx context.Context, guest *models.SGuest, err error) {
guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, err.Error())
self.SetStageFailed(ctx, err.Error())
@@ -108,3 +136,25 @@ func (self *GuestDeployTask) OnDeployStartGuestComplete(ctx context.Context, obj
func (self *GuestDeployTask) OnDeployGuestSyncstatusComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
type GuestDeployBackupTask struct {
GuestDeployTask
}
func (self *GuestDeployBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
if len(guest.BackupHostId) == 0 {
self.SetStageFailed(ctx, "Guest dosen't have backup host")
}
self.SetStage("OnDeployGuestComplete", nil)
self.DeployBackup(ctx, guest, nil)
}
func (self *GuestDeployBackupTask) OnDeployGuestComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
func init() {
taskman.RegisterTask(GuestDeployTask{})
taskman.RegisterTask(GuestDeployBackupTask{})
}
@@ -40,13 +40,10 @@ func (self *GuestDetachAllDisksTask) OnDiskDeleteComplete(ctx context.Context, o
if purge {
taskData.Add(jsonutils.JSONTrue, "purge")
}
disk := guestdisk.GetDisk()
storage := disk.GetStorage()
if storage.IsLocal() {
taskData.Add(jsonutils.JSONFalse, "keep_disk")
} else {
taskData.Add(jsonutils.JSONTrue, "keep_disk")
if jsonutils.QueryBoolean(self.Params, "override_pending_delete", false) {
taskData.Add(jsonutils.JSONTrue, "override_pending_delete")
}
taskData.Add(jsonutils.JSONFalse, "keep_disk")
task, err := taskman.TaskManager.NewTask(ctx, "GuestDetachDiskTask", guest, self.UserCred, taskData, self.GetTaskId(), "", nil)
if err != nil {
self.SetStageFailed(ctx, err.Error())
+1 -4
View File
@@ -91,15 +91,12 @@ func (self *GuestDetachDiskTask) OnSyncConfigComplete(ctx context.Context, guest
db.OpsLog.LogEvent(disk, db.ACT_DELETE, "", self.UserCred)
disk.RealDelete(ctx, self.UserCred)
self.SetStageComplete(ctx, nil)
return
}
if !keepDisk && disk.GetGuestDiskCount() == 0 && disk.AutoDelete {
} else if (disk.Status != models.DISK_READY || !keepDisk) && disk.GetGuestDiskCount() == 0 && disk.AutoDelete {
self.SetStage("on_disk_delete_complete", nil)
db.OpsLog.LogEvent(disk, db.ACT_DELETE, "", self.UserCred)
err := guest.GetDriver().RequestDeleteDetachedDisk(ctx, disk, self, purge)
if err != nil {
self.OnTaskFail(ctx, guest, disk, err)
return
}
} else {
self.SetStageComplete(ctx, nil)
+23 -33
View File
@@ -12,14 +12,11 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/httputils"
)
type GuestMigrateTask struct {
SGuestBaseTask
SSchedTask
}
type GuestLiveMigrateTask struct {
@@ -32,45 +29,38 @@ func init() {
}
func (self *GuestMigrateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
guest.SetStatus(self.UserCred, models.VM_MIGRATING, "")
db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, "", self.UserCred)
self.FindCandidataTarget(ctx, guest)
StartScheduleObjects(ctx, self, []db.IStandaloneModel{obj})
}
func (self *GuestMigrateTask) FindCandidataTarget(ctx context.Context, guest *models.SGuest) {
func (self *GuestMigrateTask) GetSchedParams() *jsonutils.JSONDict {
obj := self.GetObject()
guest := obj.(*models.SGuest)
schedDesc := guest.ToSchedDesc()
if self.Params.Contains("prefer_host_id") {
preferHostId, _ := self.Params.Get("prefer_host_id")
schedDesc.Set("prefer_host_id", preferHostId)
}
s := auth.GetAdminSession(options.Options.Region, "")
results, err := modules.SchedManager.DoSchedule(s, schedDesc, 1)
if err != nil {
self.TaskFailed(ctx, guest, fmt.Sprintf("Do schedule error %s", err))
} else {
self.OnScheduleComplete(ctx, guest, results)
}
return schedDesc
}
func (self *GuestMigrateTask) OnScheduleComplete(ctx context.Context, guest *models.SGuest, results []jsonutils.JSONObject) {
if len(results) != 1 {
self.TaskFailed(ctx, guest, "Schedule failed")
return
}
var targetHostId string
if results[0].Contains("candidate") {
targetHostId, _ = results[0].GetString("candidate", "id")
} else if results[0].Contains("error") {
msg, _ := results[0].Get("error")
self.TaskFailed(ctx, guest, msg.String())
return
} else {
msg := fmt.Sprintf("Unknown scheduler result %s", results[0])
self.TaskFailed(ctx, guest, msg)
return
}
func (self *GuestMigrateTask) OnStartSchedule(obj IScheduleModel) {
guest := obj.(*models.SGuest)
guest.SetStatus(self.UserCred, models.VM_MIGRATING, "")
db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, "", self.UserCred)
}
func (self *GuestMigrateTask) OnScheduleFailCallback(obj IScheduleModel, reason string) {
// do nothing
}
func (self *GuestMigrateTask) OnScheduleFailed(ctx context.Context, reason string) {
obj := self.GetObject()
guest := obj.(*models.SGuest)
self.TaskFailed(ctx, guest, reason)
}
func (self *GuestMigrateTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, targetHostId string) {
guest := obj.(*models.SGuest)
targetHost := models.HostManager.FetchHostById(targetHostId)
if targetHost == nil {
self.TaskFailed(ctx, guest, "target host not found?")
+54 -2
View File
@@ -2,6 +2,7 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -26,13 +27,27 @@ func (self *GuestStartTask) OnInit(ctx context.Context, obj db.IStandaloneModel,
func (self *GuestStartTask) checkTemplate(ctx context.Context, guest *models.SGuest) {
diskCat := guest.CategorizeDisks()
if diskCat.Root != nil && len(diskCat.Root.GetTemplateId()) > 0 {
self.SetStage("on_start_template_ready", nil)
if len(guest.BackupHostId) > 0 {
self.SetStage("OnMasterHostTemplateReady", nil)
} else {
self.SetStage("OnStartTemplateReady", nil)
}
guest.GetDriver().CheckDiskTemplateOnStorage(ctx, self.UserCred, diskCat.Root.GetTemplateId(), diskCat.Root.StorageId, self)
} else {
self.startStart(ctx, guest)
}
}
func (self *GuestStartTask) OnMasterHostTemplateReady(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnStartTemplateReady", nil)
diskCat := guest.CategorizeDisks()
err := guest.GetDriver().CheckDiskTemplateOnStorage(ctx, self.UserCred, diskCat.Root.GetTemplateId(),
diskCat.Root.BackupStorageId, self)
if err != nil {
self.SetStageFailed(ctx, err.Error())
}
}
func (self *GuestStartTask) OnStartTemplateReady(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
self.startStart(ctx, guest)
@@ -40,7 +55,15 @@ func (self *GuestStartTask) OnStartTemplateReady(ctx context.Context, obj db.ISt
func (self *GuestStartTask) startStart(ctx context.Context, guest *models.SGuest) {
db.OpsLog.LogEvent(guest, db.ACT_STARTING, nil, self.UserCred)
self.SetStage("on_start_complete", nil)
if len(guest.BackupHostId) > 0 {
self.RequestStartBacking(ctx, guest)
} else {
self.RequestStart(ctx, guest)
}
}
func (self *GuestStartTask) RequestStart(ctx context.Context, guest *models.SGuest) {
self.SetStage("OnStartComplete", nil)
host := guest.GetHost()
guest.SetStatus(self.UserCred, models.VM_STARTING, "")
result, err := guest.GetDriver().RequestStartOnHost(ctx, guest, host, self.UserCred, self)
@@ -55,6 +78,35 @@ func (self *GuestStartTask) startStart(ctx context.Context, guest *models.SGuest
}
}
func (self *GuestStartTask) RequestStartBacking(ctx context.Context, guest *models.SGuest) {
self.SetStage("OnStartBackupGuestComplete", nil)
host := models.HostManager.FetchHostById(guest.BackupHostId)
guest.SetStatus(self.UserCred, models.VM_BACKUP_STARTING, "")
result, err := guest.GetDriver().RequestStartOnHost(ctx, guest, host, self.UserCred, self)
if err != nil {
self.onStartGuestFailed(ctx, guest, err)
} else {
if result != nil && jsonutils.QueryBoolean(result, "is_running", false) {
self.OnStartBackupGuestComplete(ctx, guest, nil)
}
}
}
func (self *GuestStartTask) OnStartBackupGuestComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
if data != nil {
nbdServerPort, err := data.Int("nbd_server_port")
if err == nil {
backupHost := models.HostManager.FetchHostById(guest.BackupHostId)
nbdServerUri := fmt.Sprintf("nbd:%s:%d", backupHost.AccessIp, nbdServerPort)
guest.SetMetadata(ctx, "backup_nbd_server_uri", nbdServerUri, self.UserCred)
} else {
self.onStartGuestFailed(ctx, guest, fmt.Errorf("Start backup guest result missing nbd_server_port"))
return
}
}
self.RequestStart(ctx, guest)
}
func (self *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
db.OpsLog.LogEvent(guest, db.ACT_START, guest.GetShortDesc(), self.UserCred)
+16 -3
View File
@@ -39,7 +39,7 @@ func (self *GuestStopTask) stopGuest(ctx context.Context, guest *models.SGuest)
if !self.isSubtask() {
guest.SetStatus(self.UserCred, models.VM_STOPPING, "")
}
self.SetStage("on_guest_stop_task_complete", nil)
self.SetStage("OnMasterStopTaskComplete", nil)
err := guest.GetDriver().RequestStopOnHost(ctx, guest, host, self)
if err != nil {
log.Errorf("RequestStopOnHost fail %s", err)
@@ -47,8 +47,21 @@ func (self *GuestStopTask) stopGuest(ctx context.Context, guest *models.SGuest)
}
}
func (self *GuestStopTask) OnGuestStopTaskComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
func (self *GuestStopTask) OnMasterStopTaskComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
if len(guest.BackupHostId) > 0 {
host := models.HostManager.FetchHostById(guest.BackupHostId)
self.SetStage("OnGuestStopTaskComplete", nil)
err := guest.GetDriver().RequestStopOnHost(ctx, guest, host, self)
if err != nil {
log.Errorf("RequestStopOnHost fail %s", err)
self.OnStopGuestFail(ctx, guest, err)
}
} else {
self.OnGuestStopTaskComplete(ctx, guest, data)
}
}
func (self *GuestStopTask) OnGuestStopTaskComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
if !self.isSubtask() {
guest.SetStatus(self.UserCred, models.VM_READY, "")
}
@@ -47,6 +47,8 @@ func (self *GuestSyncstatusTask) OnGetStatusSucc(ctx context.Context, guest *mod
statusStr = models.VM_SUSPEND
case cloudprovider.CloudVMStatusStopped:
statusStr = models.VM_READY
case models.VM_BLOCK_STREAM:
break
default:
statusStr = models.VM_UNKNOWN
}
+17 -1
View File
@@ -22,7 +22,11 @@ func init() {
func (self *GuestUndeployTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
targetHostId, _ := self.Params.GetString("target_host_id")
self.SetStage("OnGuestUndeployComplete", nil)
if len(targetHostId) == 0 {
if len(guest.BackupHostId) > 0 {
self.SetStage("OnMasetHostUndeployGuestComplete", nil)
}
targetHostId = guest.HostId
}
var host *models.SHost
@@ -30,7 +34,19 @@ func (self *GuestUndeployTask) OnInit(ctx context.Context, obj db.IStandaloneMod
host = models.HostManager.FetchHostById(targetHostId)
}
if host != nil {
self.SetStage("on_guest_undeploy_complete", nil)
err := guest.GetDriver().RequestUndeployGuestOnHost(ctx, guest, host, self)
if err != nil {
self.OnStartDeleteGuestFail(ctx, err)
}
} else {
self.SetStageComplete(ctx, nil)
}
}
func (self *GuestUndeployTask) OnMasetHostUndeployGuestComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStage("OnGuestUndeployComplete", nil)
host := models.HostManager.FetchHostById(guest.BackupHostId)
if host != nil {
err := guest.GetDriver().RequestUndeployGuestOnHost(ctx, guest, host, self)
if err != nil {
self.OnStartDeleteGuestFail(ctx, err)
+76 -20
View File
@@ -10,6 +10,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
@@ -31,14 +32,52 @@ type IScheduleModel interface {
type IScheduleTask interface {
GetUserCred() mcclient.TokenCredential
GetParams() *jsonutils.JSONDict
GetSchedParams() *jsonutils.JSONDict
GetPendingUsage(quota quotas.IQuota) error
SetStage(stageName string, data *jsonutils.JSONDict)
SetStageFailed(ctx context.Context, reason string)
OnScheduleFailCallback(obj IScheduleModel)
OnStartSchedule(obj IScheduleModel)
OnScheduleFailCallback(obj IScheduleModel, reason string)
OnScheduleComplete(ctx context.Context, items []db.IStandaloneModel, data *jsonutils.JSONDict)
SaveScheduleResult(ctx context.Context, obj IScheduleModel, hostId string)
SaveScheduleResultWithBackup(ctx context.Context, obj IScheduleModel, master, slave string)
OnScheduleFailed(ctx context.Context, reason string)
}
type SSchedTask struct {
taskman.STask
}
func (self *SSchedTask) GetSchedParams() *jsonutils.JSONDict {
return self.GetParams()
}
func (self *SSchedTask) OnStartSchedule(obj IScheduleModel) {
db.OpsLog.LogEvent(obj, db.ACT_ALLOCATING, nil, self.GetUserCred())
obj.SetStatus(self.GetUserCred(), SCHEDULE, "")
}
func (self *SSchedTask) OnScheduleFailCallback(obj IScheduleModel, reason string) {
obj.SetStatus(self.GetUserCred(), SCHEDULE_FAILED, reason)
db.OpsLog.LogEvent(obj, db.ACT_ALLOCATE_FAIL, reason, self.GetUserCred())
notifyclient.NotifySystemError(obj.GetId(), obj.GetName(), SCHEDULE_FAILED, reason)
}
func (self *SSchedTask) OnScheduleComplete(ctx context.Context, items []db.IStandaloneModel, data *jsonutils.JSONDict) {
self.SetStageComplete(ctx, nil)
}
func (self *SSchedTask) SaveScheduleResult(ctx context.Context, obj IScheduleModel, hostId string) {
// ...
}
func (self *SSchedTask) SaveScheduleResultWithBackup(ctx context.Context, obj IScheduleModel, master, slave string) {
// ...
}
func (self *SSchedTask) OnScheduleFailed(ctx context.Context, reason string) {
self.SetStageFailed(ctx, reason)
}
func StartScheduleObjects(
@@ -50,8 +89,7 @@ func StartScheduleObjects(
for i, obj := range objs {
schedObj := obj.(IScheduleModel)
schedObjs[i] = schedObj
db.OpsLog.LogEvent(schedObj, db.ACT_ALLOCATING, nil, task.GetUserCred())
schedObj.SetStatus(task.GetUserCred(), SCHEDULE, "")
task.OnStartSchedule(schedObj)
}
doScheduleObjects(ctx, task, schedObjs)
}
@@ -61,12 +99,13 @@ func doScheduleObjects(
task IScheduleTask,
objs []IScheduleModel,
) {
schedtags := models.ApplySchedPolicies(task.GetParams())
parmas := task.GetSchedParams()
schedtags := models.ApplySchedPolicies(parmas)
task.SetStage("OnScheduleComplete", schedtags)
s := auth.GetAdminSession(options.Options.Region, "")
results, err := modules.SchedManager.DoSchedule(s, task.GetParams(), len(objs))
results, err := modules.SchedManager.DoSchedule(s, parmas, len(objs))
if err != nil {
onSchedulerRequestFail(ctx, task, objs, fmt.Sprintf("Scheduler fail: %s", err))
return
@@ -81,7 +120,7 @@ func cancelPendingUsage(ctx context.Context, task IScheduleTask) {
log.Errorf("Taks GetPendingUsage fail %s", err)
return
}
ownerProjectId, _ := task.GetParams().GetString("owner_tenant_id")
ownerProjectId, _ := task.GetSchedParams().GetString("owner_tenant_id")
err = models.QuotaManager.CancelPendingUsage(ctx, task.GetUserCred(), ownerProjectId, &pendingUsage, &pendingUsage)
if err != nil {
log.Errorf("cancelpendingusage error %s", err)
@@ -95,13 +134,13 @@ func onSchedulerRequestFail(
reason string,
) {
for _, obj := range objs {
onScheduleFail(ctx, task, obj, reason)
onObjScheduleFail(ctx, task, obj, reason)
}
task.SetStageFailed(ctx, fmt.Sprintf("Schedule failed: %s", reason))
task.OnScheduleFailed(ctx, fmt.Sprintf("Schedule failed: %s", reason))
cancelPendingUsage(ctx, task)
}
func onScheduleFail(
func onObjScheduleFail(
ctx context.Context,
task IScheduleTask,
obj IScheduleModel,
@@ -114,11 +153,7 @@ func onScheduleFail(
if len(msg) > 0 {
reason = fmt.Sprintf("%s: %s", reason, msg)
}
obj.SetStatus(task.GetUserCred(), SCHEDULE_FAILED, reason)
db.OpsLog.LogEvent(obj, db.ACT_ALLOCATE_FAIL, reason, task.GetUserCred())
notifyclient.NotifySystemError(obj.GetId(), obj.GetName(), SCHEDULE_FAILED, reason)
task.OnScheduleFailCallback(obj)
task.OnScheduleFailCallback(obj, reason)
}
func onSchedulerResults(
@@ -131,25 +166,46 @@ func onSchedulerResults(
for idx := 0; idx < len(objs); idx += 1 {
obj := objs[idx]
result := results[idx]
if result.Contains("candidate") {
if result.Contains("candidate", "id") {
hostId, _ := result.GetString("candidate", "id")
onScheduleSucc(ctx, task, obj, hostId)
succCount += 1
} else if result.Contains("candidate", "master_id") {
master, _ := result.GetString("candidate", "master_id")
slave, _ := result.GetString("candidate", "slave_id")
if len(master) == 0 || len(slave) == 0 {
onObjScheduleFail(ctx, task, obj, "Scheduler candidates not match")
} else {
onMasterSlaveScheduleSucc(ctx, task, obj, master, slave)
}
} else if result.Contains("error") {
msg, _ := result.Get("error")
onScheduleFail(ctx, task, obj, fmt.Sprintf("%s", msg))
onObjScheduleFail(ctx, task, obj, fmt.Sprintf("%s", msg))
} else {
msg := fmt.Sprintf("Unknown scheduler result %s", result)
onScheduleFail(ctx, task, obj, msg)
onObjScheduleFail(ctx, task, obj, msg)
return
}
}
if succCount == 0 {
task.SetStageFailed(ctx, "Schedule failed")
task.OnScheduleFailed(ctx, "Schedule failed")
}
cancelPendingUsage(ctx, task)
}
func onMasterSlaveScheduleSucc(
ctx context.Context,
task IScheduleTask,
obj IScheduleModel,
master, slave string,
) {
lockman.LockObject(ctx, obj)
defer lockman.ReleaseObject(ctx, obj)
task.SaveScheduleResultWithBackup(ctx, obj, master, slave)
models.HostManager.ClearSchedDescCache(master)
models.HostManager.ClearSchedDescCache(slave)
}
func onScheduleSucc(
ctx context.Context,
task IScheduleTask,
+44 -2
View File
@@ -1,8 +1,8 @@
package httperrors
import (
"bytes"
"fmt"
"yunion.io/x/onecloud/pkg/util/httputils"
)
@@ -11,13 +11,55 @@ func NewJsonClientError(code int, title string, msg string, error httputils.Erro
return &err
}
func msgToTemplate(msg string) string {
// 将%s %d之类格式化字符串转换成{0}、{1}格式
// 注意: 1.不支持复杂类型的转换例如%.2f , %[1]d, % x
// 2.原始msg中如果包含{0},{1}形式的字符串同样会引发错误。
// 在抛出error msg时应注意避免
fmtstr := false
lst := []rune(msg)
lastIndex := len(lst) - 1
temp := bytes.Buffer{}
index := 0
for i, c := range lst {
switch c {
case '%':
if fmtstr || i == lastIndex {
temp.WriteRune(c)
fmtstr = false
} else {
fmtstr = true
}
case 'v', 'T', 't', 'b', 'c', 'd', 'o', 'q', 'x', 'X', 'U', 'e', 'E', 'f', 'F', 'g', 'G', 's', 'p':
if fmtstr {
temp.WriteRune('{')
temp.WriteString(fmt.Sprintf("%d", index))
temp.WriteRune('}')
index++
fmtstr = false
} else {
temp.WriteRune(c)
}
default:
if fmtstr {
temp.WriteRune('%')
}
temp.WriteRune(c)
fmtstr = false
}
}
return temp.String()
}
func errorMessage(msg string, params ...interface{}) (string, httputils.Error) {
fields := make([]string, len(params))
for i, v := range params {
fields[i] = fmt.Sprint(v)
}
error := httputils.Error{Id: msg, Fields: fields}
error := httputils.Error{Id: msgToTemplate(msg), Fields: fields}
if len(params) > 0 {
msg = fmt.Sprintf(msg, params...)
}
+34
View File
@@ -50,3 +50,37 @@ func TestVariadic(t *testing.T) {
})
}
}
func TestMsgToTemplate(t *testing.T) {
cases := []struct {
name string
msg string
params []interface{}
out string
}{
{
name: "non-empty msg to template",
msg: "%% baremetals %s delete.time %d%",
out: "% baremetals {0} delete.time {1}%",
},
{
name: "empty msg to template",
msg: "",
out: "",
},
{
name: "non-empty with zh-utf8 characters msg to template",
msg: "%% baremetals %s 中文%d ¥%%",
out: "% baremetals {0} 中文{1} ¥%",
},
}
for _, c := range cases{
t.Run(c.name, func(t *testing.T) {
resp := msgToTemplate(c.msg)
if resp != c.out {
t.Errorf("want %s, got %s", c.out, resp)
}
})
}
}
+8
View File
@@ -148,3 +148,11 @@ func NewWebsocketManager(keyword, keywordPlural string, columns, adminColumns []
serviceType: "websocket"},
Keyword: keyword, KeywordPlural: keywordPlural}
}
func NewCloudmetaManager(keyword, keywordPlural string, columns, adminColumns []string) ResourceManager {
return ResourceManager{
BaseManager: BaseManager{columns: columns,
adminColumns: adminColumns,
serviceType: "cloudmeta"},
Keyword: keyword, KeywordPlural: keywordPlural}
}
+13
View File
@@ -0,0 +1,13 @@
package modules
var (
Cloudmeta ResourceManager
)
func init() {
Cloudmeta = NewCloudmetaManager("cloudmeta", "cloudmetas",
[]string{},
[]string{})
register(&Cloudmeta)
}
+28
View File
@@ -0,0 +1,28 @@
package modules
type RouteTableManager struct {
ResourceManager
}
var (
RouteTables RouteTableManager
)
func init() {
RouteTables = RouteTableManager{
NewComputeManager(
"route_table",
"route_tables",
[]string{
"id",
"name",
"type",
"vpc",
"vpc_id",
"routes",
},
[]string{"tenant"},
),
}
registerCompute(&RouteTables)
}
+17
View File
@@ -0,0 +1,17 @@
package modules
var (
ServerSkus ResourceManager
)
func init() {
ServerSkus = NewComputeManager("serversku",
"serverskus",
[]string{"id", "name", "sku_id",
"sku_family", "cpu_core_count", "memory_size_mb",
"cloudregion_id", "zone_id",
},
[]string{})
registerComputeV2(&ServerSkus)
}
+133
View File
@@ -0,0 +1,133 @@
package options
import (
"fmt"
"yunion.io/x/jsonutils"
)
type Route struct {
Type string
Cidr string
NextHopType string
NextHopId string
}
type Routes []*Route
type RoutesOptions struct {
RouteType []string
RouteCidr []string
RouteNextHopType []string
RouteNextHopId []string
}
func (opts *RoutesOptions) Params() (jsonutils.JSONObject, error) {
len0 := len(opts.RouteType)
len1 := len(opts.RouteCidr)
if len0 != len1 || len0 != len(opts.RouteNextHopType) || len1 != len(opts.RouteNextHopId) {
return nil, fmt.Errorf("there must be equal number of options of --route-xxx")
}
routes := []*Route{}
for i := 0; i < len0; i++ {
routes = append(routes, &Route{
Type: opts.RouteType[i],
Cidr: opts.RouteCidr[i],
NextHopType: opts.RouteNextHopType[i],
NextHopId: opts.RouteNextHopId[i],
})
}
routesJson := jsonutils.Marshal(routes)
return routesJson, nil
}
type RouteTableCreateOptions struct {
NAME string
Vpc string
RoutesOptions
}
func (opts *RouteTableCreateOptions) Params() (*jsonutils.JSONDict, error) {
params, err := optionsStructToParams(opts)
if err != nil {
return nil, err
}
routesJson, err := opts.RoutesOptions.Params()
if err != nil {
return nil, err
}
params.Set("routes", routesJson)
return params, nil
}
type RouteTableGetOptions struct {
ID string
}
type RouteTableUpdateOptions struct {
ID string `json:"-"`
Name string
RoutesOptions
}
func (opts *RouteTableUpdateOptions) Params() (*jsonutils.JSONDict, error) {
params, err := optionsStructToParams(opts)
if err != nil {
return nil, err
}
if len(opts.RouteCidr) != 0 {
routesJson, err := opts.RoutesOptions.Params()
if err != nil {
return nil, err
}
params.Set("routes", routesJson)
}
return params, nil
}
type RouteTableAddRoutesOptions struct {
ID string `json:"-"`
RoutesOptions
}
func (opts *RouteTableAddRoutesOptions) Params() (*jsonutils.JSONDict, error) {
if len(opts.RouteCidr) == 0 {
return nil, fmt.Errorf("nothing to add")
}
routesJson, err := opts.RoutesOptions.Params()
if err != nil {
return nil, err
}
params := jsonutils.NewDict()
params.Set("routes", routesJson)
return params, nil
}
type RouteTableDelRoutesOptions struct {
ID string `json:"-"`
RouteCidr []string
}
func (opts *RouteTableDelRoutesOptions) Params() (*jsonutils.JSONDict, error) {
if len(opts.RouteCidr) == 0 {
return nil, fmt.Errorf("nothing to del")
}
params := jsonutils.NewDict()
params.Set("cidrs", jsonutils.Marshal(opts.RouteCidr))
return params, nil
}
type RouteTableDeleteOptions struct {
ID string
}
type RouteTableListOptions struct {
Vpc string
Cloudregion string
BaseListOptions
}
+3 -1
View File
@@ -18,7 +18,7 @@ type ServerListOptions struct {
Gpu *bool `help:"Show gpu servers"`
Secgroup string `help:"Secgroup ID or Name"`
AdminSecgroup string `help:"AdminSecgroup ID or Name"`
Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure"`
Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws"`
Manager string `help:"Show servers imported from manager"`
Region string `help:"Show servers in cloudregion"`
WithEip *bool `help:"Show Servers with EIP"`
@@ -108,6 +108,8 @@ type ServerCreateOptions struct {
AllowDelete *bool `help:"Unlock server to allow deleting" json:"-"`
ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" metavar:"<SHUTDOWN_BEHAVIOR>" choices:"stop|terminate"`
AutoStart *bool `help:"Auto start server after it is created"`
Backup *bool `help:"Create server with backup server" json:"backup"`
BackupHost string `help:"Perfered host where virtual backup server should be created" json:"prefer_backup_host"`
Deploy []string `help:"Specify deploy files in virtual server file system" json:"-"`
Group []string `help:"Group of virtual server"`
Project string `help:"'Owner project ID or Name" json:"tenant"`
+9
View File
@@ -0,0 +1,9 @@
package options
type VersionListOptions struct {
Region string
}
type VersionGetOptions struct {
Service string `choices:"cloud" default:"cloud"`
}
+27 -7
View File
@@ -101,6 +101,12 @@ type SchedData struct {
// baremental
BaremetalDiskConfigs []*baremetal.BaremetalDiskConfig `json:"baremetal_disk_config"`
// vm backup schedule
// Schedule server with backup server
Backup bool `json:"backup"`
// Backup server should be scheduled
BackupHostID string `json:"backup_host_id"`
}
func NewSchedData(sjson *simplejson.Json, count int64, byTest bool) (*SchedData, error) {
@@ -150,6 +156,18 @@ func NewSchedData(sjson *simplejson.Json, count int64, byTest bool) (*SchedData,
}
}
if backupObj, ok := sjson.CheckGet("backup"); ok {
if backup, err := backupObj.Bool(); err == nil && backup {
data.Backup = true
}
}
if backupHostID, ok := sjson.CheckGet("prefer_backup_host_id"); ok {
if backHost, err := backupHostID.String(); err == nil {
data.BackupHostID = backHost
}
}
data.Candidates = candidates
err := data.reviseSchedType(sjson)
@@ -245,7 +263,9 @@ func (s *SchedData) reviseSchedType(sjson *simplejson.Json) error {
}
func (d *SchedData) SkipDirtyMarkHost() bool {
return d.IsPublicCloudProvider() || d.IsContainer || d.Hypervisor == SchedTypeContainer
skipByHypervisor := d.IsPublicCloudProvider() || d.IsContainer || d.Hypervisor == SchedTypeContainer
skipByBackup := d.Backup
return skipByHypervisor || skipByBackup
}
func (d *SchedData) IsPublicCloudProvider() bool {
@@ -818,13 +838,8 @@ type SchedResult struct {
Items []SchedResultItem `json:"scheduler"`
}
type candidateResult struct {
ID string `json:"id"`
Name string `json:"name"`
}
type SchedSuccItem struct {
Candidate SchedNormalResultItem `json:"candidate"`
Candidate interface{} `json:"candidate"`
}
type SchedErrItem struct {
@@ -837,6 +852,11 @@ type SchedNormalResultItem struct {
Data map[string]interface{} `json:"data"`
}
type SchedBackupResultItem struct {
MasterID string `json:"master_id"`
SlaveID string `json:"slave_id"`
}
type SchedTestResult struct {
Data interface{} `json:"data"`
Total int64 `json:"total"`
+20 -1
View File
@@ -195,7 +195,8 @@ type HostBuilder struct {
storageDict map[string]interface{}
storageStatesSizeDict map[string]map[string]interface{}
hostGuests map[string][]interface{}
hostGuests map[string][]interface{}
hostBackupGuests map[string][]interface{}
groupGuests []interface{}
groups []interface{}
@@ -681,6 +682,19 @@ func (b *HostBuilder) setGuests(ids []string, errMessageChannel chan error) {
errMessageChannel <- err
return
}
hostBackupGuests, err := utils.GroupBy(guests, func(obj interface{}) (string, error) {
gst, ok := obj.(*models.Guest)
if !ok {
return "", utils.ConvertError(obj, "*models.Guest")
}
return gst.BackupHostID, nil
})
if err != nil {
errMessageChannel <- err
return
}
guestDict, err := utils.ToDict(guests, func(obj interface{}) (string, error) {
gst, ok := obj.(*models.Guest)
if !ok {
@@ -695,6 +709,7 @@ func (b *HostBuilder) setGuests(ids []string, errMessageChannel chan error) {
b.guestIDs = guestIDs
b.guests = guests
b.hostGuests = hostGuests
b.hostBackupGuests = hostBackupGuests
b.guestDict = guestDict
return
}
@@ -1021,6 +1036,10 @@ func (b *HostBuilder) fillGuestsResourceInfo(desc *HostDesc, host *models.Host)
if !ok {
guestsOnHost = []interface{}{}
}
backupGuestsOnHost, ok := b.hostBackupGuests[host.ID]
if ok {
guestsOnHost = append(guestsOnHost, backupGuestsOnHost...)
}
for _, gst := range guestsOnHost {
guest := gst.(*models.Guest)
+32 -15
View File
@@ -1,6 +1,7 @@
package core
import (
"encoding/json"
"fmt"
"sort"
"strings"
@@ -85,7 +86,7 @@ func NewGenericScheduler(s Scheduler) (*GenericScheduler, error) {
return g, nil
}
func (g *GenericScheduler) Schedule(unit *Unit, candidates []Candidater) ([]*SchedResultItem, error) {
func (g *GenericScheduler) Schedule(unit *Unit, candidates []Candidater) (*SchedResultItemList, error) {
startTime := time.Now()
defer func() {
log.V(4).Infof("Schedule cost time: %v", time.Since(startTime))
@@ -157,7 +158,7 @@ func (g *GenericScheduler) Schedule(unit *Unit, candidates []Candidater) ([]*Sch
g.DirtySelectedCandidates(selectedCandidates)
}
return resultItems, nil
return &SchedResultItemList{Unit: unit, Data: resultItems}, nil
}
func newSchedResultByCtx(u *Unit, count int64, c Candidater) *SchedResultItem {
@@ -270,26 +271,38 @@ func (its SchedResultItemList) Len() int {
return len(its.Data)
}
func (its *SchedResultItemList) Swap(i, j int) {
its.Data[i], its.Data[j] = its.Data[j], its.Data[i]
}
func (its SchedResultItemList) Less(i, j int) bool {
it1, it2 := its.Data[i], its.Data[j]
ctx := its.Unit
return it1.Capacity < it2.Capacity
/*
ctx := its.Unit
m := func(c int64) int64 {
if c > 0 {
return 1
m := func(c int64) int64 {
if c > 0 {
return 1
}
return 0
}
return 0
}
v := func(count, capacity, score int64) int64 {
return (m(count) << 42) | (m(capacity) << 21) | score
}
v := func(count, capacity, score int64) int64 {
return (m(count) << 42) | (m(capacity) << 21) | score
}
count1, count2 := it1.Count, it2.Count
capacity1, capacity2 := ctx.GetCapacity(it1.ID), ctx.GetCapacity(it2.ID)
score1, score2 := int64(ctx.GetScore(it1.ID)), int64(ctx.GetScore(it2.ID))
count1, count2 := it1.Count, it2.Count
capacity1, capacity2 := ctx.GetCapacity(it1.ID), ctx.GetCapacity(it2.ID)
score1, score2 := int64(ctx.GetScore(it1.ID)), int64(ctx.GetScore(it2.ID))
return v(count1, capacity1, score1) < v(count2, capacity2, score2)
return v(count1, capacity1, score1) < v(count2, capacity2, score2)
*/
}
func (its SchedResultItemList) String() string {
bytes, _ := json.Marshal(its.Data)
return string(bytes)
}
type SelectedCandidate struct {
@@ -301,6 +314,10 @@ func (s SelectedCandidate) Index() (string, error) {
return s.Candidate.IndexKey(), nil
}
func (s SelectedCandidate) GetCount() uint64 {
return uint64(s.Count)
}
// SelectHosts takes a prioritized list of candidates and then picks
// a group of hosts
func SelectHosts(unit *Unit, priorityList HostPriorityList) ([]*SelectedCandidate, error) {
@@ -335,10 +335,13 @@ func (cm *CandidateManager) ReloadAll(resType string) ([]interface{}, error) {
return impl.ReloadAll()
}
func (cm *CandidateManager) SetCandidatesDirty(scs []*core.SelectedCandidate) {
for _, sc := range scs {
cm.dirtyPool.Add(sc, uint64(sc.Count))
}
type IDirtyPoolItem interface {
ttlpool.Item
GetCount() uint64
}
func (cm *CandidateManager) SetCandidateDirty(item IDirtyPoolItem) {
cm.dirtyPool.Add(item, item.GetCount())
}
func (cm *CandidateManager) CleanDirtyCandidatesOnce(keys []string) {
+1
View File
@@ -119,6 +119,7 @@ type Guest struct {
ShutdownBehavior string `json:"shutdown_behavior,omitempty" gorm:"column:shutdown_behavior"`
KeypairID string `json:"keypair_id,omitempty" gorm:"column:keypair_id"`
HostID string `json:"host_id,omitempty" gorm:"column:host_id"`
BackupHostID string `json:"backup_host_id,omitempty" gorm:"column:backup_host_id"`
VNCPort int64 `json:"vnc_port,omitempty" gorm:"column:vnc_port"`
VGA string `json:"vga" gorm:"column:vga"`
FlavorID string `json:"flavor_id,omitempty" gorm:"column:flavor_id"`
+16 -1
View File
@@ -6,6 +6,8 @@ import (
"github.com/jinzhu/gorm"
"yunion.io/x/log"
o "yunion.io/x/onecloud/cmd/scheduler/options"
)
@@ -65,7 +67,20 @@ func GetStorageCapacities(storageIDs []string) ([]StorageCapacity, error) {
Select("storage_id, status, sum(disk_size) as total_size").
Where(fmt.Sprintf("storage_id in ('%s') and deleted=0", strings.Join(storageIDs, "','"))).
Group("storage_id, status").Scan(&results).Error
return results, err
if err != nil {
return nil, err
}
backupResults := make([]StorageCapacity, 0)
err = Disks.DB().Table(disksTable).
Select("backup_storage_id as storage_id, status, sum(disk_size) as total_size").
Where(fmt.Sprintf("storage_id in ('%s') and deleted=0", strings.Join(storageIDs, "','"))).
Group("storage_id, status").Scan(&backupResults).Error
if err != nil {
log.Errorf("Get backup storage error: %v", err)
return results, nil
}
results = append(results, backupResults...)
return results, nil
}
func (s Storage) OverCommitBound() float64 {
+126
View File
@@ -0,0 +1,126 @@
package handler
import (
"fmt"
"sort"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/scheduler/api"
"yunion.io/x/onecloud/pkg/scheduler/core"
schedman "yunion.io/x/onecloud/pkg/scheduler/manager"
)
func transToBackupSchedResult(result *core.SchedResultItemList, preferBackupHost string, count int64) interface{} {
// clean each result sched result item's count
for _, item := range result.Data {
item.Count = 0
}
apiResults := newBackupSchedResult(result, preferBackupHost, count)
return regionResponse(apiResults)
}
func newBackupSchedResult(result *core.SchedResultItemList, preferBackupHost string, count int64) []api.SchedResultItem {
apiResults := make([]api.SchedResultItem, 0)
for i := 0; i < int(count); i++ {
log.V(10).Debugf("Select backup host from result: %s", result)
target, err := getSchedBackupResult(result, preferBackupHost)
if err != nil {
apiResults = append(apiResults, api.SchedErrItem{Error: err.Error()})
continue
}
apiResults = append(apiResults, api.SchedSuccItem{Candidate: target})
}
return apiResults
}
func getSchedBackupResult(result *core.SchedResultItemList, preferBackupHost string) (*api.SchedBackupResultItem, error) {
masterHost := selectMasterHost(result.Data, preferBackupHost)
if masterHost == nil {
return nil, fmt.Errorf("Can't find master host")
}
backupHost := selectBackupHost(masterHost.ID, preferBackupHost, result.Data)
if backupHost == nil {
return nil, fmt.Errorf("Can't find backup host by master %s", masterHost.ID)
}
markHostUsed(masterHost)
markHostUsed(backupHost)
sort.Sort(sort.Reverse(result))
ret := &api.SchedBackupResultItem{
MasterID: masterHost.ID,
SlaveID: backupHost.ID,
}
return ret, nil
}
func markHostUsed(host *core.SchedResultItem) {
host.Count++
host.Capacity--
setHostDirty(host)
}
// selectMasterID find master host id run VM
// return nil if not found
func selectMasterHost(result []*core.SchedResultItem, preferBackupHost string) *core.SchedResultItem {
if len(result) == 0 {
return nil
}
host := result[0]
if host.Capacity >= 1 && host.ID != preferBackupHost {
return host
}
if len(result) == 1 {
return nil
}
restHosts := result[1:]
return selectMasterHost(restHosts, preferBackupHost)
}
func selectBackupHost(masterID, preferBackupHost string, result []*core.SchedResultItem) *core.SchedResultItem {
if len(result) == 0 {
return nil
}
firstHost := result[0]
if canHostAsBackup(masterID, preferBackupHost, firstHost) {
return firstHost
}
if len(result) == 1 {
return nil
}
restHosts := result[1:]
return selectBackupHost(masterID, preferBackupHost, restHosts)
}
func canHostAsBackup(masterID, preferBackupHost string, host *core.SchedResultItem) bool {
if host.ID == masterID {
return false
}
if host.Capacity == 0 {
return false
}
if preferBackupHost != "" {
if host.ID != preferBackupHost {
return false
}
}
return true
}
type dirtyItemAdapter struct {
*core.SchedResultItem
}
func (a *dirtyItemAdapter) Index() (string, error) {
return a.ID, nil
}
func (a *dirtyItemAdapter) GetCount() uint64 {
return uint64(a.Count)
}
func setHostDirty(host *core.SchedResultItem) {
schedman.GetCandidateManager().SetCandidateDirty(&dirtyItemAdapter{SchedResultItem: host})
}
+12 -4
View File
@@ -108,10 +108,10 @@ func doSchedulerTest(c *gin.Context) {
c.JSON(http.StatusOK, transToSchedTestResult(result, schedInfo.SuggestionLimit))
}
func transToSchedTestResult(result []*core.SchedResultItem, limit int64) interface{} {
func transToSchedTestResult(result *core.SchedResultItemList, limit int64) interface{} {
return &api.SchedTestResult{
Data: result,
Total: int64(len(result)),
Data: result.Data,
Total: int64(result.Len()),
Limit: limit,
Offset: 0,
}
@@ -258,7 +258,15 @@ func doSyncSchedule(c *gin.Context) {
return
}
c.JSON(http.StatusOK, transToRegionSchedResult(result, schedInfo.Data.Count))
count := schedInfo.Data.Count
var resp interface{}
if schedInfo.Data.Backup {
resp = transToBackupSchedResult(result, schedInfo.Data.BackupHostID, count)
} else {
resp = transToRegionSchedResult(result.Data, count)
}
c.JSON(http.StatusOK, resp)
}
func transToRegionSchedResult(result []*core.SchedResultItem, count int64) interface{} {
+2 -2
View File
@@ -87,7 +87,7 @@ func (sm *SchedulerManager) start() {
}
}
func (sm *SchedulerManager) schedule(info *api.SchedInfo) ([]*core.SchedResultItem, error) {
func (sm *SchedulerManager) schedule(info *api.SchedInfo) (*core.SchedResultItemList, error) {
log.V(10).Infof("SchedulerManager do schedule, input: %#v", info)
task, err := sm.TaskManager.AddTask(sm, info)
if err != nil {
@@ -112,7 +112,7 @@ func NewSessionID() string {
// Schedule process the request data that is scheduled for dispatch and complements
// the session information.
func Schedule(info *api.SchedInfo) ([]*core.SchedResultItem, error) {
func Schedule(info *api.SchedInfo) (*core.SchedResultItemList, error) {
if len(info.SessionID) == 0 {
info.SessionID = NewSessionID()
}
+3 -1
View File
@@ -137,7 +137,9 @@ func (s *BaseScheduler) BeforePredicate() error {
}
func (s *BaseScheduler) DirtySelectedCandidates(scs []*core.SelectedCandidate) {
s.CandidateManager().SetCandidatesDirty(scs)
for _, sc := range scs {
s.CandidateManager().SetCandidateDirty(sc)
}
}
// GuestScheduler for guest type schedule
+7 -8
View File
@@ -30,7 +30,7 @@ type TaskExecutor struct {
callback TaskExecuteCallback
unit *core.Unit
resultItems []*core.SchedResultItem
resultItems *core.SchedResultItemList
resultError error
logs []string
completed bool
@@ -63,7 +63,7 @@ func (te *TaskExecutor) Execute() {
}
}
func (te *TaskExecutor) execute() ([]*core.SchedResultItem, error) {
func (te *TaskExecutor) execute() (*core.SchedResultItemList, error) {
scheduler := te.scheduler
genericScheduler, err := core.NewGenericScheduler(scheduler.(core.Scheduler))
if err != nil {
@@ -92,7 +92,7 @@ func (te *TaskExecutor) Kill() {
}
}
func (te *TaskExecutor) GetResult() ([]*core.SchedResultItem, error) {
func (te *TaskExecutor) GetResult() (*core.SchedResultItemList, error) {
return te.resultItems, te.resultError
}
@@ -254,7 +254,7 @@ type Task struct {
waitCh chan struct{}
completedCount int
resultItems []*core.SchedResultItem
resultItems *core.SchedResultItemList
resultError error
}
@@ -266,7 +266,6 @@ func NewTask(manager *SchedulerManager, schedInfo *api.SchedInfo) *Task {
taskExecutors: []*TaskExecutor{},
lock: sync.Mutex{},
waitCh: make(chan struct{}),
resultItems: []*core.SchedResultItem{},
resultError: nil,
}
}
@@ -312,7 +311,7 @@ func (t *Task) onTaskCompleted(taskExecutor *TaskExecutor) {
t.resultError = taskExecutor.resultError
t.onError()
} else {
t.resultItems = append(t.resultItems, taskExecutor.resultItems...)
t.resultItems = taskExecutor.resultItems
t.completedCount += 1
if t.completedCount >= len(t.taskExecutors) {
t.onCompleted()
@@ -349,12 +348,12 @@ func (t *Task) onCompleted() {
close(t.waitCh)
}
func (t *Task) Wait() ([]*core.SchedResultItem, error) {
func (t *Task) Wait() (*core.SchedResultItemList, error) {
log.V(10).Infof("Task wait...")
<-t.waitCh
return t.GetResult()
}
func (t *Task) GetResult() ([]*core.SchedResultItem, error) {
func (t *Task) GetResult() (*core.SchedResultItemList, error) {
return t.resultItems, t.resultError
}
+6 -5
View File
@@ -16,7 +16,8 @@ const (
ALIYUN_DEFAULT_REGION = "cn-hangzhou"
ALIYUN_API_VERSION = "2014-05-26"
ALIYUN_API_VERSION = "2014-05-26"
ALIYUN_API_VERSION_VPC = "2016-04-28"
ALIYUN_BSS_API_VERSION = "2017-12-14"
@@ -40,7 +41,7 @@ func NewAliyunClient(providerId string, providerName string, accessKey string, s
return &client, nil
}
func jsonRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
func ecsRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
return _jsonRequest(client, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params)
}
@@ -83,16 +84,16 @@ func (self *SAliyunClient) getDefaultClient() (*sdk.Client, error) {
return sdk.NewClientWithAccessKey(ALIYUN_DEFAULT_REGION, self.accessKey, self.secret)
}
func (self *SAliyunClient) jsonRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
func (self *SAliyunClient) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := self.getDefaultClient()
if err != nil {
return nil, err
}
return jsonRequest(cli, apiName, params)
return ecsRequest(cli, apiName, params)
}
func (self *SAliyunClient) fetchRegions() error {
body, err := self.jsonRequest("DescribeRegions", map[string]string{"AcceptLanguage": "zh-CN"})
body, err := self.ecsRequest("DescribeRegions", map[string]string{"AcceptLanguage": "zh-CN"})
if err != nil {
log.Errorf("fetchRegions fail %s", err)
return err
+2
View File
@@ -9,12 +9,14 @@ import (
// InstanceBandwidthRx":26214400,"InstanceBandwidthTx":26214400,"InstancePpsRx":4500000,"InstancePpsTx":4500000
type SInstanceType struct {
BaselineCredit int
CpuCoreCount int
MemorySize float32
EniQuantity int // 实例规格支持网卡数量
GPUAmount int
GPUSpec string
InstanceTypeFamily string
InstanceFamilyLevel string
InstanceTypeId string
LocalStorageCategory string
LocalStorageAmount int
+7 -7
View File
@@ -18,7 +18,7 @@ import (
type SRegion struct {
client *SAliyunClient
ecsClient *sdk.Client
sdkClient *sdk.Client
ossClient *oss.Client
RegionId string
@@ -45,15 +45,15 @@ func (self *SRegion) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SRegion) getEcsClient() (*sdk.Client, error) {
if self.ecsClient == nil {
func (self *SRegion) getSdkClient() (*sdk.Client, error) {
if self.sdkClient == nil {
cli, err := sdk.NewClientWithAccessKey(self.RegionId, self.client.accessKey, self.client.secret)
if err != nil {
return nil, err
}
self.ecsClient = cli
self.sdkClient = cli
}
return self.ecsClient, nil
return self.sdkClient, nil
}
// oss endpoint
@@ -80,11 +80,11 @@ func (self *SRegion) GetOssClient() (*oss.Client, error) {
}
func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cli, err := self.getEcsClient()
client, err := self.getSdkClient()
if err != nil {
return nil, err
}
return jsonRequest(cli, apiName, params)
return _jsonRequest(client, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params)
}
/////////////////////////////////////////////////////////////////////////////
+191 -9
View File
@@ -1,7 +1,13 @@
package aliyun
import (
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
// {"CreationTime":"2017-03-19T13:37:40Z","RouteEntrys":{"RouteEntry":[{"DestinationCidrBlock":"172.31.32.0/20","InstanceId":"","NextHopType":"local","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"},{"DestinationCidrBlock":"100.64.0.0/10","InstanceId":"","NextHopType":"service","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"}]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableType":"System","VRouterId":"vrt-j6c00qrol733dg36iq4qj"}
@@ -11,23 +17,199 @@ type SNextHops struct {
}
type SRouteEntry struct {
DestinationCidrBlock string
InstanceId string
NextHopType string
NextHops SNextHops
routeTable *SRouteTable
RouteTableId string
Status string
Type string
DestinationCidrBlock string
NextHopType string
InstanceId string
NextHops SNextHops
}
func (route *SRouteEntry) GetType() string {
return route.Type
}
func (route *SRouteEntry) GetCidr() string {
return route.DestinationCidrBlock
}
func (route *SRouteEntry) GetNextHopType() string {
return route.NextHopType
}
func (route *SRouteEntry) GetNextHop() string {
return route.InstanceId
}
type SRouteEntrys struct {
RouteEntry []SRouteEntry
RouteEntry []*SRouteEntry
}
type SRouteTable struct {
CreationTime time.Time
RouteEntrys SRouteEntrys
region *SRegion
vpc *SVpc
routes []cloudprovider.ICloudRoute
VpcId string
CreationTime time.Time
RouteEntrys SRouteEntrys
VRouterId string
Description string
RouteTableId string
RouteTableName string
RouteTableType string
VRouterId string
RouterId string
RouterType string
VSwitchIds SRouteTableVSwitchIds
}
type SRouteTableVSwitchIds struct {
VSwitchId []string
}
type sDescribeRouteTablesResponseRouteTables struct {
RouteTable []SRouteTable
}
type sDescribeRouteTablesResponse struct {
RouteTables sDescribeRouteTablesResponseRouteTables
TotalCount int
}
func (self *SRouteTable) GetDescription() string {
return self.Description
}
func (self *SRouteTable) GetId() string {
return self.GetGlobalId()
}
func (self *SRouteTable) GetGlobalId() string {
return self.RouteTableId
}
func (self *SRouteTable) GetManagerId() string {
return self.region.client.providerId
}
func (self *SRouteTable) GetName() string {
return self.RouteTableName
}
func (self *SRouteTable) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SRouteTable) GetRegionId() string {
return self.region.RegionId
}
func (self *SRouteTable) GetType() string {
return self.RouteTableType
}
func (self *SRouteTable) GetVpcId() string {
return self.VpcId
}
func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) {
if self.routes == nil {
err := self.fetchRoutes()
if err != nil {
return nil, err
}
}
return self.routes, nil
}
func (self *SRouteTable) GetStatus() string {
return ""
}
func (self *SRouteTable) IsEmulated() bool {
return false
}
func (self *SRouteTable) Refresh() error {
return nil
}
func (self *SRouteTable) fetchRoutes() error {
routes := make([]*SRouteEntry, 0)
for {
parts, total, err := self.RemoteGetRoutes(len(routes), 50)
if err != nil {
return err
}
routes = append(routes, parts...)
if len(routes) >= total {
break
}
}
self.routes = make([]cloudprovider.ICloudRoute, len(routes))
for i := 0; i < len(routes); i++ {
routes[i].routeTable = self
self.routes[i] = routes[i]
}
return nil
}
func (self *SRouteTable) RemoteGetRoutes(offset int, limit int) ([]*SRouteEntry, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RouteTableId"] = self.RouteTableId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
body, err := self.region.ecsRequest("DescribeRouteTables", params)
if err != nil {
log.Errorf("RemoteGetRoutes fail %s", err)
return nil, 0, err
}
resp := sDescribeRouteTablesResponse{}
err = body.Unmarshal(&resp)
if err != nil {
log.Errorf("Unmarshal routeEntrys fail %s", err)
return nil, 0, err
}
routeTables := resp.RouteTables.RouteTable
if len(routeTables) != 1 {
return nil, 0, fmt.Errorf("expecting 1 route table, got %d", len(routeTables))
}
routeTable := routeTables[0]
return routeTable.RouteEntrys.RouteEntry, resp.TotalCount, nil
}
func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["VpcId"] = self.VpcId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
body, err := self.apiRequest("DescribeRouteTableList", params)
if err != nil {
log.Errorf("RemoteGetRouteTableList fail %s", err)
return nil, 0, err
}
routeTables := make([]*SRouteTable, 0)
err = body.Unmarshal(&routeTables, "RouterTableList", "RouterTableListType")
if err != nil {
log.Errorf("Unmarshal routeTables fail %s", err)
return nil, 0, err
}
for _, routeTable := range routeTables {
routeTable.region = self.region
}
total, _ := body.Int("TotalCount")
return routeTables, int(total), nil
}
+40 -1
View File
@@ -29,7 +29,8 @@ type SVpc struct {
iwires []cloudprovider.ICloudWire
secgroups []cloudprovider.ICloudSecurityGroup
secgroups []cloudprovider.ICloudSecurityGroup
routeTables []cloudprovider.ICloudRouteTable
CidrBlock string
CreationTime time.Time
@@ -44,6 +45,14 @@ type SVpc struct {
VpcName string
}
func (self *SVpc) apiRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
client, err := self.region.getSdkClient()
if err != nil {
return nil, err
}
return _jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, action, params)
}
func (self *SVpc) GetMetadata() *jsonutils.JSONDict {
return nil
}
@@ -182,6 +191,36 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err
return self.secgroups, nil
}
func (self *SVpc) fetchRouteTables() error {
routeTables := make([]*SRouteTable, 0)
for {
parts, total, err := self.RemoteGetRouteTableList(len(routeTables), 50)
if err != nil {
return err
}
routeTables = append(routeTables, parts...)
if len(routeTables) >= total {
break
}
}
self.routeTables = make([]cloudprovider.ICloudRouteTable, len(routeTables))
for i := 0; i < len(routeTables); i++ {
routeTables[i].vpc = self
self.routeTables[i] = routeTables[i]
}
return nil
}
func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
if self.routeTables == nil {
err := self.fetchRouteTables()
if err != nil {
return nil, err
}
}
return self.routeTables, nil
}
func (self *SVpc) GetManagerId() string {
return self.region.client.providerId
}
+2 -1
View File
@@ -1,7 +1,7 @@
package aws
import (
"github.com/coredns/coredns/plugin/pkg/log"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
@@ -33,6 +33,7 @@ func NewAwsClient(providerId string, providerName string, accessUrl string, acce
client := SAwsClient{providerId: providerId, providerName: providerName, accessUrl: accessUrl, accessKey: accessKey, secret: secret}
err := client.fetchRegions()
if err != nil {
log.Debugf("NewAwsClient %s", err.Error())
return nil, err
}
return &client, nil
+51 -3
View File
@@ -27,7 +27,7 @@ type SDisk struct {
DiskId string // VolumeId
DiskName string // Tag Name
Size int // Size
Size int // Size GB
Category string // VolumeType
Type string // system | data
Status string // State
@@ -338,6 +338,7 @@ func (self *SRegion) DeleteDisk(diskId string) error {
}
params.SetVolumeId(diskId)
log.Debugf("DeleteDisk with params: %s", params.String())
_, err = self.ec2Client.DeleteVolume(params)
return err
}
@@ -365,8 +366,49 @@ func (self *SRegion) resizeDisk(diskId string, size int64) error {
}
func (self *SRegion) resetDisk(diskId, snapshotId string) error {
// aws貌似不支持直接重置
return cloudprovider.ErrNotImplemented
// 这里实际是回滚快照
disk, err := self.GetDisk(diskId)
if err != nil {
log.Debugf("resetDisk %s:%s", diskId, err.Error())
return err
}
params := &ec2.CreateVolumeInput{}
params.SetSnapshotId(snapshotId)
params.SetSize(int64(disk.Size))
params.SetVolumeType(disk.Category)
params.SetAvailabilityZone(disk.ZoneId)
tags, _ := disk.Tags.GetTagSpecifications()
params.SetTagSpecifications([]*ec2.TagSpecification{tags})
ret, err := self.ec2Client.CreateVolume(params)
if err != nil {
log.Debugf("resetDisk %s: %s", params.String(), err.Error())
return err
}
// detach disk
if disk.Status == ec2.VolumeStateInUse {
err := self.DetachDisk(disk.InstanceId, diskId)
if err != nil {
log.Debugf("resetDisk %s %s: %s", disk.InstanceId, diskId, err.Error())
return err
}
err = self.ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&diskId}})
if err != nil {
log.Debugf("resetDisk :%s", err.Error())
return err
}
}
err = self.AttachDisk(disk.InstanceId, *ret.VolumeId, disk.Device)
if err != nil {
log.Debugf("resetDisk %s %s %s: %s", disk.InstanceId, *ret.VolumeId, disk.Device, err.Error())
return err
}
// 绑定成功后删除原磁盘
return self.DeleteDisk(diskId)
}
func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string) (string, error) {
@@ -389,5 +431,11 @@ func (self *SRegion) CreateDisk(zoneId string, category string, name string, siz
return "", err
}
paramsWait := &ec2.DescribeVolumesInput{}
paramsWait.SetVolumeIds([]*string{ret.VolumeId})
err = self.ec2Client.WaitUntilVolumeAvailable(paramsWait)
if err != nil {
return "", err
}
return StrVal(ret.VolumeId), nil
}
+11
View File
@@ -2,6 +2,7 @@ package aws
import (
"fmt"
"strings"
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/jsonutils"
@@ -189,6 +190,8 @@ func (self *SRegion) GetImageByName(name string) (*SImage, error) {
if len(images) == 0 {
return nil, cloudprovider.ErrNotFound
}
log.Debugf("%d image found match name %", len(images), name)
return &images[0], nil
}
@@ -230,8 +233,16 @@ func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, ima
if len(imageId) > 0 {
params.SetImageIds(ConvertedList(imageId))
}
if len(filters) > 0 {
params.SetFilters(filters)
}
ret, err := self.ec2Client.DescribeImages(params)
if err != nil {
if strings.Contains(err.Error(), ".NotFound") {
return nil, 0, cloudprovider.ErrNotFound
}
return nil, 0, err
}
+17 -5
View File
@@ -5,8 +5,8 @@ import (
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/coredns/coredns/plugin/pkg/log"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/pkg/util/osprofile"
@@ -351,12 +351,18 @@ func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
}
func (self *SInstance) AttachDisk(diskId string) error {
// todo:bugfix . self.DeviceNames => self.GetDeviceNames()
name, err := NextDeviceName(self.DeviceNames)
if err != nil {
return err
}
return self.host.zone.region.AttachDisk(self.InstanceId, diskId, name)
err = self.host.zone.region.AttachDisk(self.InstanceId, diskId, name)
if err != nil {
return err
}
self.DeviceNames = append(self.DeviceNames, name)
return nil
}
func (self *SInstance) DetachDisk(diskId string) error {
@@ -388,11 +394,9 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
log.Errorf("GetInstances fail %s", err)
return nil, 0, err
}
instances := []SInstance{}
for _, reservation := range res.Reservations {
for _, instance := range reservation.Instances {
log.Debugf("GetInstances %s", instance.String())
if err := FillZero(instance); err != nil {
return nil, 0, err
}
@@ -441,8 +445,16 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
productCodes = append(productCodes, *p.ProductCodeId)
}
szone, err := self.getZoneById(*instance.Placement.AvailabilityZone)
if err != nil {
return nil, 0, err
}
host := szone.getHost()
sinstance := SInstance{
RegionId: self.RegionId,
host: host,
ZoneId: *instance.Placement.AvailabilityZone,
InstanceId: *instance.InstanceId,
ImageId: *instance.ImageId,
+23
View File
@@ -0,0 +1,23 @@
package aws
var LatitudeAndLongitude = map[string]map[string]float32{
"ap-south-1": {"latitude": 19.0759837, "longitude": 72.8776559},
"ap-northeast-3": {"latitude": 34.6937378, "longitude": 135.5021651},
"us-east-1": {"latitude": 37.4315734, "longitude": -78.6568942},
"us-east-2": {"latitude": 40.4172871, "longitude": -82.90712300000001},
"ap-southeast-2": {"latitude": -33.8688197, "longitude": 151.2092955},
"cn-northwest-1": {"latitude": 37.198731, "longitude": 106.1580937},
"eu-west-1": {"latitude": 53.41291, "longitude": -8.24389},
"eu-central-1": {"latitude": 50.1109221, "longitude": 8.6821267},
"sa-east-1": {"latitude": -23.5505199, "longitude": -46.63330939999999},
"ap-southeast-1": {"latitude": 1.352083, "longitude": 103.819836},
"ca-central-1": {"latitude": 56.130366, "longitude": -106.346771},
"ap-northeast-2": {"latitude": 37.566535, "longitude": 126.9779692},
"us-west-2": {"latitude": 43.8041334, "longitude": -120.5542012},
"us-gov-west-1": {"latitude": 37.09024, "longitude": -95.712891},
"us-west-1": {"latitude": 38.8375215, "longitude": -120.8958242},
"cn-north-1": {"latitude": 39.90419989999999, "longitude": 116.4073963},
"ap-northeast-1": {"latitude": 35.7090259, "longitude": 139.7319925},
"eu-west-2": {"latitude": 51.5073509, "longitude": -0.1277583},
"eu-west-3": {"latitude": 48.856614, "longitude": 2.3522219},
}
+76 -14
View File
@@ -2,6 +2,7 @@ package aws
import (
"fmt"
sdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
@@ -14,6 +15,28 @@ import (
"yunion.io/x/onecloud/pkg/compute/models"
)
var RegionLocations map[string]string = map[string]string{
"us-east-2": "美国东部(俄亥俄州)",
"us-east-1": "美国东部(弗吉尼亚北部)",
"us-west-1": "美国西部(加利福尼亚北部)",
"us-west-2": "美国西部(俄勒冈)",
"ap-south-1": "亚太地区(孟买)",
"ap-northeast-2": "亚太区域(首尔)",
"ap-northeast-3": "亚太区域(大阪)",
"ap-southeast-1": "亚太区域(新加坡)",
"ap-southeast-2": "亚太区域(悉尼)",
"ap-northeast-1": "亚太区域(东京)",
"ca-central-1": "加拿大(中部)",
"cn-north-1": "中国(北京)",
"cn-northwest-1": "中国(宁夏)",
"eu-central-1": "欧洲(法兰克福)",
"eu-west-1": "欧洲(爱尔兰)",
"eu-west-2": "欧洲(伦敦)",
"eu-west-3": "欧洲(巴黎)",
"sa-east-1": "南美洲(圣保罗)",
"us-gov-west-1": "AWS GovCloud(美国)",
}
type SRegion struct {
client *SAwsClient
ec2Client *ec2.EC2
@@ -36,12 +59,16 @@ func (self *SRegion) GetClient() *SAwsClient {
return self.client
}
func (self *SRegion) getAwsSession() (*session.Session, error) {
return session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
}
func (self *SRegion) getEc2Client() (*ec2.EC2, error) {
if self.ec2Client == nil {
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
s, err := self.getAwsSession()
if err != nil {
return nil, err
@@ -56,10 +83,7 @@ func (self *SRegion) getEc2Client() (*ec2.EC2, error) {
func (self *SRegion) getIamClient() (*iam.IAM, error) {
if self.iamClient == nil {
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
s, err := self.getAwsSession()
if err != nil {
return nil, err
@@ -73,10 +97,7 @@ func (self *SRegion) getIamClient() (*iam.IAM, error) {
func (self *SRegion) getS3Client() (*s3.S3, error) {
if self.s3Client == nil {
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
s, err := self.getAwsSession()
if err != nil {
return nil, err
@@ -164,6 +185,10 @@ func (self *SRegion) GetId() string {
}
func (self *SRegion) GetName() string {
if localName, ok := RegionLocations[self.RegionId]; ok {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, localName)
}
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, self.RegionId)
}
@@ -188,11 +213,27 @@ func (self *SRegion) GetMetadata() *jsonutils.JSONDict {
}
func (self *SRegion) GetLatitude() float32 {
return 0.0
if data, ok := LatitudeAndLongitude[self.RegionId]; !ok {
log.Debugf("Region %s not found in LatitudeAndLongitude", self.RegionId)
return 0.0
} else if lat, ok := data["latitude"]; !ok {
log.Debugf("Region %s's latitude not found in LatitudeAndLongitude", self.RegionId)
return 0.0
} else {
return lat
}
}
func (self *SRegion) GetLongitude() float32 {
return 0.0
if data, ok := LatitudeAndLongitude[self.RegionId]; !ok {
log.Debugf("Region %s not found in LatitudeAndLongitude", self.RegionId)
return 0.0
} else if lat, ok := data["longitude"]; !ok {
log.Debugf("Region %s's latitude not found in LatitudeAndLongitude", self.RegionId)
return 0.0
} else {
return lat
}
}
func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
@@ -320,11 +361,32 @@ func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStorag
}
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
tagspec := TagSpec{ResourceType: "vpc"}
if len(name) > 0 {
tagspec.SetNameTag(name)
}
if len(desc) > 0 {
tagspec.SetDescTag(desc)
}
spec, err := tagspec.GetTagSpecifications()
if err != nil {
return nil, err
}
// start create vpc
vpc, err := self.ec2Client.CreateVpc(&ec2.CreateVpcInput{CidrBlock: &cidr})
if err != nil {
return nil, err
}
tagsParams := &ec2.CreateTagsInput{Resources: []*string{vpc.Vpc.VpcId}, Tags: spec.Tags}
_, err = self.ec2Client.CreateTags(tagsParams)
if err != nil {
log.Debugf("CreateIVpc add tag failed %s", err.Error())
}
err = self.fetchInfrastructure()
if err != nil {
return nil, err
+51 -41
View File
@@ -29,7 +29,7 @@ type SSecurityGroup struct {
VpcId string
SecurityGroupId string
Description string
SecurityGroupName string
SecurityGroupName string //对应tag中的name标签
Permissions []secrules.SecurityRule
Tags Tags
@@ -123,22 +123,22 @@ func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.Securi
params := &ec2.AuthorizeSecurityGroupIngressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.AuthorizeSecurityGroupIngress(params)
if err != nil {
return err
}
_, err = self.ec2Client.AuthorizeSecurityGroupIngress(params)
}
if rule.Direction == secrules.SecurityRuleEgress {
params := &ec2.AuthorizeSecurityGroupEgressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.AuthorizeSecurityGroupEgress(params)
if err != nil {
return err
}
_, err = self.ec2Client.AuthorizeSecurityGroupEgress(params)
}
return nil
if err != nil && strings.Contains(err.Error(), "InvalidPermission.Duplicate") {
log.Debugf("addSecurityGroupRule %s %s", rule.Direction, err.Error())
return nil
}
return err
}
func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
@@ -151,20 +151,19 @@ func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.Securi
params := &ec2.RevokeSecurityGroupIngressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.RevokeSecurityGroupIngress(params)
if err != nil {
return err
}
_, err = self.ec2Client.RevokeSecurityGroupIngress(params)
}
if rule.Direction == secrules.SecurityRuleEgress {
params := &ec2.RevokeSecurityGroupEgressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.RevokeSecurityGroupEgress(params)
if err != nil {
return err
}
_, err = self.ec2Client.RevokeSecurityGroupEgress(params)
}
if err != nil {
log.Debugf("delSecurityGroupRule %s %s", rule.Direction, err.Error())
return err
}
return nil
}
@@ -217,6 +216,10 @@ func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name str
}
if len(secgroupId) == 0 {
// 名称为default的安全组与aws默认安全组名冲突
if strings.ToLower(name) == "default" {
name = fmt.Sprintf("%s-%s", vpcId, name)
}
var err error
secgroupId, err = self.createSecurityGroup(vpcId, name, desc)
if err != nil {
@@ -244,8 +247,8 @@ func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name str
func (self *SRegion) createSecurityGroup(vpcId string, name string, desc string) (string, error) {
params := &ec2.CreateSecurityGroupInput{}
params.SetVpcId(vpcId)
// 这里的描述aws 上层代码拼接的描述。并非用户提交的描述,用户描述放置在Yunion本地数据库中。)
params.SetDescription(desc)
params.SetGroupName(name)
group, err := self.ec2Client.CreateSecurityGroup(params)
if err != nil {
@@ -253,6 +256,8 @@ func (self *SRegion) createSecurityGroup(vpcId string, name string, desc string)
}
tagspec := TagSpec{ResourceType: "security-group"}
tagspec.SetNameTag(name)
tagspec.SetDescTag(desc)
tags, _ := tagspec.GetTagSpecifications()
tagParams := &ec2.CreateTagsInput{}
tagParams.SetResources([]*string{group.GroupId})
@@ -353,6 +358,9 @@ func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc stri
}
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
var DeleteRules []secrules.SecurityRule
var AddRules []secrules.SecurityRule
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
return err
} else {
@@ -360,6 +368,9 @@ func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.Secur
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(secrules.SecurityRuleSet(secgroup.Permissions))
log.Debugf("local security rules %s", rules)
log.Debugf("remote security rules %s", secgroup.Permissions)
i, j := 0, 0
for i < len(rules) || j < len(secgroup.Permissions) {
if i < len(rules) && j < len(secgroup.Permissions) {
@@ -367,42 +378,41 @@ func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.Secur
ruleStr := rules[i].String()
cmp := strings.Compare(permissionStr, ruleStr)
if cmp == 0 {
if secgroup.Permissions[j].Description != rules[i].Description {
if err := self.updateSecurityGroupRuleDescription(secgroupId, &rules[i]); err != nil {
log.Errorf("updateSecurityGroupRuleDescription error %v", rules[i])
return err
}
}
DeleteRules = append(DeleteRules, secgroup.Permissions[j])
AddRules = append(AddRules, rules[i])
i += 1
j += 1
} else if cmp > 0 {
if err := self.delSecurityGroupRule(secgroupId, &secgroup.Permissions[j]); err != nil {
log.Errorf("delSecurityGroupRule error %v", secgroup.Permissions[j])
return err
}
DeleteRules = append(DeleteRules, secgroup.Permissions[j])
j += 1
} else {
if err := self.addSecurityGroupRules(secgroupId, &rules[i]); err != nil {
log.Errorf("addSecurityGroupRule error %v", rules[i])
return err
}
AddRules = append(AddRules, rules[i])
i += 1
}
} else if i >= len(rules) {
if err := self.delSecurityGroupRule(secgroupId, &secgroup.Permissions[j]); err != nil {
log.Errorf("delSecurityGroupRule error %v", secgroup.Permissions[j])
return err
}
DeleteRules = append(DeleteRules, secgroup.Permissions[j])
j += 1
} else if j >= len(secgroup.Permissions) {
if err := self.addSecurityGroupRules(secgroupId, &rules[i]); err != nil {
log.Errorf("addSecurityGroupRule error %v", rules[i])
return err
}
AddRules = append(AddRules, rules[i])
i += 1
}
}
}
for _, r := range DeleteRules {
if err := self.delSecurityGroupRule(secgroupId, &r); err != nil {
log.Errorf("delSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
for _, r := range AddRules {
if err := self.addSecurityGroupRules(secgroupId, &r); err != nil {
log.Errorf("addSecurityGroupRule %v error: %s", r, err.Error())
return err
}
}
return nil
}
+14 -6
View File
@@ -3,7 +3,9 @@ package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
@@ -11,9 +13,9 @@ import (
type SnapshotStatusType string
const (
SnapshotStatusAccomplished SnapshotStatusType = "accomplished"
SnapshotStatusProgress SnapshotStatusType = "progressing"
SnapshotStatusFailed SnapshotStatusType = "failed"
SnapshotStatusAccomplished SnapshotStatusType = "completed"
SnapshotStatusProgress SnapshotStatusType = "pending"
SnapshotStatusFailed SnapshotStatusType = "error"
)
type SSnapshot struct {
@@ -89,10 +91,11 @@ func (self *SSnapshot) GetDiskId() string {
}
func (self *SSnapshot) Delete() error {
panic("implement me")
return self.region.DeleteSnapshot(self.SnapshotId)
}
func (self *SSnapshot) GetRegionId() string {
// 这里特别注意:aws没有有uuid形式的region id
return self.region.GetId()
}
@@ -124,6 +127,10 @@ func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName
ret, err := self.ec2Client.DescribeSnapshots(params)
if err != nil {
if strings.Contains(err.Error(), "InvalidSnapshot.NotFound") {
return nil, 0, cloudprovider.ErrNotFound
}
return nil, 0, err
}
@@ -176,8 +183,9 @@ func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) {
}
params.SetDescription(desc)
_, err := self.ec2Client.CreateSnapshot(params)
return "", err
log.Debugf("CreateSnapshots with params %s", params)
ret, err := self.ec2Client.CreateSnapshot(params)
return StrVal(ret.SnapshotId), err
}
func (self *SRegion) DeleteSnapshot(snapshotId string) error {
+16 -13
View File
@@ -1,12 +1,11 @@
package aws
import (
"bytes"
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/s3"
"io/ioutil"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"strings"
"time"
"yunion.io/x/jsonutils"
@@ -148,17 +147,20 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI
return "", err
}
s3Client, err := self.region.getS3Client()
if err != nil {
return "", nil
// uploader to aws s3
input := &s3manager.UploadInput{
Bucket: &bucketName,
Key: &imageId,
Body: reader,
}
// 内存?
f, err := ioutil.ReadAll(reader)
params := &s3.PutObjectInput{}
params.SetBucket(bucketName)
params.SetKey(imageId)
params.SetBody(bytes.NewReader(f))
_, err = s3Client.PutObject(params)
awsSession, err := self.region.getAwsSession()
if err != nil {
log.Debugf("uploadImage %s", err.Error())
return "", fmt.Errorf("get aws session failed")
}
uploader := s3manager.NewUploader(awsSession)
_, err = uploader.Upload(input)
if err != nil {
return "", nil
}
@@ -183,6 +185,7 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI
imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx)
nameIdx += 1
log.Debugf("uploadImage Match remote name %s", imageName)
}
task, err := self.region.ImportImage(imageName, osArch, osType, osDist, diskFormat, bucketName, imageId)
@@ -194,6 +197,7 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI
// todo:// 等待镜像导入完成
for i := 1; i < 120; i++ {
time.Sleep(2 * time.Minute)
ret, err := self.region.ec2Client.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{ImportTaskIds: []*string{&task.TaskId}})
if err != nil {
return "", err
@@ -210,7 +214,6 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI
return *item.ImageId, nil
}
}
time.Sleep(1 * time.Minute)
}
return task.ImageId, fmt.Errorf("uploadImage uncompleted: %s", task)
+9 -1
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"net"
"reflect"
"regexp"
"strings"
"yunion.io/x/jsonutils"
@@ -295,6 +296,8 @@ func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.Ip
return rules, nil
}
// YunionSecRuleToAws 不能保证无损转换
// 规则描述如果包含中文等字符,将被丢弃掉
func YunionSecRuleToAws(rule secrules.SecurityRule) ([]*ec2.IpPermission, error) {
if rule.Action == secrules.SecurityRuleDeny {
return nil, fmt.Errorf("YunionSecRuleToAws ignored aws not supported deny rule")
@@ -304,8 +307,13 @@ func YunionSecRuleToAws(rule secrules.SecurityRule) ([]*ec2.IpPermission, error)
if iprange == "<nil>" {
return nil, fmt.Errorf("YunionSecRuleToAws ignored ipnet should not be empty")
}
description := ""
if match, err := regexp.MatchString("^[\\sa-zA-Z0-9. _:/()#,@\\]\\[+=&;{}!$*-]+$", rule.Description); err == nil && match {
description = rule.Description
}
ipranges := []*ec2.IpRange{}
ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange, Description: &rule.Description})
ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange, Description: &description})
portranges := yunionPortRangeToAws(rule)
protocol := yunionProtocolToAws(rule)
+36 -16
View File
@@ -5,7 +5,6 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -102,24 +101,17 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err
return self.secgroups, nil
}
func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
rts := []cloudprovider.ICloudRouteTable{}
return rts, nil
}
func (self *SVpc) GetManagerId() string {
return self.region.client.providerId
}
func (self *SVpc) Delete() error {
err := self.fetchSecurityGroups()
if err != nil {
log.Errorf("fetchSecurityGroup for VPC delete fail %s", err)
return err
}
for i := 0; i < len(self.secgroups); i += 1 {
secgroup := self.secgroups[i].(*SSecurityGroup)
err := self.region.deleteSecurityGroup(secgroup.SecurityGroupId)
if err != nil {
log.Errorf("deleteSecurityGroup for VPC delete fail %s", err)
return err
}
}
// 删除vpc会同步删除关联的安全组
return self.region.DeleteVpc(self.VpcId)
}
@@ -205,19 +197,44 @@ func (self *SRegion) getVpc(vpcId string) (*SVpc, error) {
}
func (self *SRegion) revokeSecurityGroup(secgroupId, instanceId string, keep bool) error {
// todo : keep ? 直接使用assignSecurityGroup 即可?
return nil
}
func (self *SRegion) assignSecurityGroup(secgroupId, instanceId string) error {
instance, err := self.GetInstance(instanceId)
if err != nil {
return err
}
for _, eth := range instance.NetworkInterfaces.NetworkInterface {
params := &ec2.ModifyNetworkInterfaceAttributeInput{}
params.SetNetworkInterfaceId(eth.NetworkInterfaceId)
params.SetGroups([]*string{&secgroupId})
_, err := self.ec2Client.ModifyNetworkInterfaceAttribute(params)
if err != nil {
return err
}
}
return nil
}
func (self *SRegion) deleteSecurityGroup(secGrpId string) error {
return nil
params := &ec2.DeleteSecurityGroupInput{}
params.SetGroupId(secGrpId)
_, err := self.ec2Client.DeleteSecurityGroup(params)
return err
}
func (self *SRegion) DeleteVpc(vpcId string) error {
return nil
params := &ec2.DeleteVpcInput{}
params.SetVpcId(vpcId)
_, err := self.ec2Client.DeleteVpc(params)
return err
}
func (self *SRegion) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) {
@@ -227,6 +244,9 @@ func (self *SRegion) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int
}
ret, err := self.ec2Client.DescribeVpcs(params)
if err != nil {
if strings.Contains(err.Error(), "InvalidVpcID.NotFound") {
return nil, 0, cloudprovider.ErrNotFound
}
return nil, 0, err
}
+5
View File
@@ -135,6 +135,11 @@ func (self *SClassicVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGro
return self.secgroups, nil
}
func (self *SClassicVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
rts := []cloudprovider.ICloudRouteTable{}
return rts, nil
}
func (self *SClassicVpc) fetchWires() error {
networks := make([]cloudprovider.ICloudNetwork, len(self.Properties.Subnets))
wire := SClassicWire{zone: self.region.izones[0].(*SZone), vpc: self}
+7 -4
View File
@@ -47,8 +47,11 @@ func (self *SRegion) GetClient() *SAzureClient {
return self.client
}
func (self *SRegion) GetVMSize() (map[string]SVMSize, error) {
body, err := self.client.ListVmSizes(self.Name)
func (self *SRegion) GetVMSize(location string) (map[string]SVMSize, error) {
if len(location) == 0 {
location = self.Name
}
body, err := self.client.ListVmSizes(location)
if err != nil {
return nil, err
}
@@ -65,7 +68,7 @@ func (self *SRegion) GetVMSize() (map[string]SVMSize, error) {
}
func (self *SRegion) getHardwareProfile(cpu, memMB int) []string {
if vmSizes, err := self.GetVMSize(); err != nil {
if vmSizes, err := self.GetVMSize(""); err != nil {
return []string{}
} else {
profiles := make([]string, 0)
@@ -79,7 +82,7 @@ func (self *SRegion) getHardwareProfile(cpu, memMB int) []string {
}
func (self *SRegion) getVMSize(size string) (*SVMSize, error) {
vmSizes, err := self.GetVMSize()
vmSizes, err := self.GetVMSize("")
if err != nil {
return nil, err
}
+146
View File
@@ -0,0 +1,146 @@
package azure
import (
"fmt"
"yunion.io/x/pkg/utils"
)
/*
{
"capabilities":[
{"name":"MaxResourceVolumeMB","value":"286720"},
{"name":"OSVhdSizeMB","value":"1047552"},
{"name":"vCPUs","value":"20"},
{"name":"MemoryGB","value":"140"},
{"name":"MaxDataDiskCount","value":"64"},
{"name":"LowPriorityCapable","value":"True"},
{"name":"PremiumIO","value":"True"},
{"name":"EphemeralOSDiskSupported","value":"True"}
],
"family":"standardDSv2Family",
"locations":["CentralUSEUAP"],
"name":"Standard_DS15_v2",
"resourceType":"virtualMachines",
"restrictions":[],
"size":"DS15_v2",
"tier":"Standard"
}
*/
type SResourceSkuCapability struct {
Name string
Value string
}
type TResourceSkuCapacityScaleType string
const (
ResourceSkuCapacityScaleTypeAutomatic = TResourceSkuCapacityScaleType("Automatic")
ResourceSkuCapacityScaleTypeManual = TResourceSkuCapacityScaleType("Manual")
ResourceSkuCapacityScaleTypeNone = TResourceSkuCapacityScaleType("None")
)
type SResourceSkuCapacity struct {
Default int
Maximum int
Minimum int
ScaleType TResourceSkuCapacityScaleType
}
type SResourceSkuLocationInfo struct {
Location string
Zones []string
}
type TResourceSkuRestrictionsType string
const (
ResourceSkuRestrictionsTypeLocation = TResourceSkuRestrictionsType("Location")
ResourceSkuRestrictionsTypeZone = TResourceSkuRestrictionsType("Zone")
)
type TResourceSkuRestrictionsReasonCode string
const (
ResourceSkuRestrictionsReasonCodeNotAvailable = TResourceSkuRestrictionsReasonCode("NotAvailableForSubscription")
ResourceSkuRestrictionsReasonCodeQuotaId = TResourceSkuRestrictionsReasonCode("QuotaId")
)
type SResourceSkuRestrictionInfo struct {
Locations []string
Zones []string
}
type SResourceSkuRestrictions struct {
ReasonCode TResourceSkuRestrictionsReasonCode
RestrictionInfo SResourceSkuRestrictionInfo
Type TResourceSkuRestrictionsType
Values []string
}
type SResourceSku struct {
Capabilities []SResourceSkuCapability
Capacity *SResourceSkuCapacity
Family string
Kind string
LocationInfo []SResourceSkuLocationInfo
Locations []string
Name string
ResourceType string
Restrictions []SResourceSkuRestrictions
Size string
Tier string
}
type SResourceSkusResult struct {
NextLink string
Value []SResourceSku
}
func (self *SAzureClient) ListResourceSkus() ([]SResourceSku, error) {
cli, err := self.getDefaultClient()
if err != nil {
return nil, err
}
if len(self.subscriptionId) == 0 {
return nil, fmt.Errorf("need subscription id")
}
url := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/skus?api-version=2017-09-01", self.subscriptionId)
skus := make([]SResourceSku, 0)
for {
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return nil, err
}
result := SResourceSkusResult{}
err = body.Unmarshal(&result)
if err != nil {
return nil, err
}
skus = append(skus, result.Value...)
if len(result.NextLink) > 0 {
url = result.NextLink
} else {
break
}
}
return skus, nil
}
func (self *SRegion) GetResourceSkus(location string) ([]SResourceSku, error) {
skus, err := self.client.ListResourceSkus()
if err != nil {
return nil, err
}
if len(location) == 0 {
return skus, nil
}
ret := make([]SResourceSku, 0)
for i := 0; i < len(skus); i += 1 {
if utils.IsInStringArray(location, skus[i].Locations) {
ret = append(ret, skus[i])
}
}
return ret, nil
}
+10 -3
View File
@@ -39,18 +39,25 @@ func init() {
})
type InstanceSizeListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
Location string
}
shellutils.R(&InstanceSizeListOptions{}, "instance-size-list", "List intances", func(cli *azure.SRegion, args *InstanceSizeListOptions) error {
if vmSize, err := cli.GetVMSize(); err != nil {
if vmSize, err := cli.GetVMSize(args.Location); err != nil {
return err
} else {
printObject(vmSize)
return nil
}
})
shellutils.R(&InstanceSizeListOptions{}, "resource-sku-list", "List resource sku", func(cli *azure.SRegion, args *InstanceSizeListOptions) error {
skus, err := cli.GetResourceSkus(args.Location)
if err != nil {
return err
}
printList(skus, len(skus), 0, 0, []string{})
return nil
})
type InstanceCrateOptions struct {
NAME string `help:"name of instance"`
+5
View File
@@ -139,6 +139,11 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err
return self.secgroups, nil
}
func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
rts := []cloudprovider.ICloudRouteTable{}
return rts, nil
}
func (self *SVpc) fetchWires() error {
networks := make([]cloudprovider.ICloudNetwork, len(*self.Properties.Subnets))
if len(self.region.izones) == 0 {
+5
View File
@@ -85,6 +85,11 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err
return isecgroups, nil
}
func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
rts := []cloudprovider.ICloudRouteTable{}
return rts, nil
}
func (self *SVpc) getWireByZoneId(zoneId string) *SWire {
for i := 0; i <= len(self.iwires); i++ {
wire := self.iwires[i].(*SWire)
+403
View File
@@ -0,0 +1,403 @@
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
// Package s3iface provides an interface to enable mocking the Amazon Simple Storage Service service client
// for testing your code.
//
// It is important to note that this interface will have breaking changes
// when the service model is updated and adds new API operations, paginators,
// and waiters.
package s3iface
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/s3"
)
// S3API provides an interface to enable mocking the
// s3.S3 service client's API operation,
// paginators, and waiters. This make unit testing your code that calls out
// to the SDK's service client's calls easier.
//
// The best way to use this interface is so the SDK's service client's calls
// can be stubbed out for unit testing your code with the SDK without needing
// to inject custom request handlers into the SDK's request pipeline.
//
// // myFunc uses an SDK service client to make a request to
// // Amazon Simple Storage Service.
// func myFunc(svc s3iface.S3API) bool {
// // Make svc.AbortMultipartUpload request
// }
//
// func main() {
// sess := session.New()
// svc := s3.New(sess)
//
// myFunc(svc)
// }
//
// In your _test.go file:
//
// // Define a mock struct to be used in your unit tests of myFunc.
// type mockS3Client struct {
// s3iface.S3API
// }
// func (m *mockS3Client) AbortMultipartUpload(input *s3.AbortMultipartUploadInput) (*s3.AbortMultipartUploadOutput, error) {
// // mock response/functionality
// }
//
// func TestMyFunc(t *testing.T) {
// // Setup Test
// mockSvc := &mockS3Client{}
//
// myfunc(mockSvc)
//
// // Verify myFunc's functionality
// }
//
// It is important to note that this interface will have breaking changes
// when the service model is updated and adds new API operations, paginators,
// and waiters. Its suggested to use the pattern above for testing, or using
// tooling to generate mocks to satisfy the interfaces.
type S3API interface {
AbortMultipartUpload(*s3.AbortMultipartUploadInput) (*s3.AbortMultipartUploadOutput, error)
AbortMultipartUploadWithContext(aws.Context, *s3.AbortMultipartUploadInput, ...request.Option) (*s3.AbortMultipartUploadOutput, error)
AbortMultipartUploadRequest(*s3.AbortMultipartUploadInput) (*request.Request, *s3.AbortMultipartUploadOutput)
CompleteMultipartUpload(*s3.CompleteMultipartUploadInput) (*s3.CompleteMultipartUploadOutput, error)
CompleteMultipartUploadWithContext(aws.Context, *s3.CompleteMultipartUploadInput, ...request.Option) (*s3.CompleteMultipartUploadOutput, error)
CompleteMultipartUploadRequest(*s3.CompleteMultipartUploadInput) (*request.Request, *s3.CompleteMultipartUploadOutput)
CopyObject(*s3.CopyObjectInput) (*s3.CopyObjectOutput, error)
CopyObjectWithContext(aws.Context, *s3.CopyObjectInput, ...request.Option) (*s3.CopyObjectOutput, error)
CopyObjectRequest(*s3.CopyObjectInput) (*request.Request, *s3.CopyObjectOutput)
CreateBucket(*s3.CreateBucketInput) (*s3.CreateBucketOutput, error)
CreateBucketWithContext(aws.Context, *s3.CreateBucketInput, ...request.Option) (*s3.CreateBucketOutput, error)
CreateBucketRequest(*s3.CreateBucketInput) (*request.Request, *s3.CreateBucketOutput)
CreateMultipartUpload(*s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error)
CreateMultipartUploadWithContext(aws.Context, *s3.CreateMultipartUploadInput, ...request.Option) (*s3.CreateMultipartUploadOutput, error)
CreateMultipartUploadRequest(*s3.CreateMultipartUploadInput) (*request.Request, *s3.CreateMultipartUploadOutput)
DeleteBucket(*s3.DeleteBucketInput) (*s3.DeleteBucketOutput, error)
DeleteBucketWithContext(aws.Context, *s3.DeleteBucketInput, ...request.Option) (*s3.DeleteBucketOutput, error)
DeleteBucketRequest(*s3.DeleteBucketInput) (*request.Request, *s3.DeleteBucketOutput)
DeleteBucketAnalyticsConfiguration(*s3.DeleteBucketAnalyticsConfigurationInput) (*s3.DeleteBucketAnalyticsConfigurationOutput, error)
DeleteBucketAnalyticsConfigurationWithContext(aws.Context, *s3.DeleteBucketAnalyticsConfigurationInput, ...request.Option) (*s3.DeleteBucketAnalyticsConfigurationOutput, error)
DeleteBucketAnalyticsConfigurationRequest(*s3.DeleteBucketAnalyticsConfigurationInput) (*request.Request, *s3.DeleteBucketAnalyticsConfigurationOutput)
DeleteBucketCors(*s3.DeleteBucketCorsInput) (*s3.DeleteBucketCorsOutput, error)
DeleteBucketCorsWithContext(aws.Context, *s3.DeleteBucketCorsInput, ...request.Option) (*s3.DeleteBucketCorsOutput, error)
DeleteBucketCorsRequest(*s3.DeleteBucketCorsInput) (*request.Request, *s3.DeleteBucketCorsOutput)
DeleteBucketEncryption(*s3.DeleteBucketEncryptionInput) (*s3.DeleteBucketEncryptionOutput, error)
DeleteBucketEncryptionWithContext(aws.Context, *s3.DeleteBucketEncryptionInput, ...request.Option) (*s3.DeleteBucketEncryptionOutput, error)
DeleteBucketEncryptionRequest(*s3.DeleteBucketEncryptionInput) (*request.Request, *s3.DeleteBucketEncryptionOutput)
DeleteBucketInventoryConfiguration(*s3.DeleteBucketInventoryConfigurationInput) (*s3.DeleteBucketInventoryConfigurationOutput, error)
DeleteBucketInventoryConfigurationWithContext(aws.Context, *s3.DeleteBucketInventoryConfigurationInput, ...request.Option) (*s3.DeleteBucketInventoryConfigurationOutput, error)
DeleteBucketInventoryConfigurationRequest(*s3.DeleteBucketInventoryConfigurationInput) (*request.Request, *s3.DeleteBucketInventoryConfigurationOutput)
DeleteBucketLifecycle(*s3.DeleteBucketLifecycleInput) (*s3.DeleteBucketLifecycleOutput, error)
DeleteBucketLifecycleWithContext(aws.Context, *s3.DeleteBucketLifecycleInput, ...request.Option) (*s3.DeleteBucketLifecycleOutput, error)
DeleteBucketLifecycleRequest(*s3.DeleteBucketLifecycleInput) (*request.Request, *s3.DeleteBucketLifecycleOutput)
DeleteBucketMetricsConfiguration(*s3.DeleteBucketMetricsConfigurationInput) (*s3.DeleteBucketMetricsConfigurationOutput, error)
DeleteBucketMetricsConfigurationWithContext(aws.Context, *s3.DeleteBucketMetricsConfigurationInput, ...request.Option) (*s3.DeleteBucketMetricsConfigurationOutput, error)
DeleteBucketMetricsConfigurationRequest(*s3.DeleteBucketMetricsConfigurationInput) (*request.Request, *s3.DeleteBucketMetricsConfigurationOutput)
DeleteBucketPolicy(*s3.DeleteBucketPolicyInput) (*s3.DeleteBucketPolicyOutput, error)
DeleteBucketPolicyWithContext(aws.Context, *s3.DeleteBucketPolicyInput, ...request.Option) (*s3.DeleteBucketPolicyOutput, error)
DeleteBucketPolicyRequest(*s3.DeleteBucketPolicyInput) (*request.Request, *s3.DeleteBucketPolicyOutput)
DeleteBucketReplication(*s3.DeleteBucketReplicationInput) (*s3.DeleteBucketReplicationOutput, error)
DeleteBucketReplicationWithContext(aws.Context, *s3.DeleteBucketReplicationInput, ...request.Option) (*s3.DeleteBucketReplicationOutput, error)
DeleteBucketReplicationRequest(*s3.DeleteBucketReplicationInput) (*request.Request, *s3.DeleteBucketReplicationOutput)
DeleteBucketTagging(*s3.DeleteBucketTaggingInput) (*s3.DeleteBucketTaggingOutput, error)
DeleteBucketTaggingWithContext(aws.Context, *s3.DeleteBucketTaggingInput, ...request.Option) (*s3.DeleteBucketTaggingOutput, error)
DeleteBucketTaggingRequest(*s3.DeleteBucketTaggingInput) (*request.Request, *s3.DeleteBucketTaggingOutput)
DeleteBucketWebsite(*s3.DeleteBucketWebsiteInput) (*s3.DeleteBucketWebsiteOutput, error)
DeleteBucketWebsiteWithContext(aws.Context, *s3.DeleteBucketWebsiteInput, ...request.Option) (*s3.DeleteBucketWebsiteOutput, error)
DeleteBucketWebsiteRequest(*s3.DeleteBucketWebsiteInput) (*request.Request, *s3.DeleteBucketWebsiteOutput)
DeleteObject(*s3.DeleteObjectInput) (*s3.DeleteObjectOutput, error)
DeleteObjectWithContext(aws.Context, *s3.DeleteObjectInput, ...request.Option) (*s3.DeleteObjectOutput, error)
DeleteObjectRequest(*s3.DeleteObjectInput) (*request.Request, *s3.DeleteObjectOutput)
DeleteObjectTagging(*s3.DeleteObjectTaggingInput) (*s3.DeleteObjectTaggingOutput, error)
DeleteObjectTaggingWithContext(aws.Context, *s3.DeleteObjectTaggingInput, ...request.Option) (*s3.DeleteObjectTaggingOutput, error)
DeleteObjectTaggingRequest(*s3.DeleteObjectTaggingInput) (*request.Request, *s3.DeleteObjectTaggingOutput)
DeleteObjects(*s3.DeleteObjectsInput) (*s3.DeleteObjectsOutput, error)
DeleteObjectsWithContext(aws.Context, *s3.DeleteObjectsInput, ...request.Option) (*s3.DeleteObjectsOutput, error)
DeleteObjectsRequest(*s3.DeleteObjectsInput) (*request.Request, *s3.DeleteObjectsOutput)
GetBucketAccelerateConfiguration(*s3.GetBucketAccelerateConfigurationInput) (*s3.GetBucketAccelerateConfigurationOutput, error)
GetBucketAccelerateConfigurationWithContext(aws.Context, *s3.GetBucketAccelerateConfigurationInput, ...request.Option) (*s3.GetBucketAccelerateConfigurationOutput, error)
GetBucketAccelerateConfigurationRequest(*s3.GetBucketAccelerateConfigurationInput) (*request.Request, *s3.GetBucketAccelerateConfigurationOutput)
GetBucketAcl(*s3.GetBucketAclInput) (*s3.GetBucketAclOutput, error)
GetBucketAclWithContext(aws.Context, *s3.GetBucketAclInput, ...request.Option) (*s3.GetBucketAclOutput, error)
GetBucketAclRequest(*s3.GetBucketAclInput) (*request.Request, *s3.GetBucketAclOutput)
GetBucketAnalyticsConfiguration(*s3.GetBucketAnalyticsConfigurationInput) (*s3.GetBucketAnalyticsConfigurationOutput, error)
GetBucketAnalyticsConfigurationWithContext(aws.Context, *s3.GetBucketAnalyticsConfigurationInput, ...request.Option) (*s3.GetBucketAnalyticsConfigurationOutput, error)
GetBucketAnalyticsConfigurationRequest(*s3.GetBucketAnalyticsConfigurationInput) (*request.Request, *s3.GetBucketAnalyticsConfigurationOutput)
GetBucketCors(*s3.GetBucketCorsInput) (*s3.GetBucketCorsOutput, error)
GetBucketCorsWithContext(aws.Context, *s3.GetBucketCorsInput, ...request.Option) (*s3.GetBucketCorsOutput, error)
GetBucketCorsRequest(*s3.GetBucketCorsInput) (*request.Request, *s3.GetBucketCorsOutput)
GetBucketEncryption(*s3.GetBucketEncryptionInput) (*s3.GetBucketEncryptionOutput, error)
GetBucketEncryptionWithContext(aws.Context, *s3.GetBucketEncryptionInput, ...request.Option) (*s3.GetBucketEncryptionOutput, error)
GetBucketEncryptionRequest(*s3.GetBucketEncryptionInput) (*request.Request, *s3.GetBucketEncryptionOutput)
GetBucketInventoryConfiguration(*s3.GetBucketInventoryConfigurationInput) (*s3.GetBucketInventoryConfigurationOutput, error)
GetBucketInventoryConfigurationWithContext(aws.Context, *s3.GetBucketInventoryConfigurationInput, ...request.Option) (*s3.GetBucketInventoryConfigurationOutput, error)
GetBucketInventoryConfigurationRequest(*s3.GetBucketInventoryConfigurationInput) (*request.Request, *s3.GetBucketInventoryConfigurationOutput)
GetBucketLifecycle(*s3.GetBucketLifecycleInput) (*s3.GetBucketLifecycleOutput, error)
GetBucketLifecycleWithContext(aws.Context, *s3.GetBucketLifecycleInput, ...request.Option) (*s3.GetBucketLifecycleOutput, error)
GetBucketLifecycleRequest(*s3.GetBucketLifecycleInput) (*request.Request, *s3.GetBucketLifecycleOutput)
GetBucketLifecycleConfiguration(*s3.GetBucketLifecycleConfigurationInput) (*s3.GetBucketLifecycleConfigurationOutput, error)
GetBucketLifecycleConfigurationWithContext(aws.Context, *s3.GetBucketLifecycleConfigurationInput, ...request.Option) (*s3.GetBucketLifecycleConfigurationOutput, error)
GetBucketLifecycleConfigurationRequest(*s3.GetBucketLifecycleConfigurationInput) (*request.Request, *s3.GetBucketLifecycleConfigurationOutput)
GetBucketLocation(*s3.GetBucketLocationInput) (*s3.GetBucketLocationOutput, error)
GetBucketLocationWithContext(aws.Context, *s3.GetBucketLocationInput, ...request.Option) (*s3.GetBucketLocationOutput, error)
GetBucketLocationRequest(*s3.GetBucketLocationInput) (*request.Request, *s3.GetBucketLocationOutput)
GetBucketLogging(*s3.GetBucketLoggingInput) (*s3.GetBucketLoggingOutput, error)
GetBucketLoggingWithContext(aws.Context, *s3.GetBucketLoggingInput, ...request.Option) (*s3.GetBucketLoggingOutput, error)
GetBucketLoggingRequest(*s3.GetBucketLoggingInput) (*request.Request, *s3.GetBucketLoggingOutput)
GetBucketMetricsConfiguration(*s3.GetBucketMetricsConfigurationInput) (*s3.GetBucketMetricsConfigurationOutput, error)
GetBucketMetricsConfigurationWithContext(aws.Context, *s3.GetBucketMetricsConfigurationInput, ...request.Option) (*s3.GetBucketMetricsConfigurationOutput, error)
GetBucketMetricsConfigurationRequest(*s3.GetBucketMetricsConfigurationInput) (*request.Request, *s3.GetBucketMetricsConfigurationOutput)
GetBucketNotification(*s3.GetBucketNotificationConfigurationRequest) (*s3.NotificationConfigurationDeprecated, error)
GetBucketNotificationWithContext(aws.Context, *s3.GetBucketNotificationConfigurationRequest, ...request.Option) (*s3.NotificationConfigurationDeprecated, error)
GetBucketNotificationRequest(*s3.GetBucketNotificationConfigurationRequest) (*request.Request, *s3.NotificationConfigurationDeprecated)
GetBucketNotificationConfiguration(*s3.GetBucketNotificationConfigurationRequest) (*s3.NotificationConfiguration, error)
GetBucketNotificationConfigurationWithContext(aws.Context, *s3.GetBucketNotificationConfigurationRequest, ...request.Option) (*s3.NotificationConfiguration, error)
GetBucketNotificationConfigurationRequest(*s3.GetBucketNotificationConfigurationRequest) (*request.Request, *s3.NotificationConfiguration)
GetBucketPolicy(*s3.GetBucketPolicyInput) (*s3.GetBucketPolicyOutput, error)
GetBucketPolicyWithContext(aws.Context, *s3.GetBucketPolicyInput, ...request.Option) (*s3.GetBucketPolicyOutput, error)
GetBucketPolicyRequest(*s3.GetBucketPolicyInput) (*request.Request, *s3.GetBucketPolicyOutput)
GetBucketReplication(*s3.GetBucketReplicationInput) (*s3.GetBucketReplicationOutput, error)
GetBucketReplicationWithContext(aws.Context, *s3.GetBucketReplicationInput, ...request.Option) (*s3.GetBucketReplicationOutput, error)
GetBucketReplicationRequest(*s3.GetBucketReplicationInput) (*request.Request, *s3.GetBucketReplicationOutput)
GetBucketRequestPayment(*s3.GetBucketRequestPaymentInput) (*s3.GetBucketRequestPaymentOutput, error)
GetBucketRequestPaymentWithContext(aws.Context, *s3.GetBucketRequestPaymentInput, ...request.Option) (*s3.GetBucketRequestPaymentOutput, error)
GetBucketRequestPaymentRequest(*s3.GetBucketRequestPaymentInput) (*request.Request, *s3.GetBucketRequestPaymentOutput)
GetBucketTagging(*s3.GetBucketTaggingInput) (*s3.GetBucketTaggingOutput, error)
GetBucketTaggingWithContext(aws.Context, *s3.GetBucketTaggingInput, ...request.Option) (*s3.GetBucketTaggingOutput, error)
GetBucketTaggingRequest(*s3.GetBucketTaggingInput) (*request.Request, *s3.GetBucketTaggingOutput)
GetBucketVersioning(*s3.GetBucketVersioningInput) (*s3.GetBucketVersioningOutput, error)
GetBucketVersioningWithContext(aws.Context, *s3.GetBucketVersioningInput, ...request.Option) (*s3.GetBucketVersioningOutput, error)
GetBucketVersioningRequest(*s3.GetBucketVersioningInput) (*request.Request, *s3.GetBucketVersioningOutput)
GetBucketWebsite(*s3.GetBucketWebsiteInput) (*s3.GetBucketWebsiteOutput, error)
GetBucketWebsiteWithContext(aws.Context, *s3.GetBucketWebsiteInput, ...request.Option) (*s3.GetBucketWebsiteOutput, error)
GetBucketWebsiteRequest(*s3.GetBucketWebsiteInput) (*request.Request, *s3.GetBucketWebsiteOutput)
GetObject(*s3.GetObjectInput) (*s3.GetObjectOutput, error)
GetObjectWithContext(aws.Context, *s3.GetObjectInput, ...request.Option) (*s3.GetObjectOutput, error)
GetObjectRequest(*s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput)
GetObjectAcl(*s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error)
GetObjectAclWithContext(aws.Context, *s3.GetObjectAclInput, ...request.Option) (*s3.GetObjectAclOutput, error)
GetObjectAclRequest(*s3.GetObjectAclInput) (*request.Request, *s3.GetObjectAclOutput)
GetObjectTagging(*s3.GetObjectTaggingInput) (*s3.GetObjectTaggingOutput, error)
GetObjectTaggingWithContext(aws.Context, *s3.GetObjectTaggingInput, ...request.Option) (*s3.GetObjectTaggingOutput, error)
GetObjectTaggingRequest(*s3.GetObjectTaggingInput) (*request.Request, *s3.GetObjectTaggingOutput)
GetObjectTorrent(*s3.GetObjectTorrentInput) (*s3.GetObjectTorrentOutput, error)
GetObjectTorrentWithContext(aws.Context, *s3.GetObjectTorrentInput, ...request.Option) (*s3.GetObjectTorrentOutput, error)
GetObjectTorrentRequest(*s3.GetObjectTorrentInput) (*request.Request, *s3.GetObjectTorrentOutput)
HeadBucket(*s3.HeadBucketInput) (*s3.HeadBucketOutput, error)
HeadBucketWithContext(aws.Context, *s3.HeadBucketInput, ...request.Option) (*s3.HeadBucketOutput, error)
HeadBucketRequest(*s3.HeadBucketInput) (*request.Request, *s3.HeadBucketOutput)
HeadObject(*s3.HeadObjectInput) (*s3.HeadObjectOutput, error)
HeadObjectWithContext(aws.Context, *s3.HeadObjectInput, ...request.Option) (*s3.HeadObjectOutput, error)
HeadObjectRequest(*s3.HeadObjectInput) (*request.Request, *s3.HeadObjectOutput)
ListBucketAnalyticsConfigurations(*s3.ListBucketAnalyticsConfigurationsInput) (*s3.ListBucketAnalyticsConfigurationsOutput, error)
ListBucketAnalyticsConfigurationsWithContext(aws.Context, *s3.ListBucketAnalyticsConfigurationsInput, ...request.Option) (*s3.ListBucketAnalyticsConfigurationsOutput, error)
ListBucketAnalyticsConfigurationsRequest(*s3.ListBucketAnalyticsConfigurationsInput) (*request.Request, *s3.ListBucketAnalyticsConfigurationsOutput)
ListBucketInventoryConfigurations(*s3.ListBucketInventoryConfigurationsInput) (*s3.ListBucketInventoryConfigurationsOutput, error)
ListBucketInventoryConfigurationsWithContext(aws.Context, *s3.ListBucketInventoryConfigurationsInput, ...request.Option) (*s3.ListBucketInventoryConfigurationsOutput, error)
ListBucketInventoryConfigurationsRequest(*s3.ListBucketInventoryConfigurationsInput) (*request.Request, *s3.ListBucketInventoryConfigurationsOutput)
ListBucketMetricsConfigurations(*s3.ListBucketMetricsConfigurationsInput) (*s3.ListBucketMetricsConfigurationsOutput, error)
ListBucketMetricsConfigurationsWithContext(aws.Context, *s3.ListBucketMetricsConfigurationsInput, ...request.Option) (*s3.ListBucketMetricsConfigurationsOutput, error)
ListBucketMetricsConfigurationsRequest(*s3.ListBucketMetricsConfigurationsInput) (*request.Request, *s3.ListBucketMetricsConfigurationsOutput)
ListBuckets(*s3.ListBucketsInput) (*s3.ListBucketsOutput, error)
ListBucketsWithContext(aws.Context, *s3.ListBucketsInput, ...request.Option) (*s3.ListBucketsOutput, error)
ListBucketsRequest(*s3.ListBucketsInput) (*request.Request, *s3.ListBucketsOutput)
ListMultipartUploads(*s3.ListMultipartUploadsInput) (*s3.ListMultipartUploadsOutput, error)
ListMultipartUploadsWithContext(aws.Context, *s3.ListMultipartUploadsInput, ...request.Option) (*s3.ListMultipartUploadsOutput, error)
ListMultipartUploadsRequest(*s3.ListMultipartUploadsInput) (*request.Request, *s3.ListMultipartUploadsOutput)
ListMultipartUploadsPages(*s3.ListMultipartUploadsInput, func(*s3.ListMultipartUploadsOutput, bool) bool) error
ListMultipartUploadsPagesWithContext(aws.Context, *s3.ListMultipartUploadsInput, func(*s3.ListMultipartUploadsOutput, bool) bool, ...request.Option) error
ListObjectVersions(*s3.ListObjectVersionsInput) (*s3.ListObjectVersionsOutput, error)
ListObjectVersionsWithContext(aws.Context, *s3.ListObjectVersionsInput, ...request.Option) (*s3.ListObjectVersionsOutput, error)
ListObjectVersionsRequest(*s3.ListObjectVersionsInput) (*request.Request, *s3.ListObjectVersionsOutput)
ListObjectVersionsPages(*s3.ListObjectVersionsInput, func(*s3.ListObjectVersionsOutput, bool) bool) error
ListObjectVersionsPagesWithContext(aws.Context, *s3.ListObjectVersionsInput, func(*s3.ListObjectVersionsOutput, bool) bool, ...request.Option) error
ListObjects(*s3.ListObjectsInput) (*s3.ListObjectsOutput, error)
ListObjectsWithContext(aws.Context, *s3.ListObjectsInput, ...request.Option) (*s3.ListObjectsOutput, error)
ListObjectsRequest(*s3.ListObjectsInput) (*request.Request, *s3.ListObjectsOutput)
ListObjectsPages(*s3.ListObjectsInput, func(*s3.ListObjectsOutput, bool) bool) error
ListObjectsPagesWithContext(aws.Context, *s3.ListObjectsInput, func(*s3.ListObjectsOutput, bool) bool, ...request.Option) error
ListObjectsV2(*s3.ListObjectsV2Input) (*s3.ListObjectsV2Output, error)
ListObjectsV2WithContext(aws.Context, *s3.ListObjectsV2Input, ...request.Option) (*s3.ListObjectsV2Output, error)
ListObjectsV2Request(*s3.ListObjectsV2Input) (*request.Request, *s3.ListObjectsV2Output)
ListObjectsV2Pages(*s3.ListObjectsV2Input, func(*s3.ListObjectsV2Output, bool) bool) error
ListObjectsV2PagesWithContext(aws.Context, *s3.ListObjectsV2Input, func(*s3.ListObjectsV2Output, bool) bool, ...request.Option) error
ListParts(*s3.ListPartsInput) (*s3.ListPartsOutput, error)
ListPartsWithContext(aws.Context, *s3.ListPartsInput, ...request.Option) (*s3.ListPartsOutput, error)
ListPartsRequest(*s3.ListPartsInput) (*request.Request, *s3.ListPartsOutput)
ListPartsPages(*s3.ListPartsInput, func(*s3.ListPartsOutput, bool) bool) error
ListPartsPagesWithContext(aws.Context, *s3.ListPartsInput, func(*s3.ListPartsOutput, bool) bool, ...request.Option) error
PutBucketAccelerateConfiguration(*s3.PutBucketAccelerateConfigurationInput) (*s3.PutBucketAccelerateConfigurationOutput, error)
PutBucketAccelerateConfigurationWithContext(aws.Context, *s3.PutBucketAccelerateConfigurationInput, ...request.Option) (*s3.PutBucketAccelerateConfigurationOutput, error)
PutBucketAccelerateConfigurationRequest(*s3.PutBucketAccelerateConfigurationInput) (*request.Request, *s3.PutBucketAccelerateConfigurationOutput)
PutBucketAcl(*s3.PutBucketAclInput) (*s3.PutBucketAclOutput, error)
PutBucketAclWithContext(aws.Context, *s3.PutBucketAclInput, ...request.Option) (*s3.PutBucketAclOutput, error)
PutBucketAclRequest(*s3.PutBucketAclInput) (*request.Request, *s3.PutBucketAclOutput)
PutBucketAnalyticsConfiguration(*s3.PutBucketAnalyticsConfigurationInput) (*s3.PutBucketAnalyticsConfigurationOutput, error)
PutBucketAnalyticsConfigurationWithContext(aws.Context, *s3.PutBucketAnalyticsConfigurationInput, ...request.Option) (*s3.PutBucketAnalyticsConfigurationOutput, error)
PutBucketAnalyticsConfigurationRequest(*s3.PutBucketAnalyticsConfigurationInput) (*request.Request, *s3.PutBucketAnalyticsConfigurationOutput)
PutBucketCors(*s3.PutBucketCorsInput) (*s3.PutBucketCorsOutput, error)
PutBucketCorsWithContext(aws.Context, *s3.PutBucketCorsInput, ...request.Option) (*s3.PutBucketCorsOutput, error)
PutBucketCorsRequest(*s3.PutBucketCorsInput) (*request.Request, *s3.PutBucketCorsOutput)
PutBucketEncryption(*s3.PutBucketEncryptionInput) (*s3.PutBucketEncryptionOutput, error)
PutBucketEncryptionWithContext(aws.Context, *s3.PutBucketEncryptionInput, ...request.Option) (*s3.PutBucketEncryptionOutput, error)
PutBucketEncryptionRequest(*s3.PutBucketEncryptionInput) (*request.Request, *s3.PutBucketEncryptionOutput)
PutBucketInventoryConfiguration(*s3.PutBucketInventoryConfigurationInput) (*s3.PutBucketInventoryConfigurationOutput, error)
PutBucketInventoryConfigurationWithContext(aws.Context, *s3.PutBucketInventoryConfigurationInput, ...request.Option) (*s3.PutBucketInventoryConfigurationOutput, error)
PutBucketInventoryConfigurationRequest(*s3.PutBucketInventoryConfigurationInput) (*request.Request, *s3.PutBucketInventoryConfigurationOutput)
PutBucketLifecycle(*s3.PutBucketLifecycleInput) (*s3.PutBucketLifecycleOutput, error)
PutBucketLifecycleWithContext(aws.Context, *s3.PutBucketLifecycleInput, ...request.Option) (*s3.PutBucketLifecycleOutput, error)
PutBucketLifecycleRequest(*s3.PutBucketLifecycleInput) (*request.Request, *s3.PutBucketLifecycleOutput)
PutBucketLifecycleConfiguration(*s3.PutBucketLifecycleConfigurationInput) (*s3.PutBucketLifecycleConfigurationOutput, error)
PutBucketLifecycleConfigurationWithContext(aws.Context, *s3.PutBucketLifecycleConfigurationInput, ...request.Option) (*s3.PutBucketLifecycleConfigurationOutput, error)
PutBucketLifecycleConfigurationRequest(*s3.PutBucketLifecycleConfigurationInput) (*request.Request, *s3.PutBucketLifecycleConfigurationOutput)
PutBucketLogging(*s3.PutBucketLoggingInput) (*s3.PutBucketLoggingOutput, error)
PutBucketLoggingWithContext(aws.Context, *s3.PutBucketLoggingInput, ...request.Option) (*s3.PutBucketLoggingOutput, error)
PutBucketLoggingRequest(*s3.PutBucketLoggingInput) (*request.Request, *s3.PutBucketLoggingOutput)
PutBucketMetricsConfiguration(*s3.PutBucketMetricsConfigurationInput) (*s3.PutBucketMetricsConfigurationOutput, error)
PutBucketMetricsConfigurationWithContext(aws.Context, *s3.PutBucketMetricsConfigurationInput, ...request.Option) (*s3.PutBucketMetricsConfigurationOutput, error)
PutBucketMetricsConfigurationRequest(*s3.PutBucketMetricsConfigurationInput) (*request.Request, *s3.PutBucketMetricsConfigurationOutput)
PutBucketNotification(*s3.PutBucketNotificationInput) (*s3.PutBucketNotificationOutput, error)
PutBucketNotificationWithContext(aws.Context, *s3.PutBucketNotificationInput, ...request.Option) (*s3.PutBucketNotificationOutput, error)
PutBucketNotificationRequest(*s3.PutBucketNotificationInput) (*request.Request, *s3.PutBucketNotificationOutput)
PutBucketNotificationConfiguration(*s3.PutBucketNotificationConfigurationInput) (*s3.PutBucketNotificationConfigurationOutput, error)
PutBucketNotificationConfigurationWithContext(aws.Context, *s3.PutBucketNotificationConfigurationInput, ...request.Option) (*s3.PutBucketNotificationConfigurationOutput, error)
PutBucketNotificationConfigurationRequest(*s3.PutBucketNotificationConfigurationInput) (*request.Request, *s3.PutBucketNotificationConfigurationOutput)
PutBucketPolicy(*s3.PutBucketPolicyInput) (*s3.PutBucketPolicyOutput, error)
PutBucketPolicyWithContext(aws.Context, *s3.PutBucketPolicyInput, ...request.Option) (*s3.PutBucketPolicyOutput, error)
PutBucketPolicyRequest(*s3.PutBucketPolicyInput) (*request.Request, *s3.PutBucketPolicyOutput)
PutBucketReplication(*s3.PutBucketReplicationInput) (*s3.PutBucketReplicationOutput, error)
PutBucketReplicationWithContext(aws.Context, *s3.PutBucketReplicationInput, ...request.Option) (*s3.PutBucketReplicationOutput, error)
PutBucketReplicationRequest(*s3.PutBucketReplicationInput) (*request.Request, *s3.PutBucketReplicationOutput)
PutBucketRequestPayment(*s3.PutBucketRequestPaymentInput) (*s3.PutBucketRequestPaymentOutput, error)
PutBucketRequestPaymentWithContext(aws.Context, *s3.PutBucketRequestPaymentInput, ...request.Option) (*s3.PutBucketRequestPaymentOutput, error)
PutBucketRequestPaymentRequest(*s3.PutBucketRequestPaymentInput) (*request.Request, *s3.PutBucketRequestPaymentOutput)
PutBucketTagging(*s3.PutBucketTaggingInput) (*s3.PutBucketTaggingOutput, error)
PutBucketTaggingWithContext(aws.Context, *s3.PutBucketTaggingInput, ...request.Option) (*s3.PutBucketTaggingOutput, error)
PutBucketTaggingRequest(*s3.PutBucketTaggingInput) (*request.Request, *s3.PutBucketTaggingOutput)
PutBucketVersioning(*s3.PutBucketVersioningInput) (*s3.PutBucketVersioningOutput, error)
PutBucketVersioningWithContext(aws.Context, *s3.PutBucketVersioningInput, ...request.Option) (*s3.PutBucketVersioningOutput, error)
PutBucketVersioningRequest(*s3.PutBucketVersioningInput) (*request.Request, *s3.PutBucketVersioningOutput)
PutBucketWebsite(*s3.PutBucketWebsiteInput) (*s3.PutBucketWebsiteOutput, error)
PutBucketWebsiteWithContext(aws.Context, *s3.PutBucketWebsiteInput, ...request.Option) (*s3.PutBucketWebsiteOutput, error)
PutBucketWebsiteRequest(*s3.PutBucketWebsiteInput) (*request.Request, *s3.PutBucketWebsiteOutput)
PutObject(*s3.PutObjectInput) (*s3.PutObjectOutput, error)
PutObjectWithContext(aws.Context, *s3.PutObjectInput, ...request.Option) (*s3.PutObjectOutput, error)
PutObjectRequest(*s3.PutObjectInput) (*request.Request, *s3.PutObjectOutput)
PutObjectAcl(*s3.PutObjectAclInput) (*s3.PutObjectAclOutput, error)
PutObjectAclWithContext(aws.Context, *s3.PutObjectAclInput, ...request.Option) (*s3.PutObjectAclOutput, error)
PutObjectAclRequest(*s3.PutObjectAclInput) (*request.Request, *s3.PutObjectAclOutput)
PutObjectTagging(*s3.PutObjectTaggingInput) (*s3.PutObjectTaggingOutput, error)
PutObjectTaggingWithContext(aws.Context, *s3.PutObjectTaggingInput, ...request.Option) (*s3.PutObjectTaggingOutput, error)
PutObjectTaggingRequest(*s3.PutObjectTaggingInput) (*request.Request, *s3.PutObjectTaggingOutput)
RestoreObject(*s3.RestoreObjectInput) (*s3.RestoreObjectOutput, error)
RestoreObjectWithContext(aws.Context, *s3.RestoreObjectInput, ...request.Option) (*s3.RestoreObjectOutput, error)
RestoreObjectRequest(*s3.RestoreObjectInput) (*request.Request, *s3.RestoreObjectOutput)
SelectObjectContent(*s3.SelectObjectContentInput) (*s3.SelectObjectContentOutput, error)
SelectObjectContentWithContext(aws.Context, *s3.SelectObjectContentInput, ...request.Option) (*s3.SelectObjectContentOutput, error)
SelectObjectContentRequest(*s3.SelectObjectContentInput) (*request.Request, *s3.SelectObjectContentOutput)
UploadPart(*s3.UploadPartInput) (*s3.UploadPartOutput, error)
UploadPartWithContext(aws.Context, *s3.UploadPartInput, ...request.Option) (*s3.UploadPartOutput, error)
UploadPartRequest(*s3.UploadPartInput) (*request.Request, *s3.UploadPartOutput)
UploadPartCopy(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error)
UploadPartCopyWithContext(aws.Context, *s3.UploadPartCopyInput, ...request.Option) (*s3.UploadPartCopyOutput, error)
UploadPartCopyRequest(*s3.UploadPartCopyInput) (*request.Request, *s3.UploadPartCopyOutput)
WaitUntilBucketExists(*s3.HeadBucketInput) error
WaitUntilBucketExistsWithContext(aws.Context, *s3.HeadBucketInput, ...request.WaiterOption) error
WaitUntilBucketNotExists(*s3.HeadBucketInput) error
WaitUntilBucketNotExistsWithContext(aws.Context, *s3.HeadBucketInput, ...request.WaiterOption) error
WaitUntilObjectExists(*s3.HeadObjectInput) error
WaitUntilObjectExistsWithContext(aws.Context, *s3.HeadObjectInput, ...request.WaiterOption) error
WaitUntilObjectNotExists(*s3.HeadObjectInput) error
WaitUntilObjectNotExistsWithContext(aws.Context, *s3.HeadObjectInput, ...request.WaiterOption) error
}
var _ S3API = (*s3.S3)(nil)
+529
View File
@@ -0,0 +1,529 @@
package s3manager
import (
"bytes"
"fmt"
"io"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
)
const (
// DefaultBatchSize is the batch size we initialize when constructing a batch delete client.
// This value is used when calling DeleteObjects. This represents how many objects to delete
// per DeleteObjects call.
DefaultBatchSize = 100
)
// BatchError will contain the key and bucket of the object that failed to
// either upload or download.
type BatchError struct {
Errors Errors
code string
message string
}
// Errors is a typed alias for a slice of errors to satisfy the error
// interface.
type Errors []Error
func (errs Errors) Error() string {
buf := bytes.NewBuffer(nil)
for i, err := range errs {
buf.WriteString(err.Error())
if i+1 < len(errs) {
buf.WriteString("\n")
}
}
return buf.String()
}
// Error will contain the original error, bucket, and key of the operation that failed
// during batch operations.
type Error struct {
OrigErr error
Bucket *string
Key *string
}
func newError(err error, bucket, key *string) Error {
return Error{
err,
bucket,
key,
}
}
func (err *Error) Error() string {
origErr := ""
if err.OrigErr != nil {
origErr = ":\n" + err.OrigErr.Error()
}
return fmt.Sprintf("failed to perform batch operation on %q to %q%s",
aws.StringValue(err.Key),
aws.StringValue(err.Bucket),
origErr,
)
}
// NewBatchError will return a BatchError that satisfies the awserr.Error interface.
func NewBatchError(code, message string, err []Error) awserr.Error {
return &BatchError{
Errors: err,
code: code,
message: message,
}
}
// Code will return the code associated with the batch error.
func (err *BatchError) Code() string {
return err.code
}
// Message will return the message associated with the batch error.
func (err *BatchError) Message() string {
return err.message
}
func (err *BatchError) Error() string {
return awserr.SprintError(err.Code(), err.Message(), "", err.Errors)
}
// OrigErr will return the original error. Which, in this case, will always be nil
// for batched operations.
func (err *BatchError) OrigErr() error {
return err.Errors
}
// BatchDeleteIterator is an interface that uses the scanner pattern to
// iterate through what needs to be deleted.
type BatchDeleteIterator interface {
Next() bool
Err() error
DeleteObject() BatchDeleteObject
}
// DeleteListIterator is an alternative iterator for the BatchDelete client. This will
// iterate through a list of objects and delete the objects.
//
// Example:
// iter := &s3manager.DeleteListIterator{
// Client: svc,
// Input: &s3.ListObjectsInput{
// Bucket: aws.String("bucket"),
// MaxKeys: aws.Int64(5),
// },
// Paginator: request.Pagination{
// NewRequest: func() (*request.Request, error) {
// var inCpy *ListObjectsInput
// if input != nil {
// tmp := *input
// inCpy = &tmp
// }
// req, _ := c.ListObjectsRequest(inCpy)
// return req, nil
// },
// },
// }
//
// batcher := s3manager.NewBatchDeleteWithClient(svc)
// if err := batcher.Delete(aws.BackgroundContext(), iter); err != nil {
// return err
// }
type DeleteListIterator struct {
Bucket *string
Paginator request.Pagination
objects []*s3.Object
}
// NewDeleteListIterator will return a new DeleteListIterator.
func NewDeleteListIterator(svc s3iface.S3API, input *s3.ListObjectsInput, opts ...func(*DeleteListIterator)) BatchDeleteIterator {
iter := &DeleteListIterator{
Bucket: input.Bucket,
Paginator: request.Pagination{
NewRequest: func() (*request.Request, error) {
var inCpy *s3.ListObjectsInput
if input != nil {
tmp := *input
inCpy = &tmp
}
req, _ := svc.ListObjectsRequest(inCpy)
return req, nil
},
},
}
for _, opt := range opts {
opt(iter)
}
return iter
}
// Next will use the S3API client to iterate through a list of objects.
func (iter *DeleteListIterator) Next() bool {
if len(iter.objects) > 0 {
iter.objects = iter.objects[1:]
}
if len(iter.objects) == 0 && iter.Paginator.Next() {
iter.objects = iter.Paginator.Page().(*s3.ListObjectsOutput).Contents
}
return len(iter.objects) > 0
}
// Err will return the last known error from Next.
func (iter *DeleteListIterator) Err() error {
return iter.Paginator.Err()
}
// DeleteObject will return the current object to be deleted.
func (iter *DeleteListIterator) DeleteObject() BatchDeleteObject {
return BatchDeleteObject{
Object: &s3.DeleteObjectInput{
Bucket: iter.Bucket,
Key: iter.objects[0].Key,
},
}
}
// BatchDelete will use the s3 package's service client to perform a batch
// delete.
type BatchDelete struct {
Client s3iface.S3API
BatchSize int
}
// NewBatchDeleteWithClient will return a new delete client that can delete a batched amount of
// objects.
//
// Example:
// batcher := s3manager.NewBatchDeleteWithClient(client, size)
//
// objects := []BatchDeleteObject{
// {
// Object: &s3.DeleteObjectInput {
// Key: aws.String("key"),
// Bucket: aws.String("bucket"),
// },
// },
// }
//
// if err := batcher.Delete(aws.BackgroundContext(), &s3manager.DeleteObjectsIterator{
// Objects: objects,
// }); err != nil {
// return err
// }
func NewBatchDeleteWithClient(client s3iface.S3API, options ...func(*BatchDelete)) *BatchDelete {
svc := &BatchDelete{
Client: client,
BatchSize: DefaultBatchSize,
}
for _, opt := range options {
opt(svc)
}
return svc
}
// NewBatchDelete will return a new delete client that can delete a batched amount of
// objects.
//
// Example:
// batcher := s3manager.NewBatchDelete(sess, size)
//
// objects := []BatchDeleteObject{
// {
// Object: &s3.DeleteObjectInput {
// Key: aws.String("key"),
// Bucket: aws.String("bucket"),
// },
// },
// }
//
// if err := batcher.Delete(aws.BackgroundContext(), &s3manager.DeleteObjectsIterator{
// Objects: objects,
// }); err != nil {
// return err
// }
func NewBatchDelete(c client.ConfigProvider, options ...func(*BatchDelete)) *BatchDelete {
client := s3.New(c)
return NewBatchDeleteWithClient(client, options...)
}
// BatchDeleteObject is a wrapper object for calling the batch delete operation.
type BatchDeleteObject struct {
Object *s3.DeleteObjectInput
// After will run after each iteration during the batch process. This function will
// be executed whether or not the request was successful.
After func() error
}
// DeleteObjectsIterator is an interface that uses the scanner pattern to iterate
// through a series of objects to be deleted.
type DeleteObjectsIterator struct {
Objects []BatchDeleteObject
index int
inc bool
}
// Next will increment the default iterator's index and and ensure that there
// is another object to iterator to.
func (iter *DeleteObjectsIterator) Next() bool {
if iter.inc {
iter.index++
} else {
iter.inc = true
}
return iter.index < len(iter.Objects)
}
// Err will return an error. Since this is just used to satisfy the BatchDeleteIterator interface
// this will only return nil.
func (iter *DeleteObjectsIterator) Err() error {
return nil
}
// DeleteObject will return the BatchDeleteObject at the current batched index.
func (iter *DeleteObjectsIterator) DeleteObject() BatchDeleteObject {
object := iter.Objects[iter.index]
return object
}
// Delete will use the iterator to queue up objects that need to be deleted.
// Once the batch size is met, this will call the deleteBatch function.
func (d *BatchDelete) Delete(ctx aws.Context, iter BatchDeleteIterator) error {
var errs []Error
objects := []BatchDeleteObject{}
var input *s3.DeleteObjectsInput
for iter.Next() {
o := iter.DeleteObject()
if input == nil {
input = initDeleteObjectsInput(o.Object)
}
parity := hasParity(input, o)
if parity {
input.Delete.Objects = append(input.Delete.Objects, &s3.ObjectIdentifier{
Key: o.Object.Key,
VersionId: o.Object.VersionId,
})
objects = append(objects, o)
}
if len(input.Delete.Objects) == d.BatchSize || !parity {
if err := deleteBatch(ctx, d, input, objects); err != nil {
errs = append(errs, err...)
}
objects = objects[:0]
input = nil
if !parity {
objects = append(objects, o)
input = initDeleteObjectsInput(o.Object)
input.Delete.Objects = append(input.Delete.Objects, &s3.ObjectIdentifier{
Key: o.Object.Key,
VersionId: o.Object.VersionId,
})
}
}
}
// iter.Next() could return false (above) plus populate iter.Err()
if iter.Err() != nil {
errs = append(errs, newError(iter.Err(), nil, nil))
}
if input != nil && len(input.Delete.Objects) > 0 {
if err := deleteBatch(ctx, d, input, objects); err != nil {
errs = append(errs, err...)
}
}
if len(errs) > 0 {
return NewBatchError("BatchedDeleteIncomplete", "some objects have failed to be deleted.", errs)
}
return nil
}
func initDeleteObjectsInput(o *s3.DeleteObjectInput) *s3.DeleteObjectsInput {
return &s3.DeleteObjectsInput{
Bucket: o.Bucket,
MFA: o.MFA,
RequestPayer: o.RequestPayer,
Delete: &s3.Delete{},
}
}
const (
// ErrDeleteBatchFailCode represents an error code which will be returned
// only when DeleteObjects.Errors has an error that does not contain a code.
ErrDeleteBatchFailCode = "DeleteBatchError"
errDefaultDeleteBatchMessage = "failed to delete"
)
// deleteBatch will delete a batch of items in the objects parameters.
func deleteBatch(ctx aws.Context, d *BatchDelete, input *s3.DeleteObjectsInput, objects []BatchDeleteObject) []Error {
errs := []Error{}
if result, err := d.Client.DeleteObjectsWithContext(ctx, input); err != nil {
for i := 0; i < len(input.Delete.Objects); i++ {
errs = append(errs, newError(err, input.Bucket, input.Delete.Objects[i].Key))
}
} else if len(result.Errors) > 0 {
for i := 0; i < len(result.Errors); i++ {
code := ErrDeleteBatchFailCode
msg := errDefaultDeleteBatchMessage
if result.Errors[i].Message != nil {
msg = *result.Errors[i].Message
}
if result.Errors[i].Code != nil {
code = *result.Errors[i].Code
}
errs = append(errs, newError(awserr.New(code, msg, err), input.Bucket, result.Errors[i].Key))
}
}
for _, object := range objects {
if object.After == nil {
continue
}
if err := object.After(); err != nil {
errs = append(errs, newError(err, object.Object.Bucket, object.Object.Key))
}
}
return errs
}
func hasParity(o1 *s3.DeleteObjectsInput, o2 BatchDeleteObject) bool {
if o1.Bucket != nil && o2.Object.Bucket != nil {
if *o1.Bucket != *o2.Object.Bucket {
return false
}
} else if o1.Bucket != o2.Object.Bucket {
return false
}
if o1.MFA != nil && o2.Object.MFA != nil {
if *o1.MFA != *o2.Object.MFA {
return false
}
} else if o1.MFA != o2.Object.MFA {
return false
}
if o1.RequestPayer != nil && o2.Object.RequestPayer != nil {
if *o1.RequestPayer != *o2.Object.RequestPayer {
return false
}
} else if o1.RequestPayer != o2.Object.RequestPayer {
return false
}
return true
}
// BatchDownloadIterator is an interface that uses the scanner pattern to iterate
// through a series of objects to be downloaded.
type BatchDownloadIterator interface {
Next() bool
Err() error
DownloadObject() BatchDownloadObject
}
// BatchDownloadObject contains all necessary information to run a batch operation once.
type BatchDownloadObject struct {
Object *s3.GetObjectInput
Writer io.WriterAt
// After will run after each iteration during the batch process. This function will
// be executed whether or not the request was successful.
After func() error
}
// DownloadObjectsIterator implements the BatchDownloadIterator interface and allows for batched
// download of objects.
type DownloadObjectsIterator struct {
Objects []BatchDownloadObject
index int
inc bool
}
// Next will increment the default iterator's index and and ensure that there
// is another object to iterator to.
func (batcher *DownloadObjectsIterator) Next() bool {
if batcher.inc {
batcher.index++
} else {
batcher.inc = true
}
return batcher.index < len(batcher.Objects)
}
// DownloadObject will return the BatchDownloadObject at the current batched index.
func (batcher *DownloadObjectsIterator) DownloadObject() BatchDownloadObject {
object := batcher.Objects[batcher.index]
return object
}
// Err will return an error. Since this is just used to satisfy the BatchDeleteIterator interface
// this will only return nil.
func (batcher *DownloadObjectsIterator) Err() error {
return nil
}
// BatchUploadIterator is an interface that uses the scanner pattern to
// iterate through what needs to be uploaded.
type BatchUploadIterator interface {
Next() bool
Err() error
UploadObject() BatchUploadObject
}
// UploadObjectsIterator implements the BatchUploadIterator interface and allows for batched
// upload of objects.
type UploadObjectsIterator struct {
Objects []BatchUploadObject
index int
inc bool
}
// Next will increment the default iterator's index and and ensure that there
// is another object to iterator to.
func (batcher *UploadObjectsIterator) Next() bool {
if batcher.inc {
batcher.index++
} else {
batcher.inc = true
}
return batcher.index < len(batcher.Objects)
}
// Err will return an error. Since this is just used to satisfy the BatchUploadIterator interface
// this will only return nil.
func (batcher *UploadObjectsIterator) Err() error {
return nil
}
// UploadObject will return the BatchUploadObject at the current batched index.
func (batcher *UploadObjectsIterator) UploadObject() BatchUploadObject {
object := batcher.Objects[batcher.index]
return object
}
// BatchUploadObject contains all necessary information to run a batch operation once.
type BatchUploadObject struct {
Object *UploadInput
// After will run after each iteration during the batch process. This function will
// be executed whether or not the request was successful.
After func() error
}
+88
View File
@@ -0,0 +1,88 @@
package s3manager
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
)
// GetBucketRegion will attempt to get the region for a bucket using the
// regionHint to determine which AWS partition to perform the query on.
//
// The request will not be signed, and will not use your AWS credentials.
//
// A "NotFound" error code will be returned if the bucket does not exist in the
// AWS partition the regionHint belongs to. If the regionHint parameter is an
// empty string GetBucketRegion will fallback to the ConfigProvider's region
// config. If the regionHint is empty, and the ConfigProvider does not have a
// region value, an error will be returned..
//
// For example to get the region of a bucket which exists in "eu-central-1"
// you could provide a region hint of "us-west-2".
//
// sess := session.Must(session.NewSession())
//
// bucket := "my-bucket"
// region, err := s3manager.GetBucketRegion(ctx, sess, bucket, "us-west-2")
// if err != nil {
// if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "NotFound" {
// fmt.Fprintf(os.Stderr, "unable to find bucket %s's region not found\n", bucket)
// }
// return err
// }
// fmt.Printf("Bucket %s is in %s region\n", bucket, region)
//
func GetBucketRegion(ctx aws.Context, c client.ConfigProvider, bucket, regionHint string, opts ...request.Option) (string, error) {
var cfg aws.Config
if len(regionHint) != 0 {
cfg.Region = aws.String(regionHint)
}
svc := s3.New(c, &cfg)
return GetBucketRegionWithClient(ctx, svc, bucket, opts...)
}
const bucketRegionHeader = "X-Amz-Bucket-Region"
// GetBucketRegionWithClient is the same as GetBucketRegion with the exception
// that it takes a S3 service client instead of a Session. The regionHint is
// derived from the region the S3 service client was created in.
//
// See GetBucketRegion for more information.
func GetBucketRegionWithClient(ctx aws.Context, svc s3iface.S3API, bucket string, opts ...request.Option) (string, error) {
req, _ := svc.HeadBucketRequest(&s3.HeadBucketInput{
Bucket: aws.String(bucket),
})
req.Config.S3ForcePathStyle = aws.Bool(true)
req.Config.Credentials = credentials.AnonymousCredentials
req.SetContext(ctx)
// Disable HTTP redirects to prevent an invalid 301 from eating the response
// because Go's HTTP client will fail, and drop the response if an 301 is
// received without a location header. S3 will return a 301 without the
// location header for HeadObject API calls.
req.DisableFollowRedirects = true
var bucketRegion string
req.Handlers.Send.PushBack(func(r *request.Request) {
bucketRegion = r.HTTPResponse.Header.Get(bucketRegionHeader)
if len(bucketRegion) == 0 {
return
}
r.HTTPResponse.StatusCode = 200
r.HTTPResponse.Status = "OK"
r.Error = nil
})
req.ApplyOptions(opts...)
if err := req.Send(); err != nil {
return "", err
}
bucketRegion = s3.NormalizeBucketLocation(bucketRegion)
return bucketRegion, nil
}
+3
View File
@@ -0,0 +1,3 @@
// Package s3manager provides utilities to upload and download objects from
// S3 concurrently. Helpful for when working with large objects.
package s3manager

Some files were not shown because too many files have changed in this diff Show More