mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
resolve conflict
This commit is contained in:
Generated
+8
-7
@@ -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",
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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, "aCpuMem)
|
||||
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{})
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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?")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package modules
|
||||
|
||||
var (
|
||||
Cloudmeta ResourceManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
Cloudmeta = NewCloudmetaManager("cloudmeta", "cloudmetas",
|
||||
[]string{},
|
||||
[]string{})
|
||||
|
||||
register(&Cloudmeta)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package options
|
||||
|
||||
type VersionListOptions struct {
|
||||
Region string
|
||||
}
|
||||
|
||||
type VersionGetOptions struct {
|
||||
Service string `choices:"cloud" default:"cloud"`
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
@@ -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{} {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user