Merge pull request #746 from wanyaoqi/feature/wyq/image-do-probe-on-upload

featrue: Image probe info on upload
This commit is contained in:
yunion-ci-robot
2019-05-16 17:34:34 +08:00
committed by GitHub
20 changed files with 425 additions and 38 deletions
+11
View File
@@ -19,6 +19,17 @@ const (
ImageTypeISO = TImageType("iso")
LocalFilePrefix = "file://"
// image properties
IMAGE_OS_ARCH = "os_arch"
IMAGE_OS_DISTRO = "os_distribution"
IMAGE_OS_TYPE = "os_type"
IMAGE_OS_VERSION = "os_version"
IMAGE_UEFI_SUPPORT = "uefi_support"
IMAGE_IS_LVM_PARTITION = "is_lvm_partition"
IMAGE_IS_READONLY = "is_readonly"
IMAGE_PARTITION_TYPE = "partition_type"
IMAGE_INSTALLED_CLOUDINIT = "installed_cloud_init"
)
var (
+5 -3
View File
@@ -74,9 +74,11 @@ const (
ACT_SPLIT = "net_split"
ACT_MERGE = "net_merge"
ACT_SAVING = "saving"
ACT_SAVE = "save"
ACT_SAVE_FAIL = "save_fail"
ACT_SAVING = "saving"
ACT_SAVE = "save"
ACT_SAVE_FAIL = "save_fail"
ACT_PROBE = "probe"
ACT_PROBE_FAIL = "probe_fail"
ACT_SWITCHED = "switched"
ACT_SWITCH_FAILED = "switch_failed"
+7
View File
@@ -38,6 +38,7 @@ import (
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
imageapi "yunion.io/x/onecloud/pkg/apis/image"
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
"yunion.io/x/onecloud/pkg/cloudcommon/cmdline"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
@@ -884,6 +885,12 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
input.Disks[0] = diskConfig
imgProperties := diskConfig.ImageProperties
imgSupportUEFI := imgProperties[imageapi.IMAGE_UEFI_SUPPORT] == "true"
imgIsWindows := imgProperties[imageapi.IMAGE_OS_TYPE] == "Windows"
if imgSupportUEFI && imgIsWindows && len(input.IsolatedDevices) > 0 {
input.Bios = "UEFI" // windows gpu passthrough
}
if input.Cdrom != "" {
cdromStr := input.Cdrom
image, err := parseIsoInfo(ctx, userCred, cdromStr)
+1 -1
View File
@@ -65,7 +65,7 @@ func AddDownloadHandler(prefix string, app *appsrv.Application) {
func customizeHandlerInfo(info *appsrv.SHandlerInfo) {
switch info.GetName(nil) {
case "disk_download", "download", "snapshot_download":
info.SetProcessTimeout(time.Minute * 30).SetWorkerManager(streamingWorkerMan)
info.SetProcessTimeout(time.Minute * 60).SetWorkerManager(streamingWorkerMan)
}
}
+12 -4
View File
@@ -109,11 +109,19 @@ func (d *sGuestRootFsDriver) CommitChanges(rootfs IDiskPartition) error {
return nil
}
func (d *sGuestRootFsDriver) DetectIsUEFISupport(IDiskPartition) bool {
return false
}
func (l *sGuestRootFsDriver) IsCloudinitInstall() bool {
return false
}
type SReleaseInfo struct {
Distro string
Version string
Arch string
Language string
Distro string `json:"os_distribution,omitempty"`
Version string `json:"os_version,omitempty"`
Arch string `json:"os_arch,omitempty"`
Language string `json:"os_language,omitempty"`
}
func newReleaseInfo(distro, version, arch string) *SReleaseInfo {
@@ -41,8 +41,11 @@ type IDiskPartition interface {
SupportSerialPorts() bool
Mount() bool
MountPartReadOnly() bool
Umount() bool
GetMountPath() string
IsReadonly() bool
GetPhysicalPartitionType() string
}
type IRootFsDriver interface {
@@ -69,6 +72,8 @@ type IRootFsDriver interface {
DisableSerialConsole(IDiskPartition) error
CommitChanges(IDiskPartition) error
DeployFiles(deploys []jsonutils.JSONObject) error
DetectIsUEFISupport(IDiskPartition) bool
IsCloudinitInstall() bool
PrepareFsForTemplate(IDiskPartition) error
}
+8
View File
@@ -431,6 +431,14 @@ func (l *sLinuxRootFs) disableSerialConsoleSystemd(rootFs IDiskPartition) {
}
}
func (l *sLinuxRootFs) DetectIsUEFISupport(part IDiskPartition) bool {
return part.Exists("/efi", false)
}
func (l *sLinuxRootFs) IsCloudinitInstall() bool {
return l.GetPartition().Exists("/usr/bin/cloud-init", false)
}
type sDebianLikeRootFs struct {
*sLinuxRootFs
}
+19
View File
@@ -476,3 +476,22 @@ func (w *SWindowsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []jsonu
w.putGuestScriptContents("/windows/mountdisk.js", WinScriptMountDisk)
return nil
}
func (w *SWindowsRootFs) DetectIsUEFISupport(part IDiskPartition) bool {
content, err := w.rootFs.FileGetContents("/windows/panther/setupact.log", true)
if err != nil {
log.Errorln(err)
return false
}
contentStr := string(content)
sep := "Detected boot environment: "
idx := strings.Index(contentStr, sep)
if idx < 0 {
return false
}
if strings.HasPrefix(contentStr[idx+len(sep):], "EFI") ||
strings.HasPrefix(contentStr[idx+len(sep):], "UEFI") {
return true
}
return false
}
+48 -2
View File
@@ -32,19 +32,49 @@ type SKVMGuestDiskPartition struct {
partDev string
fs string
readonly bool
readonly bool
sourceDev string
IsLVMPart bool
}
func NewKVMGuestDiskPartition(devPath string) *SKVMGuestDiskPartition {
func NewKVMGuestDiskPartition(devPath, sourceDev string, isLVM bool) *SKVMGuestDiskPartition {
var res = new(SKVMGuestDiskPartition)
res.partDev = devPath
res.fs = res.getFsFormat()
res.sourceDev = sourceDev
res.IsLVMPart = isLVM
fileutils2.CleanFailedMountpoints()
mountPath := fmt.Sprintf("/tmp/%s", strings.Replace(devPath, "/", "_", -1))
res.SLocalGuestFS = NewLocalGuestFS(mountPath)
return res
}
func (p *SKVMGuestDiskPartition) GetPhysicalPartitionType() string {
dev := p.partDev
if p.IsLVMPart {
// for lvm part, sourceDev like /dev/nbdxpx
idx := strings.LastIndexByte(p.sourceDev, 'p')
if idx > 0 {
dev = p.sourceDev[:idx]
} else {
dev = p.sourceDev
}
}
cmd := fmt.Sprintf(`fdisk -l %s | grep "Disk label type:"`, dev)
output, err := procutils.NewCommand("sh", "-c", cmd).Run()
if err != nil {
log.Errorf("get disk label type error %s", output)
return ""
}
idx := strings.Index(string(output), "Disk label type:")
tp := strings.TrimSpace(string(output)[idx+len("Disk label type:"):])
if tp == "dos" {
return "mbr"
} else {
return tp
}
}
func (p *SKVMGuestDiskPartition) GetPartDev() string {
return p.partDev
}
@@ -57,6 +87,22 @@ func (p *SKVMGuestDiskPartition) getFsFormat() string {
return fileutils2.GetFsFormat(p.partDev)
}
func (p *SKVMGuestDiskPartition) MountPartReadOnly() bool {
if len(p.fs) == 0 || utils.IsInStringArray(p.fs, []string{"swap", "btrfs"}) {
return false
}
// no fsck, becasue read only
err := p.mount(true)
if err != nil {
log.Errorf("SKVMGuestDiskPartition mount as readonly error: %s", err)
return false
}
p.readonly = true
return true
}
func (p *SKVMGuestDiskPartition) Mount() bool {
if len(p.fs) == 0 || utils.IsInStringArray(p.fs, []string{"swap", "btrfs"}) {
return false
+12
View File
@@ -113,6 +113,18 @@ func (p *SSHPartition) osPathExists(path string) bool {
return true
}
func (p *SSHPartition) MountPartReadOnly() bool {
return false // Not implement
}
func (p *SSHPartition) IsReadonly() bool {
return false // sshpart not implement mount as readonly
}
func (p *SSHPartition) GetPhysicalPartitionType() string {
return "" // Not implement
}
func (p *SSHPartition) Mount() bool {
if err := p.osMkdirP(p.mountPath, 0); err != nil {
log.Errorf("SSHPartition mount error: %s", err)
+6 -1
View File
@@ -35,6 +35,7 @@ import (
"yunion.io/x/onecloud/pkg/hostman/metadata"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/util/sysutils"
)
type SHostService struct {
@@ -43,8 +44,12 @@ type SHostService struct {
func (host *SHostService) StartService() {
common_options.ParseOptions(&options.HostOptions, os.Args, "host.conf", "host")
options.HostOptions.EnableRbac = false // disable rbac
isRoot := sysutils.IsRootPermission()
if !isRoot {
log.Fatalf("host service must running with root permissions")
}
options.HostOptions.EnableRbac = false // disable rbac
app := app_common.InitApp(&options.HostOptions.CommonOptions, false)
hostInstance := hostinfo.Instance()
if err := hostInstance.Init(); err != nil {
+37 -3
View File
@@ -58,6 +58,10 @@ func NewKVMGuestDisk(imagePath string) *SKVMGuestDisk {
return ret
}
func (d *SKVMGuestDisk) IsLVMPartition() bool {
return len(d.lvms) > 0
}
func (d *SKVMGuestDisk) Connect() bool {
d.nbdDev = nbd.GetNBDManager().AcquireNbddev()
if len(d.nbdDev) == 0 {
@@ -141,7 +145,7 @@ func (d *SKVMGuestDisk) findPartitions() error {
}
for i := 0; i < len(files); i++ {
if files[i].Name() != dev && strings.HasPrefix(files[i].Name(), dev+"p") {
var part = guestfs.NewKVMGuestDiskPartition(path.Join(devpath, files[i].Name()))
var part = guestfs.NewKVMGuestDiskPartition(path.Join(devpath, files[i].Name()), "", false)
d.partitions = append(d.partitions, part)
}
}
@@ -259,9 +263,35 @@ func (d *SKVMGuestDisk) Disconnect() bool {
}
}
func (d *SKVMGuestDisk) MountKvmRootfs() fsdriver.IRootFsDriver {
func (d *SKVMGuestDisk) DetectIsUEFISupport(rootfs fsdriver.IRootFsDriver) bool {
for i := 0; i < len(d.partitions); i++ {
if d.partitions[i].Mount() {
if d.partitions[i].IsMounted() {
if rootfs.DetectIsUEFISupport(d.partitions[i]) {
return true
}
} else {
if d.partitions[i].Mount() {
support := rootfs.DetectIsUEFISupport(d.partitions[i])
d.partitions[i].Umount()
if support {
return true
}
}
}
}
return false
}
func (d *SKVMGuestDisk) MountKvmRootfs() fsdriver.IRootFsDriver {
return d.mountKvmRootfs(false)
}
func (d *SKVMGuestDisk) mountKvmRootfs(readonly bool) fsdriver.IRootFsDriver {
for i := 0; i < len(d.partitions); i++ {
mountFunc := d.partitions[i].Mount
if readonly {
mountFunc = d.partitions[i].MountPartReadOnly
}
if mountFunc() {
if fs := guestfs.DetectRootFs(d.partitions[i]); fs != nil {
log.Infof("Use rootfs %s, partition %s",
fs, d.partitions[i].GetPartDev())
@@ -274,6 +304,10 @@ func (d *SKVMGuestDisk) MountKvmRootfs() fsdriver.IRootFsDriver {
return nil
}
func (d *SKVMGuestDisk) MountKvmRootfsReadOnly() fsdriver.IRootFsDriver {
return d.mountKvmRootfs(true)
}
func (d *SKVMGuestDisk) UmountKvmRootfs(fd fsdriver.IRootFsDriver) {
if part := fd.GetPartition(); part != nil {
part.Umount()
+1 -1
View File
@@ -192,7 +192,7 @@ func (p *SKVMGuestLVMPartition) FindPartitions() []*guestfs.SKVMGuestDiskPartiti
parts := []*guestfs.SKVMGuestDiskPartition{}
for _, f := range files {
partPath := fmt.Sprintf("/dev/%s/%s", p.vgname, f.Name())
part := guestfs.NewKVMGuestDiskPartition(partPath)
part := guestfs.NewKVMGuestDiskPartition(partPath, p.partDev, true)
parts = append(parts, part)
}
return parts
+37 -16
View File
@@ -117,7 +117,7 @@ type SImage struct {
func (manager *SImageManager) CustomizeHandlerInfo(info *appsrv.SHandlerInfo) {
switch info.GetName(nil) {
case "get_details", "create", "update":
info.SetProcessTimeout(time.Minute * 30).SetWorkerManager(imgStreamingWorkerMan)
info.SetProcessTimeout(time.Minute * 120).SetWorkerManager(imgStreamingWorkerMan)
}
}
@@ -208,7 +208,7 @@ func (self *SImage) CustomizedGetDetailsBody(ctx context.Context, userCred mccli
}
defer fp.Close()
_, err = streamutils.StreamPipe(fp, appParams.Response)
_, err = streamutils.StreamPipe(fp, appParams.Response, false)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
@@ -374,19 +374,20 @@ func (self *SImage) saveFailed(userCred mcclient.TokenCredential, msg string) {
db.OpsLog.LogEvent(self, db.ACT_SAVE_FAIL, msg, userCred)
}
func (self *SImage) saveImageFromStream(localPath string, reader io.Reader) (*streamutils.SStreamProperty, error) {
func (self *SImage) saveImageFromStream(localPath string, reader io.Reader, calChecksum bool) (*streamutils.SStreamProperty, error) {
fp, err := os.Create(localPath)
if err != nil {
return nil, err
}
defer fp.Close()
return streamutils.StreamPipe(reader, fp)
return streamutils.StreamPipe(reader, fp, calChecksum)
}
func (self *SImage) SaveImageFromStream(reader io.Reader) error {
//Image always do probe and customize after save from stream
func (self *SImage) SaveImageFromStream(reader io.Reader, calChecksum bool) error {
localPath := self.GetPath("")
sp, err := self.saveImageFromStream(localPath, reader)
sp, err := self.saveImageFromStream(localPath, reader, calChecksum)
if err != nil {
log.Errorf("saveImageFromStream fail %s", err)
return err
@@ -401,15 +402,20 @@ func (self *SImage) SaveImageFromStream(reader io.Reader) error {
format = string(img.Format)
virtualSizeBytes = img.SizeBytes
fastChksum, err := fileutils2.FastCheckSum(localPath)
if err != nil {
return err
var fastChksum string
if calChecksum {
fastChksum, err = fileutils2.FastCheckSum(localPath)
if err != nil {
return err
}
}
db.Update(self, func() error {
self.Size = sp.Size
self.Checksum = sp.CheckSum
self.FastHash = fastChksum
if calChecksum {
self.Checksum = sp.CheckSum
self.FastHash = fastChksum
}
self.Location = fmt.Sprintf("%s%s", LocalFilePrefix, localPath)
if len(format) > 0 {
self.DiskFormat = format
@@ -443,15 +449,14 @@ func (self *SImage) PostCreate(ctx context.Context, userCred mcclient.TokenCrede
db.OpsLog.LogEvent(self, db.ACT_SAVING, "create upload", userCred)
self.SetStatus(userCred, api.IMAGE_STATUS_SAVING, "create upload")
err := self.SaveImageFromStream(appParams.Request.Body)
err := self.SaveImageFromStream(appParams.Request.Body, false)
if err != nil {
self.OnSaveFailed(ctx, userCred, fmt.Sprintf("create upload fail %s", err))
return
}
self.OnSaveSuccess(ctx, userCred, "create upload success")
self.StartImageConvertTask(ctx, userCred, "")
self.ImageProbeAndCustomization(ctx, userCred, true)
} else {
copyFrom := appParams.Request.Header.Get(modules.IMAGE_META_COPY_FROM)
if len(copyFrom) > 0 {
@@ -460,6 +465,22 @@ func (self *SImage) PostCreate(ctx context.Context, userCred mcclient.TokenCrede
}
}
// After image probe and customization, image size and checksum changed
// will recalculate checksum in the end
func (self *SImage) ImageProbeAndCustomization(
ctx context.Context, userCred mcclient.TokenCredential, doConvertAfterProbe bool,
) error {
data := jsonutils.NewDict()
data.Set("do_convert", jsonutils.NewBool(doConvertAfterProbe))
task, err := taskman.TaskManager.NewTask(
ctx, "ImageProbeTask", self, userCred, data, "", "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
}
func (self *SImage) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if self.Status != api.IMAGE_STATUS_QUEUED {
appParams := appsrv.AppContextGetParams(ctx)
@@ -471,14 +492,14 @@ func (self *SImage) ValidateUpdateData(ctx context.Context, userCred mcclient.To
if appParams != nil {
if appParams.Request.ContentLength > 0 {
self.SetStatus(userCred, api.IMAGE_STATUS_SAVING, "update start upload")
err := self.SaveImageFromStream(appParams.Request.Body)
err := self.SaveImageFromStream(appParams.Request.Body, false)
if err != nil {
self.OnSaveFailed(ctx, userCred, fmt.Sprintf("update upload failed %s", err))
return nil, httperrors.NewGeneralError(err)
}
self.OnSaveSuccess(ctx, userCred, "update upload success")
data.Remove("status")
self.StartImageConvertTask(ctx, userCred, "")
self.ImageProbeAndCustomization(ctx, userCred, true)
} else {
copyFrom := appParams.Request.Header.Get(modules.IMAGE_META_COPY_FROM)
if len(copyFrom) > 0 {
+6
View File
@@ -33,6 +33,7 @@ import (
_ "yunion.io/x/onecloud/pkg/image/tasks"
"yunion.io/x/onecloud/pkg/image/torrent"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/sysutils"
)
const (
@@ -45,6 +46,11 @@ func StartService() {
dbOpts := &opts.DBOptions
common_options.ParseOptions(opts, os.Args, "glance-api.conf", SERVICE_TYPE)
isRoot := sysutils.IsRootPermission()
if !isRoot {
log.Fatalf("glance service must running with root permissions")
}
if opts.PortV2 > 0 {
log.Infof("Port V2 %d is specified, use v2 port", opts.PortV2)
opts.Port = opts.PortV2
+2 -2
View File
@@ -50,7 +50,7 @@ func (self *ImageCopyFromUrlTask) OnInit(ctx context.Context, obj db.IStandalone
if err != nil {
return nil, err
}
err = image.SaveImageFromStream(resp.Body)
err = image.SaveImageFromStream(resp.Body, false)
if err != nil {
return nil, err
}
@@ -61,7 +61,7 @@ func (self *ImageCopyFromUrlTask) OnInit(ctx context.Context, obj db.IStandalone
func (self *ImageCopyFromUrlTask) OnImageImportComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
image := obj.(*models.SImage)
image.OnSaveTaskSuccess(self, self.UserCred, "create upload success")
image.StartImageConvertTask(ctx, self.UserCred, "")
image.ImageProbeAndCustomization(ctx, self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
+186
View File
@@ -0,0 +1,186 @@
package tasks
import (
"context"
"fmt"
"os"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/image"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/image/models"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type ImageProbeTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(ImageProbeTask{})
}
func (self *ImageProbeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
image := obj.(*models.SImage)
self.StartImageProbe(ctx, image)
}
func (self *ImageProbeTask) StartImageProbe(ctx context.Context, image *models.SImage) {
probeErr := self.doProbe(ctx, image)
// if failed, set image unavailable, because size and chksum changed
if err := self.updateImageMetadata(ctx, image); err != nil {
image.SetStatus(self.UserCred, api.IMAGE_STATUS_KILLED,
fmt.Sprintf("Image update failed after probe %s", err))
self.SetStageFailed(ctx, err.Error())
return
}
if probeErr == nil {
self.OnProbeSuccess(ctx, image)
} else {
self.OnProbeFailed(ctx, image, probeErr.Error())
}
}
func (self *ImageProbeTask) doProbe(ctx context.Context, image *models.SImage) error {
diskPath := image.GetPath("")
kvmDisk := storageman.NewKVMGuestDisk(diskPath)
defer kvmDisk.Disconnect()
if !kvmDisk.Connect() {
return fmt.Errorf("Disk connector failed to connect image")
}
// Fsck is executed during mount
rootfs := kvmDisk.MountKvmRootfs()
if rootfs == nil {
return fmt.Errorf("Failed mounting rootfs for kvm disk")
}
defer kvmDisk.UmountKvmRootfs(rootfs)
imageInfo := self.getImageInfo(kvmDisk, rootfs)
self.updateImageInfo(ctx, image, imageInfo)
return nil
}
func (self *ImageProbeTask) updateImageMetadata(
ctx context.Context, image *models.SImage,
) error {
imagePath := image.GetPath("")
fp, err := os.Open(imagePath)
if err != nil {
return err
}
defer fp.Close()
stat, err := fp.Stat()
if err != nil {
return err
}
chksum, err := fileutils2.MD5(imagePath)
if err != nil {
return err
}
fastchksum, err := fileutils2.FastCheckSum(imagePath)
if err != nil {
return err
}
_, err = db.Update(image, func() error {
image.Size = stat.Size()
image.Checksum = chksum
image.FastHash = fastchksum
return nil
})
if err != nil {
return err
}
return nil
}
func (self *ImageProbeTask) updateImageInfo(ctx context.Context, image *models.SImage, imageInfo *sImageInfo) {
imageProperties := jsonutils.Marshal(imageInfo.osInfo).(*jsonutils.JSONDict)
if len(imageInfo.OsType) > 0 {
imageProperties.Set(api.IMAGE_OS_TYPE, jsonutils.NewString(imageInfo.OsType))
}
if imageInfo.IsUEFISupport {
imageProperties.Set(api.IMAGE_UEFI_SUPPORT, jsonutils.JSONTrue)
}
if imageInfo.IsLVMPartition {
imageProperties.Set(api.IMAGE_IS_LVM_PARTITION, jsonutils.JSONTrue)
}
if imageInfo.IsReadonly {
imageProperties.Set(api.IMAGE_IS_READONLY, jsonutils.JSONTrue)
}
if imageInfo.IsInstalledCloudInit {
imageProperties.Set(api.IMAGE_INSTALLED_CLOUDINIT, jsonutils.JSONTrue)
}
if len(imageInfo.PhysicalPartitionType) > 0 {
imageProperties.Set(api.IMAGE_PARTITION_TYPE, jsonutils.NewString(imageInfo.PhysicalPartitionType))
}
models.ImagePropertyManager.SaveProperties(ctx, self.UserCred, image.Id, imageProperties)
}
type sImageInfo struct {
osInfo *fsdriver.SReleaseInfo
OsType string
IsUEFISupport bool
IsLVMPartition bool
IsReadonly bool
PhysicalPartitionType string // mbr or gbt or unknown
IsInstalledCloudInit bool
}
func (self *ImageProbeTask) getImageInfo(kvmDisk *storageman.SKVMGuestDisk, rootfs fsdriver.IRootFsDriver) *sImageInfo {
partition := rootfs.GetPartition()
return &sImageInfo{
osInfo: rootfs.GetReleaseInfo(partition),
OsType: rootfs.GetOs(),
IsUEFISupport: kvmDisk.DetectIsUEFISupport(rootfs),
IsLVMPartition: kvmDisk.IsLVMPartition(),
IsReadonly: partition.IsReadonly(),
PhysicalPartitionType: partition.GetPhysicalPartitionType(),
IsInstalledCloudInit: rootfs.IsCloudinitInstall(),
}
}
func (self *ImageProbeTask) OnProbeFailed(ctx context.Context, image *models.SImage, reason string) {
log.Infof("Image %s Probe Failed ...", image.Name)
db.OpsLog.LogEvent(image, db.ACT_PROBE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithContext(ctx, image, logclient.ACT_IMAGE_PROBE, reason, self.UserCred, false)
if jsonutils.QueryBoolean(self.Params, "do_convert", false) {
self.SetStage("OnConvertComplete", nil)
image.StartImageConvertTask(ctx, self.UserCred, self.GetId())
} else {
self.SetStageFailed(ctx, reason)
}
}
func (self *ImageProbeTask) OnProbeSuccess(ctx context.Context, image *models.SImage) {
log.Infof("Image %s Probe Success ...", image.Name)
db.OpsLog.LogEvent(image, db.ACT_PROBE, "Image Probe Success", self.UserCred)
logclient.AddActionLogWithContext(
ctx, image, logclient.ACT_IMAGE_PROBE, "Image Probe Success", self.UserCred, true)
if jsonutils.QueryBoolean(self.Params, "do_convert", false) {
self.SetStage("OnConvertComplete", nil)
image.StartImageConvertTask(ctx, self.UserCred, self.GetId())
} else {
self.SetStageComplete(ctx, nil)
}
}
func (self *ImageProbeTask) OnConvertComplete(ctx context.Context, image *models.SImage, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
}
+3 -1
View File
@@ -68,6 +68,7 @@ var WhiteList = []string{
ACT_IMAGE_SAVE, ACT_RECYCLE_PREPAID, ACT_UNDO_RECYCLE_PREPAID,
ACT_FETCH, ACT_VM_CHANGE_NIC, ACT_HOST_IMPORT_LIBVIRT_SERVERS,
ACT_GUEST_CREATE_FROM_IMPORT, ACT_DISK_CREATE_SNAPSHOT,
ACT_IMAGE_PROBE,
}
const (
@@ -138,7 +139,8 @@ const (
ACT_LB_REMOVE_LISTENER_RULE = "移除负载均衡转发规则"
ACT_DELETE_BACKUP = "删除备份机"
ACT_IMAGE_SAVE = "上传镜像"
ACT_IMAGE_SAVE = "上传镜像"
ACT_IMAGE_PROBE = "镜像检测"
ACT_RECYCLE_PREPAID = "池化预付费主机"
ACT_UNDO_RECYCLE_PREPAID = "取消池化预付费主机"
+12 -4
View File
@@ -17,6 +17,7 @@ package streamutils
import (
"crypto/md5"
"fmt"
"hash"
"io"
)
@@ -25,17 +26,22 @@ type SStreamProperty struct {
Size int64
}
func StreamPipe(reader io.Reader, writer io.Writer) (*SStreamProperty, error) {
func StreamPipe(reader io.Reader, writer io.Writer, CalChecksum bool) (*SStreamProperty, error) {
sp := SStreamProperty{}
md5sum := md5.New()
var md5sum hash.Hash
if CalChecksum {
md5sum = md5.New()
}
buf := make([]byte, 4096)
for {
n, err := reader.Read(buf)
if n > 0 {
sp.Size += int64(n)
md5sum.Write(buf[:n])
if CalChecksum {
md5sum.Write(buf[:n])
}
offset := 0
for offset < n {
m, err := writer.Write(buf[offset:n])
@@ -53,6 +59,8 @@ func StreamPipe(reader io.Reader, writer io.Writer) (*SStreamProperty, error) {
}
}
sp.CheckSum = fmt.Sprintf("%x", md5sum.Sum(nil))
if CalChecksum {
sp.CheckSum = fmt.Sprintf("%x", md5sum.Sum(nil))
}
return &sp, nil
}
+7
View File
@@ -0,0 +1,7 @@
package sysutils
import "os"
func IsRootPermission() bool {
return os.Geteuid() == 0
}