mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 22:32:15 +08:00
20181222: storageman interfaces, work manager refactor
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package storagetypes
|
||||
|
||||
// TODO: move models/storages.go storage types to this file
|
||||
const (
|
||||
STORAGE_LOCAL = "local"
|
||||
STORAGE_BAREMETAL = "baremetal"
|
||||
STORAGE_SHEEPDOG = "sheepdog"
|
||||
STORAGE_RBD = "rbd"
|
||||
STORAGE_DOCKER = "docker"
|
||||
STORAGE_NAS = "nas"
|
||||
STORAGE_VSAN = "vsan"
|
||||
STORAGE_NFS = "nfs"
|
||||
)
|
||||
@@ -61,7 +61,3 @@ func (w *SWorkManager) Stop() {
|
||||
func NewWorkManger() *SWorkManager {
|
||||
return &SWorkManager{}
|
||||
}
|
||||
|
||||
// type ITaskPramas interface {
|
||||
// To
|
||||
// }
|
||||
|
||||
@@ -59,7 +59,6 @@ func deleteGuest(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
response(ctx, w, err)
|
||||
} else {
|
||||
// TODO: CleanGuest
|
||||
wm.DelayTask(ctx, guest.CleanGuest, migrated)
|
||||
response(ctx, w, map[string]bool{"delay_clean": true})
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"yunion.io/x/pkg/util/seclib"
|
||||
)
|
||||
|
||||
const VNC_PORT_BASE = 5900
|
||||
|
||||
type SGuestManager struct {
|
||||
ServersPath string
|
||||
Servers map[string]*SKVMGuestInstance
|
||||
@@ -282,12 +284,10 @@ func (m *SGuestManager) Delete(sid string) (*SKVMGuestInstance, error) {
|
||||
func (m *SGuestManager) Start(ctx context.Context, sid string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if guest, ok := m.Servers[sid]; ok {
|
||||
if desc, err := body.Get("desc"); err != nil {
|
||||
// TODO
|
||||
guest.SaveDesc(desc)
|
||||
}
|
||||
if guest.IsStopped() {
|
||||
params, _ := body.Get("params")
|
||||
// TODO
|
||||
if err := guest.StartGuest(ctx, params); err != nil {
|
||||
return nil, httperrors.NewBadRequestError("Failed to start server")
|
||||
} else {
|
||||
@@ -309,6 +309,26 @@ func (m *SGuestManager) Start(ctx context.Context, sid string, body jsonutils.JS
|
||||
}
|
||||
}
|
||||
|
||||
func (m *SGuestManager) GetFreeVncPort() int64 {
|
||||
vncPorts := make(map[int]struct{}, 0)
|
||||
for _, guest := range m.Servers {
|
||||
inUsePort := guest.GetVncPort()
|
||||
if inUsePort > 0 {
|
||||
vncPorts[inUsePort] = struct{}{}
|
||||
}
|
||||
}
|
||||
var port = 1
|
||||
for {
|
||||
if _, ok := vncPorts[port]; !ok && !cloudcommon.IsTcpPortUsed("0.0.0.0", VNC_PORT_BASE+port) &&
|
||||
!cloudcommon.IsTcpPortUsed("0.0.0.0", MONITOR_PORT_BASE+port) {
|
||||
break
|
||||
} else {
|
||||
port += 1
|
||||
}
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func initGuestManager(serversPath string) {
|
||||
if guestManger == nil {
|
||||
guestManger = NewGuestManager(serversPath)
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/httpclients"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/storagetypes"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestfs"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostinfo"
|
||||
"yunion.io/x/onecloud/pkg/hostman/monitor"
|
||||
@@ -169,19 +170,35 @@ func (s *SKVMGuestInstance) DirtyServerRequestStart() {
|
||||
}
|
||||
}
|
||||
|
||||
// Must called in new goroutine
|
||||
func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params *jsonutils.JSONDict) {
|
||||
// TODO
|
||||
// hostinof.instace().clean_deleted_ports
|
||||
// Delay Process
|
||||
func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params interface{}) {
|
||||
data, ok := params.(*jsonutils.JSONDict)
|
||||
if !ok {
|
||||
log.Errorln("asyncScriptStart params error")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO hostinof.instace().clean_deleted_ports
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
var isStarted, tried, err = false, 0, nil
|
||||
for !isStarted && tried < MAX_TRY {
|
||||
tried += 1
|
||||
|
||||
vncPort := s.manager.GetFreeVncPort()
|
||||
s.saveVncPort(vncPort)
|
||||
params.Set("vnc_port", jsonutils.NewInt(vncPort))
|
||||
s.saveScripts(params)
|
||||
isStarted, err = s.scriptStart()
|
||||
if err = s.saveVncPort(vncPort); err != nil {
|
||||
goto finally
|
||||
} else {
|
||||
data.Set("vnc_port", jsonutils.NewInt(vncPort))
|
||||
}
|
||||
|
||||
if err = s.saveScripts(data); err != nil {
|
||||
goto finally
|
||||
} else {
|
||||
isStarted, err = s.scriptStart()
|
||||
}
|
||||
|
||||
finally:
|
||||
if !isStarted {
|
||||
log.Errorf("Start VM failed: %s", err)
|
||||
time.Sleep((1 << (tried - 1)) * time.Seconde)
|
||||
@@ -189,6 +206,7 @@ func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params *jsonut
|
||||
log.Infof("VM started ...")
|
||||
}
|
||||
}
|
||||
|
||||
s.onAsyncScriptStart(ctx, isStarted, err)
|
||||
}
|
||||
|
||||
@@ -205,6 +223,29 @@ func (s *SKVMGuestInstance) onAsyncScriptStart(ctx context.Context, isStarted bo
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) saveScripts(data *jsonutils.JSONDict) error {
|
||||
startScript, err := s.generateStartScript(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cloudcommon.FilePutContents(s.GetStartScriptPath, startScript, false); err != nil {
|
||||
return err
|
||||
}
|
||||
stopScript, err := s.generateStopScript(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cloudcommon.FilePutContents(s.GetStopScriptPath, stopScript, false)
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) GetStartScriptPath() string {
|
||||
return path.Join(s.HomeDir(), "startvm")
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) GetStopScriptPath() string {
|
||||
return path.Join(s.HomeDir(), "stopvm")
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) ImportServer(pendingDelete bool) {
|
||||
if s.IsDirtyShotdown() && !pendingDelete {
|
||||
log.Infof("Server dirty shotdown %s", s.GetName())
|
||||
@@ -334,6 +375,10 @@ func (s *SKVMGuestInstance) GetVncPort() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) saveVncPort(port int64) error {
|
||||
return cloudcommon.FilePutContents(s.GetVncFilePath(), fmt.Sprintf("%d", port), false)
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) SyncStatus() {
|
||||
if s.IsRunning() {
|
||||
s.monitor.GetBlockJobs(s.CheckBlockOrRunning)
|
||||
@@ -360,9 +405,7 @@ func (s *SKVMGuestInstance) SaveDesc(desc jsonutils.JSONObject) error {
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) StartGuest(ctx context.Context, params jsonutils.JSONObject) {
|
||||
wm.DelayTask(func() {
|
||||
s.asyncScriptStart(ctx, params)
|
||||
})
|
||||
wm.DelayTask(ctx, s.asyncScriptStart, params)
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) DeployFs(deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error) {
|
||||
@@ -372,12 +415,13 @@ func (s *SKVMGuestInstance) DeployFs(deployInfo *guestfs.SDeployInfo) (jsonutils
|
||||
diskId, _ := disks[0].GetString("disk_id")
|
||||
|
||||
disk := hostinfo.GetStorageManager().GetStorageDisk(storageId, diskId)
|
||||
return disk.DeployGuestFs(s.Desc, deployInfo)
|
||||
return disk.DeployGuestFs(disk.GetPath, s.Desc, deployInfo)
|
||||
} else {
|
||||
return nil, fmt.Errorf("Guest dosen't have disk ??")
|
||||
}
|
||||
}
|
||||
|
||||
// Delay process
|
||||
func (s *SKVMGuestInstance) CleanGuest(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
|
||||
migrated, ok := params.(bool)
|
||||
if !ok {
|
||||
@@ -443,8 +487,12 @@ func (s *SKVMGuestInstance) delTmpDisks(ctx context.Context, migrated bool) {
|
||||
// TODO GetDisksByPath, storagetypes, deleteallsnapshot, delete
|
||||
d := hostinfo.GetStorageManager().GetDiskByPath(diskPath)
|
||||
if d != nil && d.GetType == storagetypes.STORAGE_LOCAL && migrated {
|
||||
d.DeleteAllSnapshot()
|
||||
d.Delete(ctx)
|
||||
if err := d.DeleteAllSnapshot(); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
if err := d.Delete(ctx); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package guestman
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/options"
|
||||
)
|
||||
|
||||
var (
|
||||
OS_NAME_LINUX = "Linux"
|
||||
OS_NAME_WINDOWS = "Windows"
|
||||
OS_NAME_MACOS = "macOS"
|
||||
OS_NAME_ANDROID = "Android"
|
||||
OS_NAME_VMWARE = "VMWare"
|
||||
)
|
||||
|
||||
func (s *SKVMGuestInstance) getOsname() string {
|
||||
if s.Desc.Contains("metadata") {
|
||||
metadata, _ := s.Desc.Get("metadata")
|
||||
if metadata.Contains("os_name") {
|
||||
osname, _ := metadata.GetString("os_name")
|
||||
return osname
|
||||
}
|
||||
}
|
||||
return OS_NAME_LINUX
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) generateStartScript(data *jsonutils.JSONDict) (string, error) {
|
||||
osname := s.GetOsname()
|
||||
if osname == OS_NAME_MACOS {
|
||||
s.Desc.Set("machine", jsonutils.NewString("q35"))
|
||||
s.Desc.Set("bios", jsonutils.NewString("UEFI"))
|
||||
}
|
||||
|
||||
vncPort, _ := data.Int("vnc_port")
|
||||
|
||||
qemuVersion := options.HostOptions.DefaultQemuVersion
|
||||
if data.Contains("qemu_version") {
|
||||
qemuVersion, _ := data.GetString("qemu_version")
|
||||
}
|
||||
if qemuVersion == "latest" {
|
||||
qemuVersion = ""
|
||||
}
|
||||
|
||||
// TODO: isolatedDevsParams := hostinfo.Instance()...
|
||||
}
|
||||
@@ -51,6 +51,8 @@ type SHostOptions struct {
|
||||
PrivatePrefixes []string `help:"IPv4 private prefixes"`
|
||||
LocalImagePath []string `help:"Local image storage paths"`
|
||||
SharedStorages []string `help:"Path of shared storages"`
|
||||
|
||||
DefaultQemuVersion string `help:"Default qemu version" default:"2.9.1"`
|
||||
}
|
||||
|
||||
var HostOptions SHostOptions
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package storageman
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
@@ -12,8 +13,18 @@ import (
|
||||
type IDisk interface {
|
||||
GetId() string
|
||||
Probe() bool
|
||||
DeployGuestFs(guestDesc *jsonutils.JSONDict,
|
||||
deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error)
|
||||
|
||||
DeleteAllSnapshot() error
|
||||
Delete() error
|
||||
|
||||
GetPath() string
|
||||
CreateFromUrl(context.Context, string) error
|
||||
// CreateFromSnapshot
|
||||
CreateFromTemplate(context.Context, string, string, int64) error
|
||||
Resize(context.Context, int64) error
|
||||
|
||||
// @params: diskPath, guestDesc, deployInfo
|
||||
DeployGuestFs(string, *jsonutils.JSONDict, *guestfs.SDeployInfo) (jsonutils.JSONObject, error)
|
||||
}
|
||||
|
||||
type SBaseDisk struct {
|
||||
@@ -28,14 +39,37 @@ func NewBaseDisk(storage IStorage, id string) *SBaseDisk {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) getPath() string {
|
||||
func (d *SBaseDisk) GetId() string {
|
||||
return d.Id
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) GetPath() string {
|
||||
return path.Join(d.Storage.GetPath(), d.Id)
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) DeployGuestFs(
|
||||
guestDesc *jsonutils.JSONDict,
|
||||
func (d *SBaseDisk) Probe() error {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) Delete() error {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) CreateFromUrl(context.Context, string) error {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) CreateFromTemplate(context.Context, string, string, int64) error {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) Resize(context.Context, int64) error {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
func (d *SBaseDisk) DeployGuestFs(diskPath string, guestDesc *jsonutils.JSONDict,
|
||||
deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error) {
|
||||
var kvmDisk = NewKVMGuestDisk(d.getPath())
|
||||
var kvmDisk = NewKVMGuestDisk(diskPath)
|
||||
if kvmDisk.Connect() {
|
||||
defer kvmDisk.Disconnect()
|
||||
log.Infof("Kvm Disk Connect Success !!")
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package storageman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"yunion.io/x/log"
|
||||
)
|
||||
|
||||
var _ALTER_SUFFIX_ = ".alter"
|
||||
|
||||
type SLocalDisk struct {
|
||||
SBaseDisk
|
||||
isAlter bool
|
||||
}
|
||||
|
||||
func NewLocalDisk(storage IStorage, id string) *SLocalDisk {
|
||||
var ret = new(SLocalDisk)
|
||||
ret.SBaseDisk = *NewBaseDisk(storage, id)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) getPath() string {
|
||||
return path.Join(d.Storage.GetPath(), d.Id)
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) getAlterPath() string {
|
||||
return path.Join(d.Storage.GetPath(), d.Id, _ALTER_SUFFIX_)
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) GetPath() string {
|
||||
if d.isAlter {
|
||||
return d.getAlterPath()
|
||||
} else {
|
||||
return d.getPath()
|
||||
}
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) Probe() error {
|
||||
if _, err := os.Stat(d.getPath()); !os.IsNotExist(err) {
|
||||
d.isAlter = false
|
||||
return nil
|
||||
} else if _, err := os.Stat(d.getAlterPath()); !os.IsNotExist(err) {
|
||||
d.isAlter = true
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Disk not found")
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) Delete() error {
|
||||
dpath := d.GetPath()
|
||||
log.Infof("Delete guest disk %s", dpath)
|
||||
if err := d.Storage.DeleteDiskfile(dpath); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: PostCreateFromImageFuse umount fuse fs
|
||||
d.UmountImageFuse()
|
||||
/* ????????????????
|
||||
files = os.listdir(self.storage.path)
|
||||
for f in files:
|
||||
if f.startswith(self.id):
|
||||
if not re.match(r'[a-z0-9\-]*\.\d{14}', f):
|
||||
path = os.path.join(self.storage.path, f)
|
||||
print 'delete backing-file:', path
|
||||
self.storage.delete_diskfile(path)
|
||||
*/
|
||||
d.Storage.RemoveDisk(d)
|
||||
return nil
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/qemutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestfs"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package storageman
|
||||
|
||||
import "context"
|
||||
|
||||
type IImageCache interface {
|
||||
GetPath() string
|
||||
Load() error
|
||||
Acquire(context.Context, string, string) error
|
||||
Release()
|
||||
Remove() error
|
||||
GetImageId() string
|
||||
}
|
||||
|
||||
type SImageCacheDesc struct {
|
||||
name string
|
||||
format string
|
||||
id string
|
||||
chksum string
|
||||
path string
|
||||
size int64
|
||||
}
|
||||
|
||||
type SLocalImageCache struct {
|
||||
imageId string
|
||||
Manager IImagecacheManager
|
||||
Size int64
|
||||
Desc *SImageCacheDesc
|
||||
|
||||
consumerCount int
|
||||
}
|
||||
|
||||
func NewLocalImageCache(imageId string, imagecacheManager IImageCacheManger) *SLocalImageCache {
|
||||
imageCache := new(SLocalImageCache)
|
||||
imageCache.imageId = imageId
|
||||
imageCache.Manager = imagecacheManager
|
||||
return imageCache
|
||||
}
|
||||
|
||||
func (l *SLocalImageCache) Load() error {
|
||||
// TODO
|
||||
}
|
||||
|
||||
type SRbdImageCache struct {
|
||||
imageId string
|
||||
Manager IImagecacheManager
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package storageman
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
)
|
||||
|
||||
type IImageCacheManger interface {
|
||||
// LoadCache() error ???
|
||||
PrefetchImageCache(ctx, data jsonutils.JSONObject) error
|
||||
DeleteImageCache(ctx, data jsonutils.JSONObject) error
|
||||
}
|
||||
|
||||
type SBaseImageCacheManager struct {
|
||||
storagemanager *SStorageManager
|
||||
storagecacaheId string
|
||||
cachePath string
|
||||
cachedImages map[string]IImageCache
|
||||
mutex *sync.Mutex
|
||||
}
|
||||
|
||||
type SLocalImageCacheManager struct {
|
||||
SBaseImageCacheManager
|
||||
limit int
|
||||
isTemplate bool
|
||||
}
|
||||
|
||||
func NewLocalImageCacheManager(manager *SStorageManager, cachePath string, limit int, isTemplete bool, storagecacheId string) *SLocalImageCacheManager {
|
||||
imageCacheManager := new(SLocalImageCacheManager)
|
||||
imageCacheManager.storagemanager = manager
|
||||
imageCacheManager.storagecacaheId = storagecacheId
|
||||
imageCacheManager.cachePath = cachePath
|
||||
imageCacheManager.limit = limit
|
||||
imageCacheManager.isTemplate = isTemplete
|
||||
imageCacheManager.cachedImages = make(map[string]IImageCache, 0)
|
||||
imageCacheManager.mutex = new(sync.Mutex)
|
||||
if _, err := os.Stat(cachePath); os.IsNotExist(err) {
|
||||
exec.Command("mkdir", "-p", cachePath).Run()
|
||||
}
|
||||
imageCacheManager.loadCache()
|
||||
}
|
||||
|
||||
func (c *SLocalImageCacheManager) loadCache() {
|
||||
if len(c.cachePath) == 0 {
|
||||
return
|
||||
}
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
files, _ := ioutil.ReadDir(c.cachePath)
|
||||
for _, f := range files {
|
||||
if regutils.MatchUUIDExact(f.Name()) {
|
||||
c.loadImageCache(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *SLocalImageCacheManager) loadImageCache(file string) {
|
||||
imageCache := NewLocalImageCache(file, c)
|
||||
if err := imageCache.Load(); err != nil {
|
||||
c.cachedImages[imageCache.GetImageId()] = imageCache
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: AgentImageCacheManager
|
||||
type SAgentImageCacheManager struct {
|
||||
storagemanager *SStorageManager
|
||||
}
|
||||
|
||||
func NewAgentImageCacheManager(storagemanager *SStorageManager) *SAgentImageCacheManager {
|
||||
return &SAgentImageCacheManager{storagemanager}
|
||||
}
|
||||
|
||||
type SRbdImageCacheManager struct {
|
||||
SBaseImageCacheManager
|
||||
pool, prefix string
|
||||
storage IStorage
|
||||
}
|
||||
|
||||
func NewRbdImageCacheManager() *SRbdImageCacheManager {
|
||||
// TODO
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package storageman
|
||||
|
||||
import "os"
|
||||
|
||||
type SLocalDisk struct {
|
||||
*SBaseDisk
|
||||
}
|
||||
|
||||
func NewLocalDisk(storage IStorage, id string) *SLocalDisk {
|
||||
var ret = new(SLocalDisk)
|
||||
ret.SBaseDisk = NewBaseDisk(storage, id)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) GetId() string {
|
||||
return d.Id
|
||||
}
|
||||
|
||||
func (d *SLocalDisk) Probe() bool {
|
||||
if _, err := os.Stat(d.getPath()); !os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
// TODO alter ??
|
||||
return false
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
type IStorage interface {
|
||||
StorageType() string
|
||||
GetPath() string
|
||||
GetFreeSizeMb() int
|
||||
|
||||
// Find owner disks first, if not found, call create disk
|
||||
GetDiskById(diskId string) IDisk
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
package storageman
|
||||
|
||||
import "yunion.io/x/log"
|
||||
|
||||
type SLocalStorage struct {
|
||||
*SBaseStorage
|
||||
SBaseStorage
|
||||
}
|
||||
|
||||
func NewLocalStorage(manager *SStorageManager, path string) *SLocalStorage {
|
||||
var ret = new(SLocalStorage)
|
||||
ret.SBaseStorage = NewBaseStorage(manager, path)
|
||||
ret.SBaseStorage = *NewBaseStorage(manager, path)
|
||||
ret.StartSnapshotRecycle()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *SLocalStorage) StorageType() string {
|
||||
return "local"
|
||||
return storagetypes.STORAGE_LOCAL
|
||||
}
|
||||
|
||||
func (s *SLocalStorage) GetDiskById(diskId string) IDisk {
|
||||
@@ -28,11 +30,13 @@ func (s *SLocalStorage) CreateDisk(diskId string) IDisk {
|
||||
s.DiskLock.Lock()
|
||||
defer s.DiskLock.Unlock()
|
||||
var disk = NewLocalDisk(s, diskId)
|
||||
if disk.Probe() {
|
||||
if err := disk.Probe(); err != nil {
|
||||
s.Disks = append(s.Disks, disk)
|
||||
return disk
|
||||
} else {
|
||||
log.Errorln(err)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SLocalStorage) StartSnapshotRecycle() {
|
||||
@@ -1,22 +1,25 @@
|
||||
package storageman
|
||||
|
||||
import (
|
||||
"yunion.io/x/log"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/hostman/options"
|
||||
)
|
||||
|
||||
/***************************************************************************/
|
||||
/****************************StorageManager*********************************/
|
||||
/***************************************************************************/
|
||||
|
||||
const MINIMAL_FREE_SPACE = 128
|
||||
|
||||
type SStorageManager struct {
|
||||
storages []IStorage
|
||||
LocalStorageImagecache IStorageCache
|
||||
storages []IStorage
|
||||
AgentStorage IStorage
|
||||
LocalStorageImagecacheManager IImageCacheManger
|
||||
AgentStorageImagecacheManager IImageCacheManger
|
||||
NfsStorageImagecacheMangers []IImageCacheManger
|
||||
}
|
||||
|
||||
func NewStorageManager() *SStorageManager {
|
||||
func NewStorageManager() (*SStorageManager, error) {
|
||||
var ret = new(SStorageManager)
|
||||
ret.storages = make([]IStorage, 0)
|
||||
var allFull = true
|
||||
@@ -36,12 +39,97 @@ func NewStorageManager() *SStorageManager {
|
||||
allFull = False
|
||||
}
|
||||
if allFull {
|
||||
log.Fatalf("Not enough storage space!")
|
||||
return nil, fmt.Errorf("Not enough storage space!")
|
||||
}
|
||||
if err := ret.initLocalStorageImagecache(); err != nil {
|
||||
return nil, fmt.Errorf("Init Local storage image cache failed: %s", err)
|
||||
}
|
||||
ret.initLocalStorageImagecache()
|
||||
ret.initAgentStorageImagecache()
|
||||
ret.initAgentStorage()
|
||||
return ret
|
||||
if err := ret.initAgentStorage(); err != nil {
|
||||
return nil, fmt.Errorf("Init agent storage failed: %s", err)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *SStorageManager) getLeasedUsedLocalStorage(cacheDir string, limit int) (string, error) {
|
||||
var maxFree int
|
||||
var spath string
|
||||
var maxStorage IStorage
|
||||
for _, storage := range s.storages {
|
||||
if _, ok := storage.(*SLocalStorage); ok {
|
||||
cachePath := path.Join(storage.GetPath(), cacheDir)
|
||||
if _, err := os.Stat(cachePath); !os.IsNotExist(err) {
|
||||
spath = cachePath
|
||||
break
|
||||
}
|
||||
free := storage.GetFreeSizeMb()
|
||||
if maxFree < free {
|
||||
maxFree = free
|
||||
maxStorage = storage
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(spath) == 0 {
|
||||
if maxFree >= limit*1024 {
|
||||
spath = path.Join(maxStorage.GetPath(), cacheDir)
|
||||
} else {
|
||||
return "", fmt.Errorf("No local storage has free space larger than %dGB", limit)
|
||||
}
|
||||
}
|
||||
return spath, nil
|
||||
}
|
||||
|
||||
func (s *SStorageManager) initLocalStorageImagecache() error {
|
||||
var cacheDir = "image_cache"
|
||||
cachePath := options.HostOptions.ImageCachePath
|
||||
limit := options.HostOptions.ImageCacheLimit
|
||||
if len(cachePath) == 0 {
|
||||
var err error
|
||||
cachePath, err = s.getLeasedUsedLocalStorage(cacheDir, limit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(cachePath) == 0 {
|
||||
s.LocalStorageImagecacheManager = NewLocalImageCacheManager(s, cachePath, limit, true, "")
|
||||
return nil
|
||||
} else {
|
||||
fmt.Errorf("Cannot allocate image cache storage")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SStorageManager) initAgentStorageImagecache() {
|
||||
s.AgentStorageImagecacheManager = NewAgentImageCacheManager(s)
|
||||
}
|
||||
|
||||
func (s *SStorageManager) initAgentStorage() error {
|
||||
var cacheDir = "agent_tmp"
|
||||
var spath = options.HostOptions.AgentTempPath
|
||||
var limit = options.HostOptions.AgentTempLimit
|
||||
if len(spath) == 0 {
|
||||
var err error
|
||||
spath, err = s.getLeasedUsedLocalStorage(cacheDir, limit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(spath) != nil {
|
||||
// TODO: NewAgentStorage
|
||||
s.AgentStorage = NewAgentStorage(s, spath)
|
||||
} else {
|
||||
return fmt.Errorf("Cannot allocate agent storage")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SStorageManager) AddNfsStorage(storagecacheId, cachePath string) {
|
||||
if len(cachePath) == 0 {
|
||||
return
|
||||
}
|
||||
if s.NfsStorageImagecacheMangers == nil {
|
||||
s.NfsStorageImagecacheMangers = make(map[string]IImageCacheManger, 0)
|
||||
}
|
||||
s.NfsStorageImagecacheMangers[storagecacheId] = NewLocalImageCacheManager(s, cachePath,
|
||||
options.HostOptions.ImageCacheLimit, true, storagecacheId)
|
||||
}
|
||||
|
||||
func (s *SStorageManager) GetStorageDisk(storageId, diskId string) IDisk {
|
||||
@@ -51,17 +139,26 @@ func (s *SStorageManager) GetStorageDisk(storageId, diskId string) IDisk {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SStorageManager) initLocalStorageImagecache() {
|
||||
var cacheDir = "image_cache"
|
||||
cachePath := options.HostOptions.ImageCachePath
|
||||
limit := options.HostOptions.ImageCacheLimit
|
||||
if len(cachePath) == 0 {
|
||||
cachePath = s.getLeasedUsedLocalStorage(cacheDir, limit)
|
||||
}
|
||||
if len(cachePath) == 0 {
|
||||
// TODO NewLocalImageCacheManager
|
||||
s.LocalStorageImagecache = NewLocalImageCacheManager(s, cachePath, limit, true)
|
||||
} else {
|
||||
log.Fatalf("Cannot allocate image cache storage")
|
||||
func (s *SStorageManager) GetStorageByPath(sPath string) IStorage {
|
||||
for _, storage := range s.storages {
|
||||
if storage.GetPath() == sPath {
|
||||
return storage
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SStorageManager) GetDiskByPath(diskPath string) IDisk {
|
||||
pos := strings.LastIndex(diskPath, "/")
|
||||
sPath := path[:pos]
|
||||
diskId := path[pos+1:]
|
||||
pos = strings.LastIndex(diskId, ".")
|
||||
if pos > 0 {
|
||||
diskId = diskId[:pos]
|
||||
}
|
||||
storage := s.GetStorageByPath(sPath)
|
||||
if storage != nil {
|
||||
return storage.GetDiskById(diskId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user