Merge pull request #1603 from wanyaoqi/feature/wyq/storage-agent

host deploy agent
This commit is contained in:
yunion-ci-robot
2019-07-10 20:55:55 +08:00
committed by GitHub
94 changed files with 3488 additions and 1136 deletions
+1
View File
@@ -0,0 +1 @@
DESCRIPTION="Yunion Host Deploy Agent"
@@ -12,4 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package sshkeys // import "yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
package main
import "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployserver"
func main() {
deployer := deployserver.NewDeployService()
deployer.StartService()
}
+2
View File
@@ -61,6 +61,7 @@ require (
github.com/golang-plus/testing v1.0.0 // indirect
github.com/golang-plus/uuid v1.0.0
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
github.com/golang/protobuf v1.3.1
github.com/google/btree v1.0.0 // indirect
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/google/gopacket v1.1.17
@@ -138,6 +139,7 @@ require (
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
google.golang.org/appengine v1.3.0 // indirect
google.golang.org/genproto v0.0.0-20181218023534-67d6565462c5 // indirect
google.golang.org/grpc v1.19.0
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
+2
View File
@@ -167,6 +167,8 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+5 -4
View File
@@ -50,11 +50,11 @@ import (
"yunion.io/x/onecloud/pkg/baremetal/utils/disktool"
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
"yunion.io/x/onecloud/pkg/hostman/guestfs/sshpart"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
@@ -1704,18 +1704,19 @@ func (s *SBaremetalServer) SyncPartitionSize(term *ssh.Client, parts []*disktool
}
func (s *SBaremetalServer) DoDeploy(term *ssh.Client, data jsonutils.JSONObject, isInit bool) (jsonutils.JSONObject, error) {
publicKey := sshkeys.GetKeys(data)
publicKey := deployapi.GetKeys(data)
deploys, _ := data.GetArray("deploys")
password, _ := data.GetString("password")
resetPassword := jsonutils.QueryBoolean(data, "reset_password", false)
if resetPassword && len(password) == 0 {
password = seclib.RandomPassword(12)
}
deployInfo := guestfs.NewDeployInfo(publicKey, deploys, password, isInit, true, o.Options.LinuxDefaultRootUser, o.Options.WindowsDefaultAdminUser, false)
deployInfo := deployapi.NewDeployInfo(publicKey, deployapi.JsonDeploysToStructs(deploys),
password, isInit, true, o.Options.LinuxDefaultRootUser, o.Options.WindowsDefaultAdminUser, false)
return s.deployFs(term, deployInfo)
}
func (s *SBaremetalServer) deployFs(term *ssh.Client, deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error) {
func (s *SBaremetalServer) deployFs(term *ssh.Client, deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
raid, nonRaid, pcie, err := detect_storages.DetectStorageInfo(term, false)
if err != nil {
return nil, err
+1 -1
View File
@@ -50,7 +50,7 @@ func GetNicDHCPConfig(
routes := make([][]string, 0)
for _, route := range n.Routes {
routes = append(routes, []string{route[0], route[1]})
routes = append(routes, []string{route.Route[0], route.Route[1]})
}
conf := &dhcp.ResponseConfig{
+21 -1
View File
@@ -16,14 +16,18 @@ package service
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"syscall"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/pkg/util/signalutils"
"yunion.io/x/pkg/utils"
)
type IService interface {
@@ -38,6 +42,10 @@ type SServiceBase struct {
O *options.BaseOptions
}
func NewBaseService(service IService) *SServiceBase {
return &SServiceBase{Service: service}
}
func (s *SServiceBase) StartService() {
defer s.Service.OnExitService()
defer s.RemovePid()
@@ -78,3 +86,15 @@ func (s *SServiceBase) RemovePid() {
os.Remove(s.O.PidFile)
}
}
func (s *SServiceBase) SignalTrap(onExit func()) {
// dump goroutine stack
signalutils.RegisterSignal(func() {
utils.DumpAllGoroutineStack(log.Logger().Out)
}, syscall.SIGUSR1)
if onExit != nil {
quitSignals := []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM}
signalutils.RegisterSignal(onExit, quitSignals...)
}
signalutils.StartTrap()
}
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sshkeys
import "yunion.io/x/jsonutils"
type SSHKeys struct {
PublicKey string
DeletePublicKey string
AdminPublicKey string
ProjectPublicKey string
}
func GetKeys(data jsonutils.JSONObject) *SSHKeys {
var ret = new(SSHKeys)
ret.PublicKey, _ = data.GetString("public_key")
ret.DeletePublicKey, _ = data.GetString("delete_public_key")
ret.AdminPublicKey, _ = data.GetString("admin_public_key")
ret.ProjectPublicKey, _ = data.GetString("project_public_key")
return ret
}
+18 -41
View File
@@ -18,6 +18,8 @@ import (
"net"
"yunion.io/x/pkg/util/netutils"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
const (
@@ -30,21 +32,21 @@ var (
)
type SNic struct {
Type string `json:"nic_type"`
Domain string `json:"domain"`
Wire string `json:"wire"`
IpAddr string `json:"ip_addr"`
WireId string `json:"wire_id"`
NetId string `json:"net_id"`
Rate int64 `json:"rate"`
Mtu int64 `json:"mtu"`
Mac string `json:"mac"`
Dns string `json:"dns"`
MaskLen int8 `json:"masklen"`
Net string `json:"net"`
Gateway string `json:"gateway"`
LinkUp bool `json:"link_up"`
Routes []SRoute `json:"routes,omitempty"`
Type string `json:"nic_type"`
Domain string `json:"domain"`
Wire string `json:"wire"`
IpAddr string `json:"ip_addr"`
WireId string `json:"wire_id"`
NetId string `json:"net_id"`
Rate int64 `json:"rate"`
Mtu int64 `json:"mtu"`
Mac string `json:"mac"`
Dns string `json:"dns"`
MaskLen int8 `json:"masklen"`
Net string `json:"net"`
Gateway string `json:"gateway"`
LinkUp bool `json:"link_up"`
Routes []*deployapi.Routes `json:"routes,omitempty"`
}
func (n SNic) GetNetMask() string {
@@ -55,33 +57,8 @@ func (n SNic) GetMac() net.HardwareAddr {
return getMac(n.Mac)
}
type SRoute []string
type SServerNic struct {
Name string `json:"name"`
Index int `json:"index"`
Bridge string `json:"bridge"`
Domain string `json:"domain"`
Ip string `json:"ip"`
Vlan int `json:"vlan"`
Driver string `json:"driver"`
Masklen int `json:"masklen"`
Virtual bool `json:"virtual"`
Manual bool `json:"manual"`
WireId string `json:"wire_id"`
NetId string `json:"net_id"`
Mac string `json:"mac"`
BandWidth int `json:"bw"`
Dns string `json:"dns"`
Net string `json:"net"`
Interface string `json:"interface"`
Gateway string `json:"gateway"`
Ifname string `json:"ifname"`
Routes []SRoute `json:"routes,omitempty"`
NicType string `json:"nic_type,omitempty"`
LinkUp bool `json:"link_up,omitempty"`
Mtu int64 `json:"mtu,omitempty"`
TeamWith string `json:"team_with,omitempty"`
*deployapi.Nic
TeamingMaster *SServerNic `json:"-"`
TeamingSlaves []*SServerNic `json:"-"`
+14
View File
@@ -1,3 +1,17 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cloudprovider
type SServerSku struct {
+15 -10
View File
@@ -225,17 +225,22 @@ func (self *SKVMHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, ho
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
snapshotStorage := models.StorageManager.FetchStorageById(snapshot.StorageId)
snapshotHost := snapshotStorage.GetMasterHost()
if options.Options.SnapshotCreateDiskProtocol == "url" {
content.Set("snapshot_url",
jsonutils.NewString(fmt.Sprintf("%s/download/snapshots/%s/%s/%s",
snapshotHost.ManagerUri, snapshotStorage.Id, snapshot.DiskId, snapshot.Id)))
content.Set("snapshot_out_of_chain", jsonutils.NewBool(snapshot.OutOfChain))
} else if options.Options.SnapshotCreateDiskProtocol == "fuse" {
content.Set("snapshot_url", jsonutils.NewString(fmt.Sprintf("%s/snapshots/%s/%s",
snapshotHost.GetFetchUrl(true), snapshot.DiskId, snapshot.Id)))
if snapshotStorage.StorageType == api.STORAGE_LOCAL {
snapshotHost := snapshotStorage.GetMasterHost()
if options.Options.SnapshotCreateDiskProtocol == "url" {
content.Set("snapshot_url",
jsonutils.NewString(fmt.Sprintf("%s/download/snapshots/%s/%s/%s",
snapshotHost.ManagerUri, snapshotStorage.Id, snapshot.DiskId, snapshot.Id)))
content.Set("snapshot_out_of_chain", jsonutils.NewBool(snapshot.OutOfChain))
} else if options.Options.SnapshotCreateDiskProtocol == "fuse" {
content.Set("snapshot_url", jsonutils.NewString(fmt.Sprintf("%s/snapshots/%s/%s",
snapshotHost.GetFetchUrl(true), snapshot.DiskId, snapshot.Id)))
}
content.Set("protocol", jsonutils.NewString(options.Options.SnapshotCreateDiskProtocol))
} else {
content.Set("snapshot_url", jsonutils.NewString(snapshot.Location))
content.Set("protocol", jsonutils.NewString("location"))
}
content.Set("protocol", jsonutils.NewString(options.Options.SnapshotCreateDiskProtocol))
}
url := fmt.Sprintf("/disks/%s/create/%s", storage.Id, disk.Id)
+10 -1
View File
@@ -589,6 +589,14 @@ func (self *SDisk) AllowGetDetailsConvertSnapshot(ctx context.Context, userCred
}
func (self *SDisk) GetDetailsConvertSnapshot(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
needs, err := SnapshotManager.IsDiskSnapshotsNeedConvert(self.Id)
if err != nil {
return nil, httperrors.NewInternalServerError("Fetch snapshot count failed %s", err)
}
if !needs {
return nil, httperrors.NewBadRequestError("Disk %s don't need convert snapshots", self.Id)
}
deleteSnapshot := SnapshotManager.GetDiskFirstSnapshot(self.Id)
if deleteSnapshot == nil {
return nil, httperrors.NewNotFoundError("Can not get disk snapshot")
@@ -651,7 +659,8 @@ func (self *SDisk) PerformCreateSnapshot(ctx context.Context, userCred mcclient.
return nil, httperrors.NewBadRequestError("Disk dosen't attach guest??")
}
storage := self.GetStorage()
if guests[0].Hypervisor == api.HYPERVISOR_KVM && storage.StorageType != api.STORAGE_LOCAL {
if guests[0].Hypervisor == api.HYPERVISOR_KVM &&
!utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL, api.STORAGE_NFS, api.STORAGE_GPFS}) {
return nil, httperrors.NewBadRequestError("storage %s not support snapshot", storage.StorageType)
}
+15 -3
View File
@@ -406,6 +406,16 @@ func (self *SSnapshotManager) GetDiskSnapshots(diskId string) []SSnapshot {
return dest
}
func (self *SSnapshotManager) IsDiskSnapshotsNeedConvert(diskId string) (bool, error) {
count, err := self.Query().Equals("disk_id", diskId).
In("status", []string{api.SNAPSHOT_READY, api.SNAPSHOT_DELETING}).
Equals("out_of_chain", false).CountWithError()
if err != nil {
return false, err
}
return count >= options.Options.DefaultMaxSnapshotCount, nil
}
func (self *SSnapshotManager) GetDiskFirstSnapshot(diskId string) *SSnapshot {
dest := &SSnapshot{}
q := self.Query().SubQuery()
@@ -476,8 +486,8 @@ func (self *SSnapshot) StartSnapshotDeleteTask(ctx context.Context, userCred mcc
}
func (self *SSnapshot) ValidateDeleteCondition(ctx context.Context) error {
if self.RefCount > 0 {
return fmt.Errorf("Snapshot reference(by disk) count > 0, can not delete")
if len(self.ExternalId) == 0 && self.RefCount > 0 {
return httperrors.NewBadRequestError("Snapshot reference(by disk) count > 0, can not delete")
}
return nil
}
@@ -488,8 +498,10 @@ func (self *SSnapshot) CustomizeDelete(ctx context.Context, userCred mcclient.To
}
if len(self.ExternalId) == 0 {
if self.CreatedBy == api.SNAPSHOT_MANUAL {
if !self.FakeDeleted {
if !self.OutOfChain && !self.FakeDeleted {
return self.FakeDelete()
} else if self.OutOfChain {
return self.StartSnapshotDeleteTask(ctx, userCred, false, "")
}
_, err := SnapshotManager.GetConvertSnapshot(self)
if err != nil {
+2 -2
View File
@@ -65,7 +65,7 @@ func (self *DiskCreateTask) OnStorageCacheImageComplete(ctx context.Context, dis
storage := disk.GetStorage()
host := storage.GetMasterHost()
db.OpsLog.LogEvent(disk, db.ACT_ALLOCATING, disk.GetShortDesc(ctx), self.GetUserCred())
disk.SetStatus(self.GetUserCred(), api.DISK_STARTALLOC, "")
disk.SetStatus(self.GetUserCred(), api.DISK_STARTALLOC, fmt.Sprintf("Disk start alloc use host %s(%s)", host.Name, host.Id))
if len(disk.BackupStorageId) > 0 {
self.SetStage("OnMasterStorageCreateDiskComplete", nil)
} else {
@@ -82,7 +82,7 @@ func (self *DiskCreateTask) OnMasterStorageCreateDiskComplete(ctx context.Contex
storage := models.StorageManager.FetchStorageById(disk.BackupStorageId)
host := storage.GetMasterHost()
db.OpsLog.LogEvent(disk, db.ACT_BACKUP_ALLOCATING, disk.GetShortDesc(ctx), self.GetUserCred())
disk.SetStatus(self.UserCred, api.DISK_BACKUP_STARTALLOC, "")
disk.SetStatus(self.UserCred, api.DISK_BACKUP_STARTALLOC, fmt.Sprintf("Backup disk start alloc use host %s(%s)", host.Name, host.Id))
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())))
+7 -2
View File
@@ -96,7 +96,7 @@ func (self *GuestSwitchToBackupTask) OnBackupGuestStoped(ctx context.Context, gu
}
func (self *GuestSwitchToBackupTask) OnNewMasterStarted(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
self.SetStageComplete(ctx, nil)
self.OnComplete(ctx, guest, nil)
}
func (self *GuestSwitchToBackupTask) OnFail(ctx context.Context, guest *models.SGuest, reason string) {
@@ -106,13 +106,18 @@ func (self *GuestSwitchToBackupTask) OnFail(ctx context.Context, guest *models.S
self.SetStageFailed(ctx, reason)
}
func (self *GuestSwitchToBackupTask) OnComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
guest.SetMetadata(ctx, "__mirror_job_status", "", self.UserCred)
self.SetStageComplete(ctx, nil)
}
func (self *GuestSwitchToBackupTask) OnSwitched(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
oldStatus, _ := self.Params.GetString("old_status")
if utils.IsInStringArray(oldStatus, api.VM_RUNNING_STATUS) {
self.SetStage("OnNewMasterStarted", nil)
guest.StartGueststartTask(ctx, self.UserCred, nil, self.GetTaskId())
} else {
self.SetStageComplete(ctx, nil)
self.OnComplete(ctx, guest, nil)
}
}
+23 -20
View File
@@ -253,7 +253,6 @@ func (self *SnapshotDeleteTask) OnDeleteSnapshot(ctx context.Context, snapshot *
snapshot.RealDelete(ctx, self.UserCred)
self.TaskComplete(ctx, snapshot, nil)
} else {
guest, _ := snapshot.GetGuest()
var FakeDelete = false
if snapshot.CreatedBy == api.SNAPSHOT_MANUAL && snapshot.FakeDeleted == false {
FakeDelete = true
@@ -266,8 +265,7 @@ func (self *SnapshotDeleteTask) OnDeleteSnapshot(ctx context.Context, snapshot *
} else {
snapshot.RealDelete(ctx, self.UserCred)
}
self.SetStage("TaskComplete", nil)
guest.StartSyncstatus(ctx, self.UserCred, "")
self.TaskComplete(ctx, snapshot, nil)
}
} else {
snapshot.SetStatus(self.UserCred, api.SNAPSHOT_READY, "OnDeleteSnapshot")
@@ -282,35 +280,40 @@ func (self *SnapshotDeleteTask) OnDeleteSnapshotFailed(ctx context.Context, snap
func (self *SnapshotDeleteTask) OnReloadDiskSnapshot(ctx context.Context, snapshot *models.SSnapshot, data jsonutils.JSONObject) {
if !jsonutils.QueryBoolean(data, "reopen", false) {
log.Infof("OnDeleteSnapshot with no reopen")
log.Infof("OnReloadDiskSnapshot with no reopen")
return
}
if snapshot.CreatedBy == api.SNAPSHOT_AUTO {
err := snapshot.RealDelete(ctx, self.UserCred)
if err != nil {
self.TaskFailed(ctx, snapshot, err.Error())
return
}
} else {
err := snapshot.FakeDelete()
if err != nil {
self.TaskFailed(ctx, snapshot, err.Error())
return
}
}
self.SetStage("TaskComplete", nil)
guest, err := snapshot.GetGuest()
if err != nil {
self.SetStageFailed(ctx, err.Error())
self.TaskFailed(ctx, snapshot, err.Error())
return
}
guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId())
if snapshot.FakeDeleted {
params := jsonutils.NewDict()
params.Set("delete_snapshot", jsonutils.NewString(snapshot.Id))
params.Set("disk_id", jsonutils.NewString(snapshot.DiskId))
params.Set("auto_deleted", jsonutils.JSONTrue)
self.SetStage("OnDeleteSnapshot", nil)
err = guest.GetDriver().RequestDeleteSnapshot(ctx, guest, self, params)
if err != nil {
self.TaskFailed(ctx, snapshot, err.Error())
}
} else {
self.TaskComplete(ctx, snapshot, nil)
}
}
func (self *SnapshotDeleteTask) TaskComplete(ctx context.Context, snapshot *models.SSnapshot, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(snapshot, db.ACT_SNAPSHOT_DELETE, snapshot.GetShortDesc(ctx), self.UserCred)
logclient.AddActionLogWithStartable(self, snapshot, logclient.ACT_DELOCATE, nil, self.UserCred, true)
self.SetStageComplete(ctx, nil)
guest, err := snapshot.GetGuest()
if err != nil {
log.Errorln(err.Error())
return
}
guest.StartSyncstatus(ctx, self.UserCred, "")
}
func (self *SnapshotDeleteTask) TaskFailed(ctx context.Context, snapshot *models.SSnapshot, reason string) {
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package storageman
package diskutils
import (
"fmt"
@@ -26,9 +26,9 @@ import (
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/hostman/diskutils/nbd"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
"yunion.io/x/onecloud/pkg/hostman/storageman/nbd"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/qemuimg"
+1
View File
@@ -0,0 +1 @@
package diskutils // import "yunion.io/x/onecloud/pkg/hostman/diskutils"
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package storageman
package diskutils
import (
"fmt"
@@ -12,4 +12,4 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package nbd // import "yunion.io/x/onecloud/pkg/hostman/storageman/nbd"
package nbd // import "yunion.io/x/onecloud/pkg/hostman/diskutils/nbd"
+55 -81
View File
@@ -18,52 +18,15 @@ import (
"fmt"
"math/rand"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
fsdriver "yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
type SDeployInfo struct {
publicKey *sshkeys.SSHKeys
deploys []jsonutils.JSONObject
password string
isInit bool
enableTty bool
defaultRootUser bool
windowsDefaultAdminUser bool
enableCloudInit bool
}
func NewDeployInfo(
publicKey *sshkeys.SSHKeys,
deploys []jsonutils.JSONObject,
password string,
isInit bool,
enableTty bool,
defaultRootUser bool,
windowsDefaultAdminUser bool,
enableCloudInit bool,
) *SDeployInfo {
return &SDeployInfo{
publicKey: publicKey,
deploys: deploys,
password: password,
isInit: isInit,
enableTty: enableTty,
defaultRootUser: defaultRootUser,
windowsDefaultAdminUser: windowsDefaultAdminUser,
enableCloudInit: enableCloudInit,
}
}
func (d *SDeployInfo) String() string {
return fmt.Sprintf("deplys: %s, password %s, isInit: %v, enableTty: %v, defaultRootUser: %v, enableCloudInit: %v",
d.deploys, d.password, d.isInit, d.enableTty, d.defaultRootUser, d.enableCloudInit)
}
func DetectRootFs(part fsdriver.IDiskPartition) fsdriver.IRootFsDriver {
for _, newDriverFunc := range fsdriver.GetRootfsDrivers() {
d := newDriverFunc(part)
@@ -91,53 +54,49 @@ func testRootfs(d fsdriver.IRootFsDriver) bool {
return true
}
func DeployGuestFs(
rootfs fsdriver.IRootFsDriver,
guestDesc *jsonutils.JSONDict,
deployInfo *SDeployInfo,
) (jsonutils.JSONObject, error) {
var ret = jsonutils.NewDict()
var ips = make([]string, 0)
var err error
hn, _ := guestDesc.GetString("name")
domain, _ := guestDesc.GetString("domain")
gid, _ := guestDesc.GetString("uuid")
nics, _ := guestDesc.GetArray("nics")
partition := rootfs.GetPartition()
releaseInfo := rootfs.GetReleaseInfo(partition)
func DoDeployGuestFs(rootfs fsdriver.IRootFsDriver, guestDesc *deployapi.GuestDesc, deployInfo *deployapi.DeployInfo,
) (*deployapi.DeployGuestFsResponse, error) {
var (
err error
ret = new(deployapi.DeployGuestFsResponse)
ips = make([]string, 0)
hn = guestDesc.Name
domain = guestDesc.Domain
gid = guestDesc.Uuid
nics = guestDesc.Nics
nicsStandby = guestDesc.NicsStandby
partition = rootfs.GetPartition()
releaseInfo = rootfs.GetReleaseInfo(partition)
)
for _, n := range nics {
ip, _ := n.GetString("ip")
var addr netutils.IPV4Addr
if addr, err = netutils.NewIPV4Addr(ip); err != nil {
if addr, err = netutils.NewIPV4Addr(n.Ip); err != nil {
return nil, fmt.Errorf("Fail to get ip addr from %s: %v", n.String(), err)
}
if netutils.IsPrivate(addr) {
ips = append(ips, ip)
ips = append(ips, n.Ip)
}
}
if releaseInfo != nil {
ret.Set("distro", jsonutils.NewString(releaseInfo.Distro))
ret.Distro = releaseInfo.Distro
if len(releaseInfo.Version) > 0 {
ret.Set("version", jsonutils.NewString(releaseInfo.Version))
ret.Version = releaseInfo.Version
}
if len(releaseInfo.Arch) > 0 {
ret.Set("arch", jsonutils.NewString(releaseInfo.Arch))
ret.Arch = releaseInfo.Arch
}
if len(releaseInfo.Language) > 0 {
ret.Set("language", jsonutils.NewString(releaseInfo.Language))
ret.Language = releaseInfo.Language
}
}
ret.Set("os", jsonutils.NewString(rootfs.GetOs()))
ret.Os = rootfs.GetOs()
if IsPartitionReadonly(partition) {
return ret, nil
}
if len(deployInfo.deploys) > 0 {
if err = rootfs.DeployFiles(deployInfo.deploys); err != nil {
if len(deployInfo.Deploys) > 0 {
if err = rootfs.DeployFiles(deployInfo.Deploys); err != nil {
return nil, fmt.Errorf("DeployFiles: %v", err)
}
}
@@ -150,7 +109,7 @@ func DeployGuestFs(
if err = rootfs.DeployNetworkingScripts(partition, nics); err != nil {
return nil, fmt.Errorf("DeployNetworkingScripts: %v", err)
}
if nicsStandby, e := guestDesc.GetArray("nics_standby"); e == nil {
if len(nicsStandby) > 0 {
if err = rootfs.DeployStandbyNetworkingScripts(partition, nics, nicsStandby); err != nil {
return nil, fmt.Errorf("DeployStandbyNetworkingScripts: %v", err)
}
@@ -158,36 +117,35 @@ func DeployGuestFs(
if err = rootfs.DeployUdevSubsystemScripts(partition); err != nil {
return nil, fmt.Errorf("DeployUdevSubsystemScripts: %v", err)
}
if deployInfo.isInit {
disks, _ := guestDesc.GetArray("disks")
if err = rootfs.DeployFstabScripts(partition, disks); err != nil {
if deployInfo.IsInit {
if err = rootfs.DeployFstabScripts(partition, guestDesc.Disks); err != nil {
return nil, fmt.Errorf("DeployFstabScripts: %v", err)
}
}
if len(deployInfo.password) > 0 {
if len(deployInfo.Password) > 0 {
if account := rootfs.GetLoginAccount(partition,
deployInfo.defaultRootUser, deployInfo.windowsDefaultAdminUser); len(account) > 0 {
ret.Set("account", jsonutils.NewString(account))
if err = rootfs.DeployPublicKey(partition, account, deployInfo.publicKey); err != nil {
deployInfo.DefaultRootUser, deployInfo.WindowsDefaultAdminUser); len(account) > 0 {
if err = rootfs.DeployPublicKey(partition, account, deployInfo.PublicKey); err != nil {
return nil, fmt.Errorf("DeployPublicKey: %v", err)
}
var secret string
if secret, err = rootfs.ChangeUserPasswd(partition, account, gid,
deployInfo.publicKey.PublicKey, deployInfo.password); err != nil {
deployInfo.PublicKey.PublicKey, deployInfo.Password); err != nil {
return nil, fmt.Errorf("ChangeUserPasswd: %v", err)
}
ret.Account = account
if len(secret) > 0 {
ret.Set("key", jsonutils.NewString(secret))
ret.Key = secret
}
}
}
if err = rootfs.DeployYunionroot(partition, deployInfo.publicKey, deployInfo.isInit, deployInfo.enableCloudInit); err != nil {
if err = rootfs.DeployYunionroot(partition, deployInfo.PublicKey, deployInfo.IsInit, deployInfo.EnableCloudInit); err != nil {
return nil, fmt.Errorf("DeployYunionroot: %v", err)
}
if partition.SupportSerialPorts() {
if deployInfo.enableTty {
if err = rootfs.EnableSerialConsole(partition, ret); err != nil {
if deployInfo.EnableTty {
if err = rootfs.EnableSerialConsole(partition, nil); err != nil {
return nil, fmt.Errorf("EnableSerialConsole: %v", err)
}
} else {
@@ -200,10 +158,26 @@ func DeployGuestFs(
return nil, fmt.Errorf("CommitChanges: %v", err)
}
log.Debugf("Deploy finished, return: %s", ret.String())
log.Infof("Deploy finished, return: %s", ret.String())
return ret, nil
}
func DeployGuestFs(
rootfs fsdriver.IRootFsDriver,
guestDesc *jsonutils.JSONDict,
deployInfo *deployapi.DeployInfo,
) (jsonutils.JSONObject, error) {
desc, err := deployapi.GuestDescToDeployDesc(guestDesc)
if err != nil {
return nil, errors.Wrap(err, "To deploy desc fail")
}
ret, err := DoDeployGuestFs(rootfs, desc, deployInfo)
if err != nil {
return nil, err
}
return jsonutils.Marshal(ret), nil
}
func IsPartitionReadonly(rootfs fsdriver.IDiskPartition) bool {
log.Infof("Test if read-only fs ...")
var filename = fmt.Sprintf("/.%f", rand.Float32())
+5 -7
View File
@@ -19,9 +19,7 @@ import (
"sort"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
func ParsePropStr(lines string) map[string]string {
@@ -83,7 +81,7 @@ func (m *SAndroidRootFs) GetLoginAccount(rootFs IDiskPartition, defaultRootUser
return ""
}
func (m *SAndroidRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *sshkeys.SSHKeys) error {
func (m *SAndroidRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *deployapi.SSHKeys) error {
return nil
}
@@ -103,14 +101,14 @@ func (m *SAndroidRootFs) GetOs() string {
return "Android"
}
func (m *SAndroidRootFs) GetReleaseInfo(IDiskPartition) *SReleaseInfo {
func (m *SAndroidRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo {
spath := "/android-*/system/build.prop"
lines, _ := m.rootFs.FileGetContents(spath, false)
prop := ParsePropStr(string(lines))
distro, _ := prop["ro.product.model"]
version, _ := prop["ro.build.version.release"]
arch, _ := prop["ro.product.cpu.abi"]
return &SReleaseInfo{
return &deployapi.ReleaseInfo{
Distro: distro,
Version: version,
Arch: arch,
@@ -121,7 +119,7 @@ func (m *SAndroidRootFs) PrepareFsForTemplate(IDiskPartition) error {
return nil
}
func (m *SAndroidRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []jsonutils.JSONObject) error {
func (m *SAndroidRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*deployapi.Nic) error {
return nil
}
+13 -30
View File
@@ -24,7 +24,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
type sGuestRootFsDriver struct {
@@ -37,19 +37,17 @@ func newGuestRootFsDriver(rootFs IDiskPartition) *sGuestRootFsDriver {
}
}
func (d *sGuestRootFsDriver) DeployFiles(deploys []jsonutils.JSONObject) error {
func (d *sGuestRootFsDriver) DeployFiles(deploys []*deployapi.DeployContent) error {
caseInsensitive := d.IsFsCaseInsensitive()
for _, deploy := range deploys {
var modAppend = false
if action, _ := deploy.GetString("action"); action == "append" {
if deploy.Action == "append" {
modAppend = true
}
sPath, err := deploy.GetString("path")
if err != nil {
log.Errorln(err)
return err
if len(deploy.Path) == 0 {
return fmt.Errorf("Deploy file missing param path")
}
dirname := filepath.Dir(sPath)
dirname := filepath.Dir(deploy.Path)
if !d.GetPartition().Exists(dirname, caseInsensitive) {
modeRWXOwner := syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IXUSR
err := d.GetPartition().Mkdir(dirname, modeRWXOwner, caseInsensitive)
@@ -58,8 +56,8 @@ func (d *sGuestRootFsDriver) DeployFiles(deploys []jsonutils.JSONObject) error {
return err
}
}
if content, err := deploy.GetString("content"); err == nil {
err := d.GetPartition().FilePutContents(sPath, content, modAppend, caseInsensitive)
if len(deploy.Content) > 0 {
err := d.GetPartition().FilePutContents(deploy.Path, deploy.Content, modAppend, caseInsensitive)
if err != nil {
log.Errorln(err)
return err
@@ -81,7 +79,7 @@ func (d *sGuestRootFsDriver) IsFsCaseInsensitive() bool {
return false
}
func (d *sGuestRootFsDriver) DeployYunionroot(rootfs IDiskPartition, pubkeys *sshkeys.SSHKeys, isInit, enableCloudInit bool) error {
func (d *sGuestRootFsDriver) DeployYunionroot(rootfs IDiskPartition, pubkeys *deployapi.SSHKeys, isInit, enableCloudInit bool) error {
return nil
}
@@ -89,11 +87,11 @@ func (d *sGuestRootFsDriver) DeployUdevSubsystemScripts(rootfs IDiskPartition) e
return nil
}
func (d *sGuestRootFsDriver) DeployStandbyNetworkingScripts(part IDiskPartition, nics, nicsStandby []jsonutils.JSONObject) error {
func (d *sGuestRootFsDriver) DeployStandbyNetworkingScripts(part IDiskPartition, nics, nicsStandby []*deployapi.Nic) error {
return nil
}
func (d *sGuestRootFsDriver) DeployFstabScripts(_ IDiskPartition, _ []jsonutils.JSONObject) error {
func (d *sGuestRootFsDriver) DeployFstabScripts(_ IDiskPartition, _ []*deployapi.Disk) error {
return nil
}
@@ -117,22 +115,7 @@ func (l *sGuestRootFsDriver) IsCloudinitInstall() bool {
return false
}
type SReleaseInfo struct {
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 {
return &SReleaseInfo{
Distro: distro,
Version: version,
Arch: arch,
}
}
func DeployAuthorizedKeys(rootFs IDiskPartition, usrDir string, pubkeys *sshkeys.SSHKeys, replace bool) error {
func DeployAuthorizedKeys(rootFs IDiskPartition, usrDir string, pubkeys *deployapi.SSHKeys, replace bool) error {
usrStat := rootFs.Stat(usrDir, false)
if usrStat != nil {
sshDir := path.Join(usrDir, ".ssh")
@@ -171,7 +154,7 @@ func DeployAuthorizedKeys(rootFs IDiskPartition, usrDir string, pubkeys *sshkeys
return nil
}
func MergeAuthorizedKeys(oldKeys string, pubkeys *sshkeys.SSHKeys) string {
func MergeAuthorizedKeys(oldKeys string, pubkeys *deployapi.SSHKeys) string {
var allkeys = make(map[string]string)
if len(oldKeys) > 0 {
for _, line := range strings.Split(oldKeys, "\n") {
+3 -3
View File
@@ -17,13 +17,13 @@ package fsdriver
import (
"testing"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
func TestMergeAuthorizedKeys(t *testing.T) {
type args struct {
oldKeys string
pubkeys *sshkeys.SSHKeys
pubkeys *deployapi.SSHKeys
}
tests := []struct {
name string
@@ -34,7 +34,7 @@ func TestMergeAuthorizedKeys(t *testing.T) {
name: "MergeAuthorizedKeys",
args: args{
oldKeys: "Test KEY",
pubkeys: &sshkeys.SSHKeys{},
pubkeys: &deployapi.SSHKeys{},
},
want: "Test KEY\n",
},
+7 -2
View File
@@ -16,13 +16,18 @@ package fsdriver
type newRootFsDriverFunc func(part IDiskPartition) IRootFsDriver
var rootfsDrivers = make([]newRootFsDriverFunc, 0)
var (
privatePrefixes []string
rootfsDrivers = make([]newRootFsDriverFunc, 0)
)
func GetRootfsDrivers() []newRootFsDriverFunc {
return rootfsDrivers
}
func init() {
func Init(initPrivatePrefixes []string) {
privatePrefixes = make([]string, len(initPrivatePrefixes))
copy(privatePrefixes, initPrivatePrefixes)
linuxFsDrivers := []newRootFsDriverFunc{
NewCentosRootFs, NewFedoraRootFs, NewRhelRootFs,
NewDebianRootFs, NewCirrosRootFs, NewCirrosNewRootFs, NewUbuntuRootFs,
+5 -6
View File
@@ -15,10 +15,9 @@
package fsdriver
import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
type SEsxiRootFs struct {
@@ -67,19 +66,19 @@ func (m *SEsxiRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips []
return nil
}
func (m *SEsxiRootFs) GetReleaseInfo(IDiskPartition) *SReleaseInfo {
func (m *SEsxiRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo {
spath := "/boot.cfg"
lines, _ := m.rootFs.FileGetContents(spath, false)
prop := ParsePropStr(string(lines))
version, _ := prop["build"]
return &SReleaseInfo{
return &deployapi.ReleaseInfo{
Distro: "ESXi",
Version: version,
Arch: "x86_64",
}
}
func (m *SEsxiRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *sshkeys.SSHKeys) error {
func (m *SEsxiRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *deployapi.SSHKeys) error {
return nil
}
@@ -87,6 +86,6 @@ func (m *SEsxiRootFs) PrepareFsForTemplate(IDiskPartition) error {
return nil
}
func (m *SEsxiRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []jsonutils.JSONObject) error {
func (m *SEsxiRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*deployapi.Nic) error {
return nil
}
+8 -8
View File
@@ -19,7 +19,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
type IDiskPartition interface {
@@ -61,22 +61,22 @@ type IRootFsDriver interface {
IsFsCaseInsensitive() bool
RootSignatures() []string
RootExcludeSignatures() []string
GetReleaseInfo(IDiskPartition) *SReleaseInfo
GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo
GetOs() string
DeployHostname(part IDiskPartition, hn, domain string) error
DeployHosts(part IDiskPartition, hn, domain string, ips []string) error
DeployNetworkingScripts(IDiskPartition, []jsonutils.JSONObject) error
DeployStandbyNetworkingScripts(part IDiskPartition, nics, nicsStandby []jsonutils.JSONObject) error
DeployNetworkingScripts(IDiskPartition, []*deployapi.Nic) error
DeployStandbyNetworkingScripts(part IDiskPartition, nics, nicsStandby []*deployapi.Nic) error
DeployUdevSubsystemScripts(IDiskPartition) error
DeployFstabScripts(IDiskPartition, []jsonutils.JSONObject) error
DeployFstabScripts(IDiskPartition, []*deployapi.Disk) error
GetLoginAccount(IDiskPartition, bool, bool) string
DeployPublicKey(IDiskPartition, string, *sshkeys.SSHKeys) error
DeployPublicKey(IDiskPartition, string, *deployapi.SSHKeys) error
ChangeUserPasswd(part IDiskPartition, account, gid, publicKey, password string) (string, error)
DeployYunionroot(rootFs IDiskPartition, pubkeys *sshkeys.SSHKeys, isInit bool, enableCloudInit bool) error
DeployYunionroot(rootFs IDiskPartition, pubkeys *deployapi.SSHKeys, isInit bool, enableCloudInit bool) error
EnableSerialConsole(IDiskPartition, *jsonutils.JSONDict) error
DisableSerialConsole(IDiskPartition) error
CommitChanges(IDiskPartition) error
DeployFiles(deploys []jsonutils.JSONObject) error
DeployFiles(deploys []*deployapi.DeployContent) error
DetectIsUEFISupport(IDiskPartition) bool
IsCloudinitInstall() bool
+69 -82
View File
@@ -30,9 +30,8 @@ import (
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/hostman/options"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/util/coreosutils"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/fstabutils"
@@ -117,7 +116,7 @@ func (l *sLinuxRootFs) ChangeUserPasswd(rootFs IDiskPartition, account, gid, pub
return secret, err
}
func (l *sLinuxRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *sshkeys.SSHKeys) error {
func (l *sLinuxRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *deployapi.SSHKeys) error {
var usrDir string
if selUsr == "root" {
usrDir = "/root"
@@ -127,7 +126,7 @@ func (l *sLinuxRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pub
return DeployAuthorizedKeys(rootFs, usrDir, pubkeys, false)
}
func (l *sLinuxRootFs) DeployYunionroot(rootFs IDiskPartition, pubkeys *sshkeys.SSHKeys, isInit, enableCloudInit bool) error {
func (l *sLinuxRootFs) DeployYunionroot(rootFs IDiskPartition, pubkeys *deployapi.SSHKeys, isInit, enableCloudInit bool) error {
l.DisableSelinux(rootFs)
if !enableCloudInit && isInit {
l.DisableCloudinit(rootFs)
@@ -191,7 +190,7 @@ func (l *sLinuxRootFs) DisableCloudinit(rootFs IDiskPartition) {
}
}
func (l *sLinuxRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []jsonutils.JSONObject) error {
func (l *sLinuxRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []*deployapi.Disk) error {
fstabcont, err := rootFs.FileGetContents("/etc/fstab", false)
if err != nil {
return err
@@ -203,18 +202,18 @@ func (l *sLinuxRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []jsonuti
fstab.RemoveDevices(len(disks))
for i := 1; i < len(disks); i++ {
diskId, err := disks[i].GetString("disk_id")
if err != nil {
diskId := disks[i].DiskId
if len(diskId) == 0 {
diskId = "None"
}
dev := fmt.Sprintf("UUID=%s", diskId)
if !fstab.IsExists(dev) {
fs, _ := disks[i].GetString("fs")
fs := disks[i].Fs
if len(fs) > 0 {
if fs == "swap" {
rec = fmt.Sprintf("%s none %s sw 0 0", dev, fs)
} else {
mtPath, _ := disks[i].GetString("mountpoint")
mtPath := disks[i].Mountpoint
if len(mtPath) == 0 {
mtPath = "/data"
if dataDiskIdx > 0 {
@@ -237,7 +236,7 @@ func (l *sLinuxRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []jsonuti
return rootFs.FilePutContents("/etc/fstab", cf, false, false)
}
func (l *sLinuxRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (l *sLinuxRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
udevPath := "/etc/udev/rules.d/"
if rootFs.Exists(udevPath, false) {
rules := rootFs.ListDir(udevPath, false)
@@ -254,9 +253,9 @@ func (l *sLinuxRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jso
for _, nic := range nics {
nicRules += `KERNEL=="*", SUBSYSTEM=="net", ACTION=="add", `
nicRules += `DRIVERS=="?*", `
mac, _ := nic.GetString("mac")
mac := nic.Mac
nicRules += fmt.Sprintf(`ATTR{address}=="%s", ATTR{type}=="1", `, strings.ToLower(mac))
idx, _ := nic.Int("index")
idx := nic.Index
nicRules += fmt.Sprintf("NAME=\"eth%d\"\n", idx)
}
if err := rootFs.FilePutContents(path.Join(udevPath, "70-persistent-net.rules"), nicRules, false, false); err != nil {
@@ -274,17 +273,16 @@ func (l *sLinuxRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jso
return nil
}
func (l *sLinuxRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []jsonutils.JSONObject) error {
func (l *sLinuxRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []*deployapi.Nic) error {
var udevPath = "/etc/udev/rules.d/"
var nicRules string
for _, nic := range nicsStandby {
nicType, _ := nic.GetString("nic_type")
if !nic.Contains("nic_type") || nicType != "impi" {
if len(nic.NicType) == 0 || nic.NicType != "impi" {
nicRules += `KERNEL=="*", SUBSYSTEM=="net", ACTION=="add", `
nicRules += `DRIVERS=="?*", `
mac, _ := nic.GetString("mac")
mac := nic.Mac
nicRules += fmt.Sprintf(`ATTR{address}=="%s", ATTR{type}=="1", `, strings.ToLower(mac))
idx, _ := nic.Int("index")
idx := nic.Index
nicRules += fmt.Sprintf("NAME=\"eth%d\"\n", idx)
}
}
@@ -474,14 +472,14 @@ func newDebianLikeRootFs(part IDiskPartition) *sDebianLikeRootFs {
}
}
func (d *sDebianLikeRootFs) GetReleaseInfo(rootFs IDiskPartition, driver IDebianRootFsDriver) *SReleaseInfo {
func (d *sDebianLikeRootFs) GetReleaseInfo(rootFs IDiskPartition, driver IDebianRootFsDriver) *deployapi.ReleaseInfo {
version, err := rootFs.FileGetContents(driver.VersionFilePath(), false)
if err != nil {
log.Errorf("Get %s error: %v", driver.VersionFilePath(), err)
return nil
}
versionStr := strings.TrimSpace(string(version))
return &SReleaseInfo{
return &deployapi.ReleaseInfo{
Distro: driver.DistroName(),
Version: versionStr,
Arch: d.GetArch(rootFs),
@@ -512,7 +510,7 @@ func getNicTeamingConfigCmds(slaves []*types.SServerNic) string {
return cmds.String()
}
func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
if err := d.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
return err
}
@@ -521,7 +519,7 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString("auto lo\n")
cmds.WriteString("iface lo inet loopback\n\n")
allNics, _ := convertNicConfigs(nics)
allNics, _ := convertNicConfigs(ToServerNics(nics))
mainNic, err := getMainNic(allNics)
if err != nil {
return err
@@ -543,7 +541,7 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString(" netmask 255.255.255.255\n")
cmds.WriteString("\n")
} else if nicDesc.Manual {
netmask := netutils2.Netlen2Mask(nicDesc.Masklen)
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
cmds.WriteString(fmt.Sprintf("iface %s inet static\n", nicDesc.Name))
cmds.WriteString(fmt.Sprintf(" address %s\n", nicDesc.Ip))
cmds.WriteString(fmt.Sprintf(" netmask %s\n", netmask))
@@ -551,7 +549,7 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString(fmt.Sprintf(" gateway %s\n", nicDesc.Gateway))
}
var routes = make([][]string, 0)
netutils2.AddNicRoutes(&routes, nicDesc, mainIp, len(nics), options.HostOptions.PrivatePrefixes)
netutils2.AddNicRoutes(&routes, nicDesc, mainIp, len(nics), privatePrefixes)
for _, r := range routes {
cmds.WriteString(fmt.Sprintf(" up route add -net %s gw %s || true\n", r[0], r[1]))
cmds.WriteString(fmt.Sprintf(" down route del -net %s gw %s || true\n", r[0], r[1]))
@@ -615,7 +613,7 @@ func (d *SDebianRootFs) RootExcludeSignatures() []string {
return []string{"/etc/lsb-release"}
}
func (d *SDebianRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (d *SDebianRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
return d.sDebianLikeRootFs.GetReleaseInfo(rootFs, d)
}
@@ -645,7 +643,7 @@ func (d *SCirrosRootFs) VersionFilePath() string {
return "/etc/br-version"
}
func (d *SCirrosRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (d *SCirrosRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
return d.SDebianRootFs.sDebianLikeRootFs.GetReleaseInfo(rootFs, d)
}
@@ -683,7 +681,7 @@ func (d *SCirrosNewRootFs) RootSignatures() []string {
return d.rootSignatures(d)
}
func (d *SCirrosNewRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (d *SCirrosNewRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
return d.SDebianRootFs.sDebianLikeRootFs.GetReleaseInfo(rootFs, d)
}
@@ -710,7 +708,7 @@ func (d *SUbuntuRootFs) String() string {
return "UbuntuRootFs"
}
func (d *SUbuntuRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (d *SUbuntuRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
distroKey := "DISTRIB_RELEASE="
rel, err := rootFs.FileGetContents("/etc/lsb-release", false)
if err != nil {
@@ -724,7 +722,7 @@ func (d *SUbuntuRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
version = strings.TrimSpace(l[len(distroKey) : len(l)-1])
}
}
return newReleaseInfo(d.GetName(), version, d.GetArch(rootFs))
return deployapi.NewReleaseInfo(d.GetName(), version, d.GetArch(rootFs))
}
func (d *SUbuntuRootFs) EnableSerialConsole(rootFs IDiskPartition, sysInfo *jsonutils.JSONDict) error {
@@ -778,18 +776,14 @@ func (r *sRedhatLikeRootFs) DeployHostname(rootFs IDiskPartition, hn, domain str
return nil
}
func (r *sRedhatLikeRootFs) Centos5DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (r *sRedhatLikeRootFs) Centos5DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
var udevPath = "/etc/udev/rules.d/"
if rootFs.Exists(udevPath, false) {
var nicRules = ""
for _, nic := range nics {
var nicdesc = new(types.SServerNic)
if err := nic.Unmarshal(nicdesc); err != nil {
return err
}
nicRules += `KERNEL=="*", `
nicRules += fmt.Sprintf(`SYSFS{address}=="%s", `, strings.ToLower(nicdesc.Mac))
nicRules += fmt.Sprintf("NAME=\"eth%d\"\n", nicdesc.Index)
nicRules += fmt.Sprintf(`SYSFS{address}=="%s", `, strings.ToLower(nic.Mac))
nicRules += fmt.Sprintf("NAME=\"eth%d\"\n", nic.Index)
}
return rootFs.FilePutContents(path.Join(udevPath, "60-net.rules"),
nicRules, false, false)
@@ -830,7 +824,7 @@ func (r *sRedhatLikeRootFs) enableBondingModule(rootFs IDiskPartition, bondNics
return rootFs.FilePutContents("/etc/modprobe.d/bonding.conf", content.String(), false, false)
}
func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject, relInfo *SReleaseInfo) error {
func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic, relInfo *deployapi.ReleaseInfo) error {
if err := r.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
return err
}
@@ -848,7 +842,7 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
if err != nil {
return err
}
allNics, bondNics := convertNicConfigs(nics)
allNics, bondNics := convertNicConfigs(ToServerNics(nics))
if len(bondNics) > 0 {
err = r.enableBondingModule(rootFs, bondNics)
if err != nil {
@@ -896,7 +890,7 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString(netutils2.PSEUDO_VIP)
cmds.WriteString("\n")
} else if nicDesc.Manual {
netmask := netutils2.Netlen2Mask(nicDesc.Masklen)
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
cmds.WriteString("BOOTPROTO=none\n")
cmds.WriteString("NETMASK=")
cmds.WriteString(netmask)
@@ -910,7 +904,7 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString("\n")
}
var routes = make([][]string, 0)
netutils2.AddNicRoutes(&routes, nicDesc, mainIp, len(nics), options.HostOptions.PrivatePrefixes)
netutils2.AddNicRoutes(&routes, nicDesc, mainIp, len(nics), privatePrefixes)
var rtbl strings.Builder
for _, r := range routes {
rtbl.WriteString(r[0])
@@ -946,23 +940,19 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
return nil
}
func (r *sRedhatLikeRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []jsonutils.JSONObject) error {
func (r *sRedhatLikeRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []*deployapi.Nic) error {
if err := r.sLinuxRootFs.DeployStandbyNetworkingScripts(rootFs, nics, nicsStandby); err != nil {
return err
}
for _, nic := range nicsStandby {
var cmds string
var nicdesc = new(types.SServerNic)
if err := nic.Unmarshal(nicdesc); err != nil {
return err
}
if nicType, err := nic.GetString("nic_type"); err != nil && nicType != "ipmi" {
cmds += fmt.Sprintf("DEVICE=eth%d\n", nicdesc.Index)
cmds += fmt.Sprintf("NAME=eth%d\n", nicdesc.Index)
cmds += fmt.Sprintf("HWADDR=%s\n", nicdesc.Mac)
cmds += fmt.Sprintf("MACADDR=%s\n", nicdesc.Mac)
if len(nic.NicType) == 0 || nic.NicType != "ipmi" {
cmds += fmt.Sprintf("DEVICE=eth%d\n", nic.Index)
cmds += fmt.Sprintf("NAME=eth%d\n", nic.Index)
cmds += fmt.Sprintf("HWADDR=%s\n", nic.Mac)
cmds += fmt.Sprintf("MACADDR=%s\n", nic.Mac)
cmds += "ONBOOT=no\n"
var fn = fmt.Sprintf("/etc/sysconfig/network-scripts/ifcfg-eth%d", nicdesc.Index)
var fn = fmt.Sprintf("/etc/sysconfig/network-scripts/ifcfg-eth%d", nic.Index)
if err := rootFs.FilePutContents(fn, cmds, false, false); err != nil {
return err
}
@@ -1029,7 +1019,7 @@ func (c *SCentosRootFs) RootSignatures() []string {
return append([]string{"/etc/centos-release"}, sig...)
}
func (c *SCentosRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (c *SCentosRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
rel, _ := rootFs.FileGetContents("/etc/centos-release", false)
var version string
if len(rel) > 0 {
@@ -1042,10 +1032,10 @@ func (c *SCentosRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
}
}
}
return newReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
return deployapi.NewReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
}
func (c *SCentosRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (c *SCentosRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
relInfo := c.GetReleaseInfo(rootFs)
if err := c.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
return err
@@ -1092,7 +1082,7 @@ func (c *SFedoraRootFs) RootSignatures() []string {
return append([]string{"/etc/fedora-release"}, sig...)
}
func (c *SFedoraRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (c *SFedoraRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
rel, _ := rootFs.FileGetContents("/etc/fedora-release", false)
var version string
if len(rel) > 0 {
@@ -1105,10 +1095,10 @@ func (c *SFedoraRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
}
}
}
return newReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
return deployapi.NewReleaseInfo(c.GetName(), version, c.GetArch(rootFs))
}
func (c *SFedoraRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (c *SFedoraRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
relInfo := c.GetReleaseInfo(rootFs)
if err := c.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
return err
@@ -1140,7 +1130,7 @@ func (d *SRhelRootFs) String() string {
return "RhelRootFs"
}
func (d *SRhelRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (d *SRhelRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
rel, _ := rootFs.FileGetContents("/etc/redhat-release", false)
var version string
if len(rel) > 0 {
@@ -1149,10 +1139,10 @@ func (d *SRhelRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
version = dat[6]
}
}
return newReleaseInfo(d.GetName(), version, d.GetArch(rootFs))
return deployapi.NewReleaseInfo(d.GetName(), version, d.GetArch(rootFs))
}
func (d *SRhelRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (d *SRhelRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
relInfo := d.GetReleaseInfo(rootFs)
if err := d.sRedhatLikeRootFs.deployNetworkingScripts(rootFs, nics, relInfo); err != nil {
return err
@@ -1199,7 +1189,7 @@ func (d *SGentooRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string)
return rootFs.FilePutContents(spath, content, false, false)
}
func (l *SGentooRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (l *SGentooRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
if err := l.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
return err
}
@@ -1210,8 +1200,8 @@ func (l *SGentooRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []js
)
for _, nic := range nics {
nicIndex, _ := nic.Int("index")
if jsonutils.QueryBoolean(nic, "virtual", false) {
nicIndex := nic.Index
if nic.Virtual {
cmds += fmt.Sprintf(`config_eth%d="`, nicIndex)
cmds += fmt.Sprintf("%s netmask 255.255.255.255", netutils2.PSEUDO_VIP)
cmds += `"\n`
@@ -1223,7 +1213,7 @@ func (l *SGentooRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []js
return err
}
for _, nic := range nics {
nicIndex, _ := nic.Int("index")
nicIndex := nic.Index
netname := fmt.Sprintf("net.eth%d", nicIndex)
procutils.NewCommand("ln", "-s", "net.lo",
fmt.Sprintf("%s/etc/init.d/%s", rootFs.GetMountPath(), netname)).Run()
@@ -1233,8 +1223,8 @@ func (l *SGentooRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []js
return nil
}
func (d *SGentooRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
return &SReleaseInfo{
func (d *SGentooRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
return &deployapi.ReleaseInfo{
Distro: "Gentoo",
Arch: d.GetArch(rootFs),
}
@@ -1269,8 +1259,8 @@ func (d *SArchLinuxRootFs) DeployHostname(rootFs IDiskPartition, hn, domain stri
return rootFs.FilePutContents("/etc/hostname", hn, false, false)
}
func (d *SArchLinuxRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
return &SReleaseInfo{
func (d *SArchLinuxRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
return &deployapi.ReleaseInfo{
Distro: "ArchLinux",
Arch: d.GetArch(rootFs),
}
@@ -1308,9 +1298,9 @@ func (d *SOpenWrtRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string
return rootFs.FilePutContents(spath, cont, false, false)
}
func (d *SOpenWrtRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
func (d *SOpenWrtRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
ver, _ := rootFs.FileGetContents("/etc/openwrt_version", false)
return &SReleaseInfo{
return &deployapi.ReleaseInfo{
Distro: "OpenWRT",
Version: string(ver),
Arch: d.GetArch(rootFs),
@@ -1338,8 +1328,8 @@ func (d *SCoreOsRootFs) GetOs() string {
return "Linux"
}
func (d *SCoreOsRootFs) GetReleaseInfo(rootFs IDiskPartition) *SReleaseInfo {
return &SReleaseInfo{
func (d *SCoreOsRootFs) GetReleaseInfo(rootFs IDiskPartition) *deployapi.ReleaseInfo {
return &deployapi.ReleaseInfo{
Distro: "CoreOS",
Version: "stable",
}
@@ -1367,7 +1357,7 @@ func (d *SCoreOsRootFs) DeployHostname(rootFs IDiskPartition, hn, domain string)
return nil
}
func (d *SCoreOsRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *sshkeys.SSHKeys) error {
func (d *SCoreOsRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pubkeys *deployapi.SSHKeys) error {
return nil
}
@@ -1376,7 +1366,7 @@ func (d *SCoreOsRootFs) DeployHosts(rootFs IDiskPartition, hostname, domain stri
return nil
}
func (d *SCoreOsRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []jsonutils.JSONObject) error {
func (d *SCoreOsRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*deployapi.Nic) error {
cont := "[Match]\n"
cont += "Name=eth*\n\n"
cont += "[Network]\n"
@@ -1386,17 +1376,16 @@ func (d *SCoreOsRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []js
return nil
}
func (d *SCoreOsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []jsonutils.JSONObject) error {
func (d *SCoreOsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []*deployapi.Disk) error {
dataDiskIdx := 0
for i := 1; i < len(disks); i++ {
diskId, _ := disks[i].GetString("disk_id")
dev := fmt.Sprintf("UUID=%s", diskId)
fs, _ := disks[i].GetString("fs")
dev := fmt.Sprintf("UUID=%s", disks[i].DiskId)
fs := disks[i].Fs
if len(fs) > 0 {
if fs == "swap" {
d.GetConfig().AddSwap(dev)
} else {
mtPath, _ := disks[i].GetString("mountpoint")
mtPath := disks[i].Mountpoint
if len(mtPath) == 0 {
mtPath = "/data"
if dataDiskIdx > 0 {
@@ -1428,11 +1417,9 @@ func (d *SCoreOsRootFs) GetLoginAccount(rootFs IDiskPartition, defaultRootUser b
return "core"
}
func (d *SCoreOsRootFs) DeployFiles(deploys []jsonutils.JSONObject) error {
func (d *SCoreOsRootFs) DeployFiles(deploys []*deployapi.DeployContent) error {
for _, deploy := range deploys {
spath, _ := deploy.GetString("path")
content, _ := deploy.GetString("content")
d.GetConfig().AddWriteFile(spath, content, "", "", false)
d.GetConfig().AddWriteFile(deploy.Path, deploy.Content, "", "", false)
}
return nil
}
+5 -6
View File
@@ -19,10 +19,9 @@ import (
"path"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/util/macutils"
"yunion.io/x/onecloud/pkg/util/seclib2"
"yunion.io/x/onecloud/pkg/util/stringutils2"
@@ -72,7 +71,7 @@ func (m *SMacOSRootFs) RootSignatures() []string {
}
}
func (m *SMacOSRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *sshkeys.SSHKeys) error {
func (m *SMacOSRootFs) DeployPublicKey(rootfs IDiskPartition, uname string, pubkeys *deployapi.SSHKeys) error {
usrDir := fmt.Sprintf("/Users/%s", uname)
return DeployAuthorizedKeys(m.rootFs, usrDir, pubkeys, false)
}
@@ -115,13 +114,13 @@ func (m *SMacOSRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips [
return nil
}
func (m *SMacOSRootFs) GetReleaseInfo(IDiskPartition) *SReleaseInfo {
func (m *SMacOSRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo {
spath := "/System/Library/CoreServices/SystemVersion.plist"
sInfo, _ := m.rootFs.FileGetContents(spath, false)
info := macutils.ParsePlist(sInfo)
distro, _ := info["ProductName"]
version, _ := info["ProductUserVisibleVersion"]
return &SReleaseInfo{
return &deployapi.ReleaseInfo{
Distro: distro,
Version: version,
Arch: "x86_64",
@@ -132,7 +131,7 @@ func (m *SMacOSRootFs) GetOs() string {
return "macOs"
}
func (m *SMacOSRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []jsonutils.JSONObject) error {
func (m *SMacOSRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*deployapi.Nic) error {
return nil
}
+17 -10
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
func unmarshalNicConfigs(jsonNics []jsonutils.JSONObject) []types.SServerNic {
@@ -33,18 +34,24 @@ func unmarshalNicConfigs(jsonNics []jsonutils.JSONObject) []types.SServerNic {
return nics
}
func findTeamingNic(nics []types.SServerNic, mac string) *types.SServerNic {
func findTeamingNic(nics []*types.SServerNic, mac string) *types.SServerNic {
for i := range nics {
if nics[i].TeamWith == mac {
return &nics[i]
return nics[i]
}
}
return nil
}
func convertNicConfigs(jsonNics []jsonutils.JSONObject) ([]*types.SServerNic, []*types.SServerNic) {
nics := unmarshalNicConfigs(jsonNics)
func ToServerNics(nics []*deployapi.Nic) []*types.SServerNic {
ret := make([]*types.SServerNic, len(nics))
for i := 0; i < len(nics); i++ {
ret[i] = &types.SServerNic{Nic: nics[i]}
}
return ret
}
func convertNicConfigs(nics []*types.SServerNic) ([]*types.SServerNic, []*types.SServerNic) {
allNics := make([]*types.SServerNic, 0)
bondNics := make([]*types.SServerNic, 0)
@@ -61,25 +68,25 @@ func convertNicConfigs(jsonNics []jsonutils.JSONObject) ([]*types.SServerNic, []
if teamNic == nil {
nnic := nics[i]
nnic.Name = fmt.Sprintf("eth%d", nnic.Index)
allNics = append(allNics, &nnic)
allNics = append(allNics, nnic)
continue
}
master := nics[i]
nnic := nics[i]
tnic := *teamNic
nnic.Name = fmt.Sprintf("eth%d", nnic.Index)
nnic.TeamingMaster = &master
nnic.TeamingMaster = master
nnic.Ip = ""
nnic.Gateway = ""
tnic.Name = fmt.Sprintf("eth%d", tnic.Index)
tnic.TeamingMaster = &master
tnic.TeamingMaster = master
tnic.Ip = ""
tnic.Gateway = ""
master.Name = fmt.Sprintf("bond%d", len(bondNics))
master.TeamingSlaves = []*types.SServerNic{&nnic, &tnic}
master.TeamingSlaves = []*types.SServerNic{nnic, &tnic}
master.Mac = ""
allNics = append(allNics, &nnic, &tnic, &master)
bondNics = append(bondNics, &master)
allNics = append(allNics, nnic, &tnic, master)
bondNics = append(bondNics, master)
}
return allNics, bondNics
}
+17 -19
View File
@@ -22,13 +22,11 @@ import (
"strings"
"syscall"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/hostman/options"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/netutils2"
"yunion.io/x/onecloud/pkg/util/seclib2"
@@ -76,7 +74,7 @@ func (w *SWindowsRootFs) String() string {
return "WindowsRootFs"
}
func (w *SWindowsRootFs) DeployPublicKey(IDiskPartition, string, *sshkeys.SSHKeys) error {
func (w *SWindowsRootFs) DeployPublicKey(IDiskPartition, string, *deployapi.SSHKeys) error {
return nil
}
@@ -90,7 +88,7 @@ func (w *SWindowsRootFs) RootSignatures() []string {
}
}
func (w *SWindowsRootFs) GetReleaseInfo(IDiskPartition) *SReleaseInfo {
func (w *SWindowsRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo {
confPath := w.rootFs.GetLocalPath("/windows/system32/config", true)
tool := winutils.NewWinRegTool(confPath)
if tool.CheckPath() {
@@ -98,7 +96,12 @@ func (w *SWindowsRootFs) GetReleaseInfo(IDiskPartition) *SReleaseInfo {
version := tool.GetVersion()
arch := tool.GetArch()
lan := tool.GetInstallLanguage()
return &SReleaseInfo{distro, version, arch, lan}
return &deployapi.ReleaseInfo{
Distro: distro,
Version: version,
Arch: arch,
Language: lan,
}
} else {
return nil
}
@@ -228,14 +231,14 @@ func (w *SWindowsRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips
return w.rootFs.FilePutContents(ETC_HOSTS, hf.String(), false, true)
}
func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []jsonutils.JSONObject) error {
mainNic, err := netutils2.GetMainNic(nics)
func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*deployapi.Nic) error {
mainNic, err := netutils2.GetMainNicFromDeployApi(nics)
if err != nil {
return err
}
mainIp := ""
if mainNic != nil {
mainIp, _ = mainNic.GetString("ip")
mainIp = mainNic.Ip
}
bootScript := strings.Join([]string{
`set NETCFG_SCRIPT=%SystemRoot%\netcfg.bat`,
@@ -255,24 +258,19 @@ func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []j
}
for _, nic := range nics {
snic := &types.SServerNic{}
if err := nic.Unmarshal(snic); err != nil {
log.Errorln(err)
return err
}
snic := &types.SServerNic{Nic: nic}
mac := snic.Mac
mac = strings.Replace(strings.ToUpper(mac), ":", "-", -1)
lines = append(lines, fmt.Sprintf(` if "%%%%c" == "%s" (`, mac))
if jsonutils.QueryBoolean(nic, "manual", false) {
netmask := netutils2.Netlen2Mask(snic.Masklen)
if snic.Manual {
netmask := netutils2.Netlen2Mask(int(snic.Masklen))
cfg := fmt.Sprintf(` netsh interface ip set address "%%%%b" static %s %s`, snic.Ip, netmask)
if len(snic.Gateway) > 0 && snic.Ip == mainIp {
cfg += fmt.Sprintf(" %s", snic.Gateway)
}
lines = append(lines, cfg)
routes := [][]string{}
netutils2.AddNicRoutes(&routes, snic, mainIp, len(nics), options.HostOptions.PrivatePrefixes)
netutils2.AddNicRoutes(&routes, snic, mainIp, len(nics), privatePrefixes)
for _, r := range routes {
lines = append(lines, fmt.Sprintf(` netsh interface ip add route %s "%%%%b" %s`, r[0], r[1]))
}
@@ -449,7 +447,7 @@ func (w *SWindowsRootFs) deploySetupCompleteScripts(uname, passwd string) bool {
return true
}
func (w *SWindowsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []jsonutils.JSONObject) error {
func (w *SWindowsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []*deployapi.Disk) error {
if len(disks) == 1 {
return nil
}
+5 -7
View File
@@ -52,13 +52,11 @@ func NewKVMGuestDiskPartition(devPath, sourceDev string, isLVM bool) *SKVMGuestD
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
}
dev = p.sourceDev
}
idxP := strings.LastIndexByte(dev, 'p')
if idxP > 0 {
dev = dev[:idxP]
}
cmd := fmt.Sprintf(`fdisk -l %s | grep "Disk label type:"`, dev)
output, err := procutils.NewCommand("sh", "-c", cmd).Run()
+6 -6
View File
@@ -35,6 +35,12 @@ type SLocalGuestFS struct {
mountPath string
}
func NewLocalGuestFS(mountPath string) *SLocalGuestFS {
var ret = new(SLocalGuestFS)
ret.mountPath = mountPath
return ret
}
func (f *SLocalGuestFS) GetMountPath() string {
return f.mountPath
}
@@ -256,9 +262,3 @@ func (f *SLocalGuestFS) FilePutContents(sPath, content string, modAppend, caseIn
return fmt.Errorf("Cann't put content")
}
}
func NewLocalGuestFS(mountPath string) *SLocalGuestFS {
var ret = new(SLocalGuestFS)
ret.mountPath = mountPath
return ret
}
@@ -12,4 +12,4 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package guesthandlers // import "yunion.io/x/onecloud/pkg/hostman/guesthandlers"
package guesthandlers // import "yunion.io/x/onecloud/pkg/hostman/guestman/guesthandlers"
@@ -452,7 +452,7 @@ func guestReloadDiskSnapshot(ctx context.Context, sid string, body jsonutils.JSO
return nil, httperrors.NewNotFoundError("Disk not found")
}
hostutils.DelayTaskWithoutReqctx(ctx, guestman.GetGuestManager().ReloadDiskSnapshot, &guestman.SReloadDisk{sid, disk})
hostutils.DelayTask(ctx, guestman.GetGuestManager().ReloadDiskSnapshot, &guestman.SReloadDisk{sid, disk})
return nil, nil
}
@@ -519,7 +519,7 @@ func guestDeleteSnapshot(ctx context.Context, sid string, body jsonutils.JSONObj
Disk: disk,
}
if !jsonutils.QueryBoolean(body, "auto_delete", false) {
if !jsonutils.QueryBoolean(body, "auto_deleted", false) {
convertSnapshot, err := body.GetString("convert_snapshot")
if err != nil {
return nil, httperrors.NewMissingParameterError("convert_snapshot")
+18 -19
View File
@@ -25,24 +25,24 @@ import (
"sync"
"time"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/cgrouputils"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/netutils2"
"yunion.io/x/onecloud/pkg/util/seclib2"
"yunion.io/x/onecloud/pkg/util/timeutils2"
compute "yunion.io/x/onecloud/pkg/apis/compute"
appsrv "yunion.io/x/onecloud/pkg/appsrv"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
hostutils "yunion.io/x/onecloud/pkg/hostman/hostutils"
options "yunion.io/x/onecloud/pkg/hostman/options"
storageman "yunion.io/x/onecloud/pkg/hostman/storageman"
httperrors "yunion.io/x/onecloud/pkg/httperrors"
modules "yunion.io/x/onecloud/pkg/mcclient/modules"
cgrouputils "yunion.io/x/onecloud/pkg/util/cgrouputils"
fileutils2 "yunion.io/x/onecloud/pkg/util/fileutils2"
netutils2 "yunion.io/x/onecloud/pkg/util/netutils2"
seclib2 "yunion.io/x/onecloud/pkg/util/seclib2"
timeutils2 "yunion.io/x/onecloud/pkg/util/timeutils2"
)
const (
@@ -323,7 +323,7 @@ func (m *SGuestManager) GuestDeploy(ctx context.Context, params interface{}) (js
if jsonutils.QueryBoolean(deployParams.Body, "k8s_pod", false) {
return nil, nil
}
publicKey := sshkeys.GetKeys(deployParams.Body)
publicKey := deployapi.GetKeys(deployParams.Body)
deploys, _ := deployParams.Body.GetArray("deploys")
password, _ := deployParams.Body.GetString("password")
resetPassword := jsonutils.QueryBoolean(deployParams.Body, "reset_password", false)
@@ -332,12 +332,11 @@ func (m *SGuestManager) GuestDeploy(ctx context.Context, params interface{}) (js
}
enableCloudInit := jsonutils.QueryBoolean(deployParams.Body, "enable_cloud_init", false)
guestInfo, err := guest.DeployFs(guestfs.NewDeployInfo(
publicKey, deploys, password, deployParams.IsInit, false,
guestInfo, err := guest.DeployFs(deployapi.NewDeployInfo(
publicKey, deployapi.JsonDeploysToStructs(deploys), password, deployParams.IsInit, false,
options.HostOptions.LinuxDefaultRootUser, options.HostOptions.WindowsDefaultAdminUser, enableCloudInit))
if err != nil {
log.Errorf("Deploy guest fs error: %s", err)
return nil, err
return nil, errors.Wrap(err, "Deploy guest fs")
} else {
return guestInfo, nil
}
+9 -5
View File
@@ -587,8 +587,8 @@ func (s *SGuestStreamDisksTask) onBlockDrivesSucc(res *jsonutils.JSONArray) {
if len(s.streamDevs) == 0 {
s.taskComplete()
} else {
s.SyncStatus()
s.startDoBlockStream()
s.SyncStatus()
}
}
@@ -679,8 +679,11 @@ func (s *SGuestReloadDiskTask) WaitSnapshotReplaced(callback func()) error {
return fmt.Errorf(
"SnapshotDeleteJob.deleting_disk_snapshot always has %s", s.disk.GetId())
}
if _, ok := storageman.DELETEING_SNAPSHOTS[s.disk.GetId()]; ok {
if _, ok := storageman.DELETEING_SNAPSHOTS.Load(s.disk.GetId()); ok {
time.Sleep(time.Second * 1)
} else {
break
}
}
@@ -747,7 +750,9 @@ func (s *SGuestReloadDiskTask) onReloadSucc(err string) {
func (s *SGuestReloadDiskTask) onResumeSucc(results string) {
log.Infof("guest reload disk task resume succ %s", results)
hostutils.TaskComplete(s.ctx, nil)
params := jsonutils.NewDict()
params.Set("reopen", jsonutils.JSONTrue)
hostutils.TaskComplete(s.ctx, params)
}
func (s *SGuestReloadDiskTask) taskFailed(reason string) {
@@ -803,8 +808,7 @@ func (s *SGuestDiskSnapshotTask) onSnapshotBlkdevFail(string) {
func (s *SGuestDiskSnapshotTask) onResumeSucc(res string) {
log.Infof("guest disk snapshot task resume succ %s", res)
snapshotDir := s.disk.GetSnapshotDir()
snapshotLocation := path.Join(snapshotDir, s.snapshotId)
snapshotLocation := path.Join(s.disk.GetSnapshotLocation(), s.snapshotId)
body := jsonutils.NewDict()
body.Set("location", jsonutils.NewString(snapshotLocation))
hostutils.TaskComplete(s.ctx, body)
+4 -4
View File
@@ -32,7 +32,7 @@ import (
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/appctx"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/hostman/hostinfo/hostbridge"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/monitor"
@@ -761,7 +761,7 @@ func (s *SKVMGuestInstance) StartGuest(ctx context.Context, params jsonutils.JSO
func() { s.asyncScriptStart(ctx, jsonutils.NewDict()) }, nil, nil)
}
func (s *SKVMGuestInstance) DeployFs(deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error) {
func (s *SKVMGuestInstance) DeployFs(deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
disks, _ := s.Desc.GetArray("disks")
if len(disks) > 0 {
diskPath, _ := disks[0].GetString("path")
@@ -1354,9 +1354,9 @@ func (s *SKVMGuestInstance) StaticSaveSnapshot(
if err != nil {
return nil, err
}
location := path.Join(disk.GetSnapshotDir(), snapshotId)
location := path.Join(disk.GetSnapshotLocation(), snapshotId)
res := jsonutils.NewDict()
res.Set("localtion", jsonutils.NewString(location))
res.Set("location", jsonutils.NewString(location))
return res, nil
}
+11 -3
View File
@@ -24,10 +24,10 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/cronman"
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/cloudcommon/service"
"yunion.io/x/onecloud/pkg/hostman/diskhandlers"
"yunion.io/x/onecloud/pkg/hostman/downloader"
"yunion.io/x/onecloud/pkg/hostman/guesthandlers"
"yunion.io/x/onecloud/pkg/hostman/guestman"
"yunion.io/x/onecloud/pkg/hostman/guestman/guesthandlers"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
"yunion.io/x/onecloud/pkg/hostman/hostinfo"
"yunion.io/x/onecloud/pkg/hostman/hostmetrics"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
@@ -35,6 +35,8 @@ 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/hostman/storageman/diskhandlers"
"yunion.io/x/onecloud/pkg/hostman/storageman/storagehandler"
"yunion.io/x/onecloud/pkg/util/sysutils"
)
@@ -49,7 +51,12 @@ func (host *SHostService) InitService() {
log.Fatalf("host service must running with root permissions")
}
if len(options.HostOptions.DeployServerSocketPath) == 0 {
log.Fatalf("missing deploy server socket path")
}
options.HostOptions.EnableRbac = false // disable rbac
// init base option for pid file
host.SServiceBase.O = &options.HostOptions.BaseOptions
}
@@ -64,6 +71,7 @@ func (host *SHostService) RunService() {
log.Fatalf(err.Error())
}
deployclient.Init(options.HostOptions.DeployServerSocketPath)
if err := storageman.Init(hostInstance); err != nil {
log.Fatalf(err.Error())
}
@@ -104,7 +112,7 @@ func (host *SHostService) RunService() {
func (host *SHostService) initHandlers(app *appsrv.Application) {
guesthandlers.AddGuestTaskHandler("", app)
storageman.AddStorageHandler("", app)
storagehandler.AddStorageHandler("", app)
diskhandlers.AddDiskHandler("", app)
downloader.AddDownloadHandler("", app)
kubehandlers.AddKubeAgentHandler("", app)
File diff suppressed because it is too large Load Diff
+159
View File
@@ -0,0 +1,159 @@
syntax = "proto3";
package apis;
message GuestDesc {
string name = 1;
string uuid = 2;
string domain = 3;
repeated Nic nics = 4;
repeated Nic nics_standby = 5;
repeated Disk disks = 6;
}
message Disk {
string disk_id = 1;
string driver = 2;
string cache_mode = 3;
string aio_mode = 4;
int64 size = 5;
string template_id = 6;
string image_path = 7;
string storage_id = 8;
bool migrating = 9;
string target_storage_id = 10;
string path = 11;
string format = 12;
int32 index = 13;
bool merge_snapshot = 14;
string fs = 15;
string mountpoint = 16;
string dev = 17;
}
message Nic {
string mac = 1;
string ip = 2;
string net = 3;
string net_id = 4;
bool virtual = 5;
string gateway = 6;
string dns = 7;
string domain = 8;
repeated Routes routes = 9;
string ifname = 10;
int32 masklen = 11;
string driver = 12;
string bridge = 13;
string wire_id = 14;
int32 vlan = 15;
string interface = 16;
int32 bw = 17;
int32 index = 18;
repeated string virtual_ips = 19;
string externel_id = 20;
string team_with = 21;
bool manual = 22;
string nic_type = 23;
bool link_up = 24;
int64 mtu = 25;
string name = 26;
}
message Routes {
repeated string route = 1;
}
message DeployInfo {
SSHKeys public_key = 1;
repeated DeployContent deploys = 2;
string password = 3;
bool is_init = 4;
bool enable_tty = 5;
bool default_root_user = 6;
bool windows_default_admin_user = 7;
bool enable_cloud_init = 8;
}
message SSHKeys {
string public_key = 1;
string delete_public_key = 2;
string admin_public_key = 3;
string project_public_key = 4;
}
message DeployContent {
string path = 1;
string content = 2;
string action = 3;
}
message Empty {
}
message DeployGuestFsResponse {
string distro = 1;
string version = 2;
string arch = 3;
string language = 4;
string os = 5;
string account = 6;
string key = 7;
}
message DeployParams {
string disk_path = 1;
GuestDesc guest_desc = 2;
DeployInfo deploy_info = 3;
}
message ResizeFsParams {
string disk_path = 1;
}
message FormatFsParams {
string disk_path = 1;
string fs_format = 2;
string uuid = 3;
}
message ReleaseInfo {
string distro = 1;
string version = 2;
string arch = 3;
string language = 4;
}
message SaveToGlanceParams {
string disk_path = 1;
bool compress = 2;
}
message SaveToGlanceResponse {
string os_info = 1;
ReleaseInfo release_info = 2;
}
message ProbeImageInfoPramas {
string disk_path = 1;
}
message ImageInfo {
ReleaseInfo os_info = 1;
string os_type = 2;
bool is_uefi_support = 3;
bool is_lvm_partition = 4;
bool is_readonly = 5;
string physical_partition_type = 6;
bool is_installed_cloud_init = 7;
}
service DeployAgent {
rpc DeployGuestFs (DeployParams) returns (DeployGuestFsResponse);
rpc ResizeFs (ResizeFsParams) returns (Empty);
rpc FormatFs (FormatFsParams) returns (Empty);
rpc SaveToGlance (SaveToGlanceParams) returns (SaveToGlanceResponse);
rpc ProbeImageInfo(ProbeImageInfoPramas) returns (ImageInfo);
}
+1
View File
@@ -0,0 +1 @@
package apis // import "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
+114
View File
@@ -0,0 +1,114 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package apis
import (
"yunion.io/x/jsonutils"
)
func NewDeployInfo(
publicKey *SSHKeys,
deploys []*DeployContent,
password string,
isInit bool,
enableTty bool,
defaultRootUser bool,
windowsDefaultAdminUser bool,
enableCloudInit bool,
) *DeployInfo {
return &DeployInfo{
PublicKey: publicKey,
Deploys: deploys,
Password: password,
IsInit: isInit,
EnableTty: enableTty,
DefaultRootUser: defaultRootUser,
WindowsDefaultAdminUser: windowsDefaultAdminUser,
EnableCloudInit: enableCloudInit,
}
}
func JsonDeploysToStructs(jdeploys []jsonutils.JSONObject) []*DeployContent {
ret := []*DeployContent{}
for i := 0; i < len(jdeploys); i++ {
d := new(DeployContent)
path, err := jdeploys[i].GetString("path")
if err == nil {
d.Path = path
}
content, err := jdeploys[i].GetString("content")
if err == nil {
d.Content = content
}
ret = append(ret, d)
}
return ret
}
func GetKeys(data jsonutils.JSONObject) *SSHKeys {
var ret = new(SSHKeys)
ret.PublicKey, _ = data.GetString("public_key")
ret.DeletePublicKey, _ = data.GetString("delete_public_key")
ret.AdminPublicKey, _ = data.GetString("admin_public_key")
ret.ProjectPublicKey, _ = data.GetString("project_public_key")
return ret
}
func GuestDescToDeployDesc(guestDesc *jsonutils.JSONDict) (*GuestDesc, error) {
ret := new(GuestDesc)
ret.Name, _ = guestDesc.GetString("name")
ret.Domain, _ = guestDesc.GetString("domain")
ret.Uuid, _ = guestDesc.GetString("uuid")
jnics, _ := guestDesc.Get("nics")
jdisks, _ := guestDesc.Get("disks")
jnicsStandby, _ := guestDesc.Get("nics_standby")
if jnics != nil {
nics := make([]*Nic, 0)
err := jnics.Unmarshal(&nics)
if err != nil {
return nil, err
}
ret.Nics = nics
}
if jdisks != nil {
disks := make([]*Disk, 0)
err := jdisks.Unmarshal(&disks)
if err != nil {
return nil, err
}
ret.Disks = disks
}
if jnicsStandby != nil {
nicsStandby := make([]*Nic, 0)
err := jnicsStandby.Unmarshal(nicsStandby)
if err != nil {
return nil, err
}
ret.NicsStandby = nicsStandby
}
return ret, nil
}
func NewReleaseInfo(distro, version, arch string) *ReleaseInfo {
return &ReleaseInfo{
Distro: distro,
Version: version,
Arch: arch,
}
}
@@ -0,0 +1,105 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deployclient
import (
"context"
"net"
"time"
"google.golang.org/grpc"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
var (
deployClient *DeployClient
_ deployapi.DeployAgentClient = deployClient
)
func Init(socketPath string) {
deployClient = NewDeployClient(socketPath)
}
type DeployClient struct {
socketPath string
}
func NewDeployClient(socketPath string) *DeployClient {
return &DeployClient{socketPath}
}
func GetDeployClient() *DeployClient {
return deployClient
}
func grcpDialWithUnixSocket(ctx context.Context, socketPath string) (*grpc.ClientConn, error) {
return grpc.DialContext(ctx, socketPath, grpc.WithInsecure(), grpc.WithBlock(),
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
}),
)
}
func (c *DeployClient) DeployGuestFs(ctx context.Context, in *deployapi.DeployParams, opts ...grpc.CallOption) (*deployapi.DeployGuestFsResponse, error) {
conn, err := grcpDialWithUnixSocket(ctx, c.socketPath)
if err != nil {
return nil, err
}
defer conn.Close()
client := deployapi.NewDeployAgentClient(conn)
ret, err := client.DeployGuestFs(ctx, in, opts...)
return ret, err
}
func (c *DeployClient) ResizeFs(ctx context.Context, in *deployapi.ResizeFsParams, opts ...grpc.CallOption) (*deployapi.Empty, error) {
conn, err := grcpDialWithUnixSocket(ctx, c.socketPath)
if err != nil {
return nil, err
}
defer conn.Close()
client := deployapi.NewDeployAgentClient(conn)
return client.ResizeFs(ctx, in, opts...)
}
func (c *DeployClient) FormatFs(ctx context.Context, in *deployapi.FormatFsParams, opts ...grpc.CallOption) (*deployapi.Empty, error) {
conn, err := grcpDialWithUnixSocket(ctx, c.socketPath)
if err != nil {
return nil, err
}
defer conn.Close()
client := deployapi.NewDeployAgentClient(conn)
return client.FormatFs(ctx, in, opts...)
}
func (c *DeployClient) SaveToGlance(ctx context.Context, in *deployapi.SaveToGlanceParams, opts ...grpc.CallOption) (*deployapi.SaveToGlanceResponse, error) {
conn, err := grcpDialWithUnixSocket(ctx, c.socketPath)
if err != nil {
return nil, err
}
defer conn.Close()
client := deployapi.NewDeployAgentClient(conn)
return client.SaveToGlance(ctx, in, opts...)
}
func (c *DeployClient) ProbeImageInfo(ctx context.Context, in *deployapi.ProbeImageInfoPramas, opts ...grpc.CallOption) (*deployapi.ImageInfo, error) {
conn, err := grcpDialWithUnixSocket(ctx, c.socketPath)
if err != nil {
return nil, err
}
defer conn.Close()
client := deployapi.NewDeployAgentClient(conn)
return client.ProbeImageInfo(ctx, in, opts...)
}
@@ -0,0 +1 @@
package deployclient // import "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
@@ -0,0 +1,254 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deployserver
import (
"context"
"errors"
"fmt"
"net"
"os"
"strings"
"google.golang.org/grpc"
"yunion.io/x/log"
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
service "yunion.io/x/onecloud/pkg/cloudcommon/service"
diskutils "yunion.io/x/onecloud/pkg/hostman/diskutils"
nbd "yunion.io/x/onecloud/pkg/hostman/diskutils/nbd"
guestfs "yunion.io/x/onecloud/pkg/hostman/guestfs"
fsdriver "yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
fileutils2 "yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/sysutils"
"yunion.io/x/onecloud/pkg/util/winutils"
)
type DeployerServer struct{}
func (*DeployerServer) DeployGuestFs(ctx context.Context, req *deployapi.DeployParams,
) (*deployapi.DeployGuestFsResponse, error) {
log.Infof("Deploy guest fs on %s", req.DiskPath)
var kvmDisk = diskutils.NewKVMGuestDisk(req.DiskPath)
defer kvmDisk.Disconnect()
if !kvmDisk.Connect() {
log.Infof("Failed to connect kvm disk")
return new(deployapi.DeployGuestFsResponse), nil
}
root := kvmDisk.MountKvmRootfs()
if root == nil {
log.Infof("Failed mounting rootfs for kvm disk")
return new(deployapi.DeployGuestFsResponse), nil
}
defer kvmDisk.UmountKvmRootfs(root)
ret, err := guestfs.DoDeployGuestFs(root, req.GuestDesc, req.DeployInfo)
if err != nil {
return new(deployapi.DeployGuestFsResponse), err
}
if ret == nil {
return new(deployapi.DeployGuestFsResponse), nil
}
return ret, nil
}
func (*DeployerServer) ResizeFs(ctx context.Context, req *deployapi.ResizeFsParams,
) (*deployapi.Empty, error) {
log.Infof("Resize fs on %s", req.DiskPath)
disk := diskutils.NewKVMGuestDisk(req.DiskPath)
defer disk.Disconnect()
if disk.Connect() {
if err := disk.ResizePartition(); err != nil {
return new(deployapi.Empty), err
}
}
return new(deployapi.Empty), nil
}
func (*DeployerServer) FormatFs(ctx context.Context, req *deployapi.FormatFsParams) (*deployapi.Empty, error) {
log.Infof("Format fs on %s", req.DiskPath)
gd := diskutils.NewKVMGuestDisk(req.DiskPath)
defer gd.Disconnect()
if gd.Connect() {
if err := gd.MakePartition(req.FsFormat); err == nil {
err = gd.FormatPartition(req.FsFormat, req.Uuid)
if err != nil {
return new(deployapi.Empty), err
}
} else {
return new(deployapi.Empty), err
}
}
return new(deployapi.Empty), nil
}
func (*DeployerServer) SaveToGlance(ctx context.Context, req *deployapi.SaveToGlanceParams) (*deployapi.SaveToGlanceResponse, error) {
log.Infof("%s save to glance", req.DiskPath)
var (
kvmDisk = diskutils.NewKVMGuestDisk(req.DiskPath)
osInfo string
relInfo *deployapi.ReleaseInfo
)
defer kvmDisk.Disconnect()
if kvmDisk.Connect() {
var err error
func() {
if root := kvmDisk.MountKvmRootfs(); root != nil {
defer kvmDisk.UmountKvmRootfs(root)
osInfo = root.GetOs()
relInfo = root.GetReleaseInfo(root.GetPartition())
if req.Compress {
err = root.PrepareFsForTemplate(root.GetPartition())
}
}
}()
if err != nil {
log.Errorln(err)
return new(deployapi.SaveToGlanceResponse), err
}
if req.Compress {
kvmDisk.Zerofree()
}
}
return &deployapi.SaveToGlanceResponse{
OsInfo: osInfo,
ReleaseInfo: relInfo,
}, nil
}
func getImageInfo(kvmDisk *diskutils.SKVMGuestDisk, rootfs fsdriver.IRootFsDriver) *deployapi.ImageInfo {
partition := rootfs.GetPartition()
return &deployapi.ImageInfo{
OsInfo: rootfs.GetReleaseInfo(partition),
OsType: rootfs.GetOs(),
IsUefiSupport: kvmDisk.DetectIsUEFISupport(rootfs),
IsLvmPartition: kvmDisk.IsLVMPartition(),
IsReadonly: partition.IsReadonly(),
PhysicalPartitionType: partition.GetPhysicalPartitionType(),
IsInstalledCloudInit: rootfs.IsCloudinitInstall(),
}
}
func (*DeployerServer) ProbeImageInfo(ctx context.Context, req *deployapi.ProbeImageInfoPramas) (*deployapi.ImageInfo, error) {
log.Infof("%s probe image info", req.DiskPath)
kvmDisk := diskutils.NewKVMGuestDisk(req.DiskPath)
defer kvmDisk.Disconnect()
if !kvmDisk.Connect() {
log.Infof("Failed to connect kvm disk")
return new(deployapi.ImageInfo), errors.New("Disk connector failed to connect image")
}
// Fsck is executed during mount
rootfs := kvmDisk.MountKvmRootfs()
if rootfs == nil {
return new(deployapi.ImageInfo), fmt.Errorf("Failed mounting rootfs for kvm disk")
}
defer kvmDisk.UmountKvmRootfs(rootfs)
imageInfo := getImageInfo(kvmDisk, rootfs)
log.Infof("ProbeImageInfo response %s", imageInfo)
return imageInfo, nil
}
type SDeployService struct {
*service.SServiceBase
}
func NewDeployService() *SDeployService {
deployer := &SDeployService{}
deployer.SServiceBase = service.NewBaseService(deployer)
return deployer
}
func (s *SDeployService) RunService() {
grpcServer := grpc.NewServer()
deployapi.RegisterDeployAgentServer(grpcServer, &DeployerServer{})
if fileutils2.Exists(DeployOption.DeployServerSocketPath) {
if err := os.Remove(DeployOption.DeployServerSocketPath); err != nil {
log.Fatalln(err)
}
}
listener, err := net.Listen("unix", DeployOption.DeployServerSocketPath)
if err != nil {
log.Fatalln(err)
}
defer listener.Close()
log.Infof("Init net listener on %s succ", DeployOption.DeployServerSocketPath)
grpcServer.Serve(listener)
}
func (s *SDeployService) FixPathEnv() error {
var paths = []string{
"/usr/local/sbin",
"/usr/local/bin",
"/sbin",
"/bin",
"/usr/sbin",
"/usr/bin",
}
return os.Setenv("PATH", strings.Join(paths, ":"))
}
func (s *SDeployService) PrepareEnv() error {
if err := s.FixPathEnv(); err != nil {
return err
}
output, err := procutils.NewCommand("rmmod", "nbd").Run()
if err != nil {
log.Errorf("rmmod error: %s", output)
}
output, err = procutils.NewCommand("modprobe", "nbd", "max_part=16").Run()
if err != nil {
log.Errorf("Failed to activate nbd device: %s", output)
}
nbd.Init()
for i := 0; i < 16; i++ {
nbdBdi := fmt.Sprintf("/sys/block/nbd%d/bdi/", i)
sysutils.SetSysConfig(nbdBdi+"max_ratio", "0")
sysutils.SetSysConfig(nbdBdi+"min_ratio", "0")
}
if !winutils.CheckTool(DeployOption.ChntpwPath) {
log.Errorf("Failed to find chntpw tool")
}
output, err = procutils.NewCommand("pvscan").Run()
if err != nil {
log.Errorf("Failed exec lvm command pvscan: %s", output)
}
return nil
}
func (s *SDeployService) InitService() {
common_options.ParseOptions(&DeployOption, os.Args, "host.conf", "deploy-server")
if err := s.PrepareEnv(); err != nil {
log.Fatalln(err)
}
fsdriver.Init(DeployOption.PrivatePrefixes)
s.O = &DeployOption.BaseOptions
if len(DeployOption.DeployServerSocketPath) == 0 {
log.Fatalf("missing deploy server socket path")
}
// TODO implentment func onExit
s.SignalTrap(nil)
}
func (s *SDeployService) OnExitService() {}
@@ -0,0 +1 @@
package deployserver // import "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployserver"
@@ -0,0 +1,27 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deployserver
import "yunion.io/x/onecloud/pkg/cloudcommon/options"
type SDeployOptions struct {
options.BaseOptions
DeployServerSocketPath string `help:"Deploy server listen socket path"`
PrivatePrefixes []string `help:"IPv4 private prefixes"`
ChntpwPath string `help:"path to chntpw tool" default:"/usr/local/bin/chntpw.static"`
}
var DeployOption SDeployOptions
+1 -1
View File
@@ -98,7 +98,7 @@ func (s *SGuestDHCPServer) getGuestConfig(guestDesc, guestNic jsonutils.JSONObje
masklen := nicdesc.Masklen
conf.ServerIP = net.ParseIP(v4Ip.NetAddr(int8(masklen)).String())
conf.SubnetMask = net.ParseIP(netutils2.Netlen2Mask(masklen))
conf.SubnetMask = net.ParseIP(netutils2.Netlen2Mask(int(masklen)))
conf.BroadcastAddr = v4Ip.BroadcastAddr(int8(masklen)).ToBytes()
conf.Hostname, _ = guestDesc.GetString("name")
conf.Domain = nicdesc.Domain
+12 -55
View File
@@ -31,14 +31,13 @@ import (
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/hostman/hostinfo/hostbridge"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/isolated_device"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/hostman/storageman/nbd"
"yunion.io/x/onecloud/pkg/hostman/system_service"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
@@ -50,7 +49,6 @@ import (
"yunion.io/x/onecloud/pkg/util/qemutils"
"yunion.io/x/onecloud/pkg/util/sysutils"
"yunion.io/x/onecloud/pkg/util/timeutils2"
"yunion.io/x/onecloud/pkg/util/winutils"
)
type SHostInfo struct {
@@ -214,25 +212,6 @@ func (h *SHostInfo) prepareEnv() error {
return fmt.Errorf("Cannot initialize control group subsystem")
}
output, err = procutils.NewCommand("rmmod", "nbd").Run()
if err != nil {
log.Errorf("rmmod error: %s", output)
}
output, err = procutils.NewCommand("modprobe", "nbd", "max_part=16").Run()
if err != nil {
log.Errorf("Failed to activate nbd device: %s", output)
}
nbd.Init()
if !winutils.CheckTool(options.HostOptions.ChntpwPath) {
return fmt.Errorf("Failed to find chntpw tool")
}
output, err = procutils.NewCommand("pvscan").Run()
if err != nil {
log.Errorf("Failed exec lvm command pvscan: %s", output)
}
if err := hostbridge.Prepare(options.HostOptions.BridgeDriver); err != nil {
log.Errorln(err)
return err
@@ -261,11 +240,7 @@ func (h *SHostInfo) prepareEnv() error {
default:
return fmt.Errorf("Invalid hugepages option")
}
for i := 0; i < 16; i++ {
nbdBdi := fmt.Sprintf("/sys/block/nbd%d/bdi/", i)
h.setSysConfig(nbdBdi+"max_ratio", "0")
h.setSysConfig(nbdBdi+"min_ratio", "0")
}
h.PreventArpFlux()
h.TuneSystem()
return nil
@@ -312,7 +287,7 @@ func (h *SHostInfo) checkSystemServices() error {
}
}
for _, srv := range []string{"host_sdnagent"} {
for _, srv := range []string{"host_sdnagent", "host-deployer"} {
srvinst := system_service.GetService(srv)
if !srvinst.IsInstalled() {
log.Warningf("Service %s not installed", srv)
@@ -350,7 +325,7 @@ func (h *SHostInfo) DisableHugepages() {
"/sys/kernel/mm/transparent_hugepage/defrag": "never",
}
for k, v := range kv {
h.setSysConfig(k, v)
sysutils.SetSysConfig(k, v)
}
}
@@ -361,7 +336,7 @@ func (h *SHostInfo) EnableTransparentHugepages() {
"/sys/kernel/mm/transparent_hugepage/defrag": "always",
}
for k, v := range kv {
h.setSysConfig(k, v)
sysutils.SetSysConfig(k, v)
}
}
@@ -380,7 +355,7 @@ func (h *SHostInfo) EnableNativeHugepages() error {
"/sys/kernel/mm/transparent_hugepage/defrag": "never",
}
for k, v := range kv {
h.setSysConfig(k, v)
sysutils.SetSysConfig(k, v)
}
preAllocPagesNum := h.GetMemory()/h.Mem.GetHugepagesizeMb() + 1
err := timeutils2.CommandWithTimeout(1, "sh", "-c", fmt.Sprintf("echo %d > /proc/sys/vm/nr_hugepages", preAllocPagesNum)).Run()
@@ -397,36 +372,18 @@ func (h *SHostInfo) EnableNativeHugepages() error {
return nil
}
func (h *SHostInfo) setSysConfig(cpath, val string) bool {
if fileutils2.Exists(cpath) {
oval, err := ioutil.ReadFile(cpath)
if err != nil {
log.Errorln(err)
return false
}
if string(oval) != val {
err = fileutils2.FilePutContents(cpath, val, false)
if err == nil {
return true
}
log.Errorln(err)
}
}
return false
}
func (h *SHostInfo) EnableKsm(sleepSec int) {
h.setSysConfig("/sys/kernel/mm/ksm/run", "1")
h.setSysConfig("/sys/kernel/mm/ksm/sleep_millisecs",
sysutils.SetSysConfig("/sys/kernel/mm/ksm/run", "1")
sysutils.SetSysConfig("/sys/kernel/mm/ksm/sleep_millisecs",
fmt.Sprintf("%d", sleepSec*1000))
}
func (h *SHostInfo) DisableKsm() {
h.setSysConfig("/sys/kernel/mm/ksm/run", "0")
sysutils.SetSysConfig("/sys/kernel/mm/ksm/run", "0")
}
func (h *SHostInfo) PreventArpFlux() {
h.setSysConfig("/proc/sys/net/ipv4/conf/all/arp_filter", "1")
sysutils.SetSysConfig("/proc/sys/net/ipv4/conf/all/arp_filter", "1")
}
// Any system wide optimizations
@@ -436,7 +393,7 @@ func (h *SHostInfo) TuneSystem() {
"/sys/module/kvm/parameters/ignore_msrs": "1",
}
for k, v := range kv {
h.setSysConfig(k, v)
sysutils.SetSysConfig(k, v)
}
}
@@ -1158,7 +1115,7 @@ func (h *SHostInfo) deployAdminAuthorizedKeys() {
}
keys := ret.Data[0]
adminPublicKey, _ := keys.GetString("public_key")
pubKeys := &sshkeys.SSHKeys{AdminPublicKey: adminPublicKey}
pubKeys := &deployapi.SSHKeys{AdminPublicKey: adminPublicKey}
authFile := path.Join(sshDir, "authorized_keys")
oldKeysBytes, _ := fileutils2.FileGetContents(authFile)
+3 -1
View File
@@ -63,7 +63,7 @@ type SHostOptions struct {
LocalImagePath []string `help:"Local image storage paths"`
SharedStorages []string `help:"Path of shared storages"`
DefaultQemuVersion string `help:"Default qemu version" default:"2.9.1"`
DefaultQemuVersion string `help:"Default qemu version" default:"2.12.1"`
DhcpRelay []string `help:"DHCP relay upstream"`
DhcpLeaseTime int `default:"100663296" help:"DHCP lease time in seconds"`
@@ -104,6 +104,8 @@ type SHostOptions struct {
HostCpuPassthrough bool `default:"true" help:"if it is true, set qemu cpu type as -cpu host, otherwise, qemu64. default is true"`
MaxReservedMemory int `default:"10240" help:"host reserved memory"`
DeployServerSocketPath string `help:"Deploy server listen socket path"`
}
var HostOptions SHostOptions
+1 -1
View File
@@ -61,7 +61,7 @@ func NewStorageManager(host hostutils.IHost) (*SStorageManager, error) {
for i, d := range options.HostOptions.LocalImagePath {
s := NewLocalStorage(ret, d, i)
if s.Accessible() {
s.StartSnapshotRecycle()
StartSnapshotRecycle(s)
ret.Storages = append(ret.Storages, s)
if allFull && s.GetFreeSizeMb() > MINIMAL_FREE_SPACE {
allFull = false
+49 -28
View File
@@ -19,10 +19,12 @@ import (
"fmt"
"path"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
)
type IDisk interface {
@@ -33,6 +35,7 @@ type IDisk interface {
GetSnapshotDir() string
GetDiskDesc() jsonutils.JSONObject
GetDiskSetupScripts(idx int) string
GetSnapshotLocation() string
DeleteAllSnapshot() error
Delete(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
@@ -42,16 +45,17 @@ type IDisk interface {
CleanupSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
PrepareMigrate(liveMigrate bool) (string, error)
CreateFromUrl(context.Context, string) error
CreateFromUrl(ctx context.Context, url string, size int64) error
CreateFromTemplate(context.Context, string, string, int64) (jsonutils.JSONObject, error)
CreateFromImageFuse(context.Context, string) error
CreateFromSnapshotLocation(ctx context.Context, location string, size int64) error
CreateFromImageFuse(ctx context.Context, url string, size int64) error
CreateRaw(ctx context.Context, sizeMb int, diskFromat string, fsFormat string,
encryption bool, diskId string, back string) (jsonutils.JSONObject, error)
PostCreateFromImageFuse()
CreateSnapshot(snapshotId string) error
DeleteSnapshot(snapshotId, convertSnapshot string, pendingDelete bool) error
DeployGuestFs(diskPath string, guestDesc *jsonutils.JSONDict,
deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error)
deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error)
}
type SBaseDisk struct {
@@ -82,7 +86,7 @@ func (d *SBaseDisk) Delete(ctx context.Context, params interface{}) (jsonutils.J
return nil, fmt.Errorf("Not implemented")
}
func (d *SBaseDisk) CreateFromUrl(context.Context, string) error {
func (d *SBaseDisk) CreateFromUrl(ctx context.Context, url string, size int64) error {
return fmt.Errorf("Not implemented")
}
@@ -90,6 +94,10 @@ func (d *SBaseDisk) CreateFromTemplate(context.Context, string, string, int64) (
return nil, fmt.Errorf("Not implemented")
}
func (d *SBaseDisk) CreateFromSnapshotLocation(ctx context.Context, location string, size int64) error {
return fmt.Errorf("Not implemented")
}
func (d *SBaseDisk) Resize(context.Context, interface{}) (jsonutils.JSONObject, error) {
return nil, fmt.Errorf("Not implemented")
}
@@ -99,36 +107,49 @@ func (d *SBaseDisk) GetZone() string {
}
func (d *SBaseDisk) DeployGuestFs(diskPath string, guestDesc *jsonutils.JSONDict,
deployInfo *guestfs.SDeployInfo) (jsonutils.JSONObject, error) {
var kvmDisk = NewKVMGuestDisk(diskPath)
defer kvmDisk.Disconnect()
if !kvmDisk.Connect() {
log.Infof("Failed to connect kvm disk")
return nil, nil
deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
deployGuestDesc, err := deployapi.GuestDescToDeployDesc(guestDesc)
if err != nil {
return nil, errors.Wrap(err, "guest desc to deploy desc")
}
root := kvmDisk.MountKvmRootfs()
if root == nil {
log.Infof("Failed mounting rootfs for kvm disk")
return nil, nil
ret, err := deployclient.GetDeployClient().DeployGuestFs(
context.Background(), &deployapi.DeployParams{
DiskPath: diskPath,
GuestDesc: deployGuestDesc,
DeployInfo: deployInfo,
},
)
if err != nil {
return nil, errors.Wrap(err, "request deploy guest fs")
}
defer kvmDisk.UmountKvmRootfs(root)
return guestfs.DeployGuestFs(root, guestDesc, deployInfo)
return jsonutils.Marshal(ret), nil
}
func (d *SBaseDisk) ResizeFs(diskPath string) error {
disk := NewKVMGuestDisk(diskPath)
defer disk.Disconnect()
if disk.Connect() {
if err := disk.ResizePartition(); err != nil {
return err
}
}
return nil
_, err := deployclient.GetDeployClient().ResizeFs(
context.Background(), &deployapi.ResizeFsParams{DiskPath: diskPath})
return err
}
func (d *SBaseDisk) GetDiskSetupScripts(diskIndex int) string {
return ""
}
func (d *SBaseDisk) GetSnapshotLocation() string {
return ""
}
func (d *SBaseDisk) FormatFs(fsFormat, uuid, diskPath string) {
log.Infof("Make disk %s fs %s", uuid, fsFormat)
_, err := deployclient.GetDeployClient().FormatFs(
context.Background(),
&deployapi.FormatFsParams{
DiskPath: diskPath,
FsFormat: fsFormat,
Uuid: uuid,
},
)
if err != nil {
log.Errorf("Format fs error : %s", err)
}
}
+7 -19
View File
@@ -73,6 +73,10 @@ func (d *SLocalDisk) GetSnapshotDir() string {
return path.Join(d.Storage.GetSnapshotDir(), d.Id+options.HostOptions.SnapshotDirSuffix)
}
func (d *SLocalDisk) GetSnapshotLocation() string {
return d.GetSnapshotDir()
}
func (d *SLocalDisk) Probe() error {
if fileutils2.Exists(d.getPath()) {
d.isAlter = false
@@ -137,7 +141,7 @@ func (d *SLocalDisk) Resize(ctx context.Context, params interface{}) (jsonutils.
return d.GetDiskDesc(), nil
}
func (d *SLocalDisk) CreateFromImageFuse(ctx context.Context, url string) error {
func (d *SLocalDisk) CreateFromImageFuse(ctx context.Context, url string, size int64) error {
log.Infof("Create from image fuse %s", url)
var (
@@ -223,7 +227,7 @@ func (d *SLocalDisk) createFromTemplate(
}
}
func (d *SLocalDisk) CreateFromUrl(ctx context.Context, url string) error {
func (d *SLocalDisk) CreateFromUrl(ctx context.Context, url string, size int64) error {
remoteFile := remotefile.NewRemoteFile(ctx, url, d.getPath(), false, "", -1, nil, "", "")
if remoteFile.Fetch() {
if options.HostOptions.EnableFallocateDisk {
@@ -267,28 +271,12 @@ func (d *SLocalDisk) CreateRaw(ctx context.Context, sizeMB int, diskFormat, fsFo
}
if utils.IsInStringArray(fsFormat, []string{"swap", "ext2", "ext3", "ext4", "xfs"}) {
d.FormatFs(fsFormat, uuid)
d.FormatFs(fsFormat, uuid, d.GetPath())
}
return d.GetDiskDesc(), nil
}
func (d *SLocalDisk) FormatFs(fsFormat, uuid string) {
log.Infof("Make disk %s fs %s", uuid, fsFormat)
gd := NewKVMGuestDisk(d.GetPath())
defer gd.Disconnect()
if gd.Connect() {
if err := gd.MakePartition(fsFormat); err == nil {
err = gd.FormatPartition(fsFormat, uuid)
if err != nil {
log.Errorln(err)
}
} else {
log.Errorln(err)
}
}
}
func (d *SLocalDisk) GetDiskDesc() jsonutils.JSONObject {
qemuImg, err := qemuimg.NewQemuImage(d.getPath())
if err != nil {
+40
View File
@@ -16,10 +16,15 @@ package storageman
import (
"context"
"fmt"
"path"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/util/qemuimg"
)
type SNasDisk struct {
@@ -46,6 +51,41 @@ func (d *SNasDisk) CreateFromTemplate(ctx context.Context, imageId, format strin
return ret, nil
}
func (d *SNasDisk) CreateFromImageFuse(ctx context.Context, url string, size int64) error {
return fmt.Errorf("Not implemented")
}
func (d *SNasDisk) CreateFromSnapshotLocation(ctx context.Context, snapshotLocation string, size int64) error {
snapshotPath := path.Join(d.Storage.GetPath(), snapshotLocation)
newImg, err := qemuimg.NewQemuImage(d.GetPath())
if err != nil {
return errors.Wrap(err, "new image from snapshot")
}
if newImg.IsValid() {
if err := newImg.Delete(); err != nil {
log.Errorln(err)
return err
}
}
err = newImg.CreateQcow2(0, false, snapshotPath)
if err != nil {
return errors.Wrap(err, "create image from snapshot")
}
retSize, _ := d.GetDiskDesc().Int("disk_size")
log.Infof("REQSIZE: %d, RETSIZE: %d", size, retSize)
if size > retSize {
params := jsonutils.NewDict()
params.Set("size", jsonutils.NewInt(size))
_, err = d.Resize(ctx, params)
return err
}
return nil
}
func (d *SNasDisk) GetSnapshotLocation() string {
return d.GetSnapshotDir()[len(d.Storage.GetPath())+1:]
}
type SNFSDisk struct {
SNasDisk
}
+2 -22
View File
@@ -147,10 +147,6 @@ func (d *SRBDDisk) PrepareMigrate(liveMigrate bool) (string, error) {
return "", fmt.Errorf("Not support")
}
func (d *SRBDDisk) CreateFromUrl(context.Context, string) error {
return fmt.Errorf("Not impl")
}
func (d *SRBDDisk) CreateFromTemplate(ctx context.Context, imageId string, format string, size int64) (jsonutils.JSONObject, error) {
ret, err := d.createFromTemplate(ctx, imageId, format)
if err != nil {
@@ -186,7 +182,7 @@ func (d *SRBDDisk) createFromTemplate(ctx context.Context, imageId, format strin
return d.GetDiskDesc(), nil
}
func (d *SRBDDisk) CreateFromImageFuse(context.Context, string) error {
func (d *SRBDDisk) CreateFromImageFuse(ctx context.Context, url string, size int64) error {
return fmt.Errorf("Not support")
}
@@ -198,28 +194,12 @@ func (d *SRBDDisk) CreateRaw(ctx context.Context, sizeMb int, diskFromat string,
}
if utils.IsInStringArray(fsFormat, []string{"swap", "ext2", "ext3", "ext4", "xfs"}) {
d.FormatFs(fsFormat, diskId)
d.FormatFs(fsFormat, diskId, d.GetPath())
}
return d.GetDiskDesc(), nil
}
func (d *SRBDDisk) FormatFs(fsFormat, uuid string) {
log.Infof("Make disk %s fs %s", uuid, fsFormat)
gd := NewKVMGuestDisk(d.GetPath())
defer gd.Disconnect()
if gd.Connect() {
if err := gd.MakePartition(fsFormat); err == nil {
err = gd.FormatPartition(fsFormat, uuid)
if err != nil {
log.Errorln(err)
}
} else {
log.Errorln(err)
}
}
}
func (d *SRBDDisk) PostCreateFromImageFuse() {
log.Errorf("Not support PostCreateFromImageFuse")
}
@@ -12,4 +12,4 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package diskhandlers // import "yunion.io/x/onecloud/pkg/hostman/diskhandlers"
package diskhandlers // import "yunion.io/x/onecloud/pkg/hostman/storageman/diskhandlers"
+167 -14
View File
@@ -17,21 +17,37 @@ package storageman
import (
"context"
"fmt"
"io/ioutil"
"path"
"regexp"
"strings"
"sync"
"syscall"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/cronman"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/qemuimg"
)
const (
_RECYCLE_BIN_ = "recycle_bin"
_IMGSAVE_BACKUPS_ = "imgsave_backups"
_SNAPSHOT_PATH_ = "snapshots"
)
var DELETEING_SNAPSHOTS = sync.Map{}
type IStorageFactory interface {
NewStorage(manager *SStorageManager, mountPoint string) IStorage
StorageType() string
@@ -275,30 +291,167 @@ func (s *SBaseStorage) CreateDiskFromSnpashot(ctx context.Context, disk IDisk, c
// diskPath = path.Join(s.Path, createParams.DiskId)
snapshotUrl, _ = createParams.DiskInfo.GetString("snapshot_url")
transferProtocol, _ = createParams.DiskInfo.GetString("protocol")
diskSize, _ = createParams.DiskInfo.Int("size")
)
if len(snapshotUrl) == 0 || len(transferProtocol) == 0 {
return nil, fmt.Errorf("Create disk from snapshot missing params snapshot url or protocol")
}
if transferProtocol == "url" {
// TODO
// snapshotOutOfChain := jsonutils.QueryBoolean(
// createParams.DiskInfo, "snapshot_out_of_chain", false)
// // you wen ti...
// if err := s.CreateDiskFromUrl(ctx, snapshotUrl, diskPath, !snapshotOutOfChain); err != nil {
// return nil, err
// }
} else if transferProtocol == "fuse" {
if err := disk.CreateFromImageFuse(ctx, snapshotUrl); err != nil {
return nil, err
if createParams.Storage.StorageType() == compute.STORAGE_LOCAL {
if transferProtocol == "url" {
// not implement
} else if transferProtocol == "fuse" {
if err := disk.CreateFromImageFuse(ctx, snapshotUrl, diskSize); err != nil {
return nil, err
}
} else {
return nil, fmt.Errorf("Unkown protocol %s", transferProtocol)
}
} else if utils.IsInStringArray(createParams.Storage.StorageType(), compute.SHARED_FILE_STORAGE) {
if transferProtocol == "location" {
if err := disk.CreateFromSnapshotLocation(ctx, snapshotUrl, diskSize); err != nil {
return nil, err
}
} else {
return nil, fmt.Errorf("Unkown protocol %s", transferProtocol)
}
} else {
return nil, fmt.Errorf("Unkown protocol %s", transferProtocol)
}
return disk.GetDiskDesc(), nil
}
func (s *SBaseStorage) DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, desc, disksBackingFile, srcSnapshots jsonutils.JSONObject) error {
return nil
}
/*************************Background delete snapshot job****************************/
func StartSnapshotRecycle(storage IStorage) {
log.Infof("Snapshot recyle job started")
if !fileutils2.Exists(storage.GetSnapshotDir()) {
procutils.NewCommand("mkdir", "-p", storage.GetSnapshotDir()).Run()
}
cronman.GetCronJobManager(false).AddJob1(
"SnapshotRecycle", time.Hour*6,
func(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
snapshotRecycle(ctx, userCred, isStart, storage)
})
}
func snapshotRecycle(ctx context.Context, userCred mcclient.TokenCredential, isStart bool, storage IStorage) {
log.Infof("Snapshot Recycle Job Start, storage is %s, ss dir is %s", storage.GetStorageName(), storage.GetSnapshotDir())
res, err := modules.Snapshots.GetById(hostutils.GetComputeSession(ctx), "max-count", nil)
if err != nil {
log.Errorln(err)
return
}
maxSnapshotCount, err := res.Int("max_count")
if err != nil {
log.Errorln("Request region get snapshot max count failed")
return
}
files, err := ioutil.ReadDir(storage.GetSnapshotDir())
if err != nil {
log.Errorln(err)
return
}
for _, file := range files {
checkSnapshots(storage, file.Name(), int(maxSnapshotCount))
}
}
func checkSnapshots(storage IStorage, snapshotDir string, maxSnapshotCount int) {
re := regexp.MustCompile(`^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}_snap$`)
if !re.MatchString(snapshotDir) {
log.Warningf("snapshot_dir got unexcept file %s", snapshotDir)
return
}
diskId := snapshotDir[:len(snapshotDir)-len(options.HostOptions.SnapshotDirSuffix)]
snapshotPath := path.Join(storage.GetSnapshotDir(), snapshotDir)
// If disk is Deleted, request delete this disk all snapshots
if !fileutils2.Exists(path.Join(storage.GetPath(), diskId)) && fileutils2.Exists(snapshotPath) {
params := jsonutils.NewDict()
params.Set("disk_id", jsonutils.NewString(diskId))
_, err := modules.Snapshots.PerformClassAction(
hostutils.GetComputeSession(context.Background()),
"delete-disk-snapshots", params)
if err != nil {
log.Infof("Request delele disk %s snapshots failed %s", diskId, err)
}
return
}
snapshots, err := ioutil.ReadDir(snapshotPath)
if err != nil {
log.Errorln(err)
return
}
// if snapshot count greater than maxsnapshot count, do convert
if len(snapshots) >= maxSnapshotCount {
requestConvertSnapshot(snapshotPath, diskId)
}
}
func requestConvertSnapshot(snapshotPath, diskId string) {
log.Infof("SNPASHOT path %s", snapshotPath)
res, err := modules.Disks.GetSpecific(
hostutils.GetComputeSession(context.Background()), diskId, "convert-snapshot", nil)
if err != nil {
log.Errorln(err)
return
}
var (
deleteSnapshot, _ = res.GetString("delete_snapshot")
convertSnapshot, _ = res.GetString("convert_snapshot")
pendingDelete, _ = res.Bool("pending_delete")
)
log.Infof("start convert disk(%s) snapshot(%s), delete_snapshot is %s",
diskId, convertSnapshot, deleteSnapshot)
convertSnapshotPath := path.Join(snapshotPath, convertSnapshot)
outfile := convertSnapshotPath + ".tmp"
img, err := qemuimg.NewQemuImage(convertSnapshotPath)
if err != nil {
log.Errorln(err)
return
}
log.Infof("convertSnapshot path %s", convertSnapshotPath)
err = img.Convert2Qcow2To(outfile, true)
if err != nil {
log.Errorln(err)
return
}
requestDeleteSnapshot(
diskId, snapshotPath, deleteSnapshot, convertSnapshotPath, outfile, pendingDelete)
}
func requestDeleteSnapshot(
diskId, snapshotPath, deleteSnapshot, convertSnapshotPath,
outfile string, pendingDelete bool,
) {
deleteSnapshotPath := path.Join(snapshotPath, deleteSnapshot)
DELETEING_SNAPSHOTS.Store(diskId, true)
defer DELETEING_SNAPSHOTS.Delete(diskId)
_, err := modules.Snapshots.PerformAction(hostutils.GetComputeSession(context.Background()),
deleteSnapshot, "deleted", nil)
if err != nil {
log.Errorln(err)
return
}
if out, err := procutils.NewCommand("rm", "-f", convertSnapshotPath).Run(); err != nil {
log.Errorf("%s", out)
return
}
if out, err := procutils.NewCommand("mv", "-f", outfile, convertSnapshotPath).Run(); err != nil {
log.Errorf("%s", out)
return
}
if !pendingDelete {
if out, err := procutils.NewCommand("rm", "-f", deleteSnapshotPath).Run(); err != nil {
log.Errorf("%s", out)
return
}
}
}
+1
View File
@@ -48,5 +48,6 @@ func (s *SGPFSStorage) StorageType() string {
func NewGPFSStorage(manager *SStorageManager, path string) *SGPFSStorage {
ret := &SGPFSStorage{}
ret.SNasStorage = *NewNasStorage(manager, path, ret)
StartSnapshotRecycle(ret)
return ret
}
+11 -172
View File
@@ -17,10 +17,8 @@ package storageman
import (
"context"
"fmt"
"io/ioutil"
"os"
"path"
"regexp"
"time"
"yunion.io/x/jsonutils"
@@ -28,12 +26,11 @@ import (
"yunion.io/x/pkg/util/timeutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/cronman"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/hostman/storageman/remotefile"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/procutils"
@@ -41,10 +38,8 @@ import (
)
var (
_FUSE_MOUNT_PATH_ = "fusemnt"
_FUSE_TMP_PATH_ = "fusetmp"
_SNAPSHOT_PATH_ = "snapshots"
DELETEING_SNAPSHOTS = map[string]bool{}
_FUSE_MOUNT_PATH_ = "fusemnt"
_FUSE_TMP_PATH_ = "fusetmp"
)
type SLocalStorage struct {
@@ -229,38 +224,9 @@ func (s *SLocalStorage) SaveToGlance(ctx context.Context, params interface{}) (j
func (s *SLocalStorage) saveToGlance(ctx context.Context, imageId, imagePath string,
compress bool, format string) error {
var (
kvmDisk = NewKVMGuestDisk(imagePath)
osInfo string
relInfo *fsdriver.SReleaseInfo
)
if err := func() error {
defer kvmDisk.Disconnect()
if kvmDisk.Connect() {
var err error
func() {
if root := kvmDisk.MountKvmRootfs(); root != nil {
defer kvmDisk.UmountKvmRootfs(root)
osInfo = root.GetOs()
relInfo = root.GetReleaseInfo(root.GetPartition())
if compress {
err = root.PrepareFsForTemplate(root.GetPartition())
}
}
}()
if err != nil {
log.Errorln(err)
return err
}
if compress {
kvmDisk.Zerofree()
}
}
return nil
}(); err != nil {
ret, err := deployclient.GetDeployClient().SaveToGlance(context.Background(),
&deployapi.SaveToGlanceParams{DiskPath: imagePath, Compress: compress})
if err != nil {
return err
}
@@ -298,9 +264,10 @@ func (s *SLocalStorage) saveToGlance(ctx context.Context, imageId, imagePath str
size := finfo.Size()
var params = jsonutils.NewDict()
if len(osInfo) > 0 {
params.Set("os_type", jsonutils.NewString(osInfo))
if len(ret.OsInfo) > 0 {
params.Set("os_type", jsonutils.NewString(ret.OsInfo))
}
relInfo := ret.ReleaseInfo
if relInfo != nil {
params.Set("os_distribution", jsonutils.NewString(relInfo.Distro))
if len(relInfo.Version) > 0 {
@@ -317,8 +284,6 @@ func (s *SLocalStorage) saveToGlance(ctx context.Context, imageId, imagePath str
_, err = modules.Images.Upload(hostutils.GetImageSession(ctx, s.GetZone()),
params, f, size)
// TODO
// notify_template_ready
return err
}
@@ -357,132 +322,6 @@ func (s *SLocalStorage) DeleteSnapshots(ctx context.Context, params interface{})
return nil, nil
}
/*************************Background delete snapshot job****************************/
func (s *SLocalStorage) StartSnapshotRecycle() {
log.Infof("Snapshot recyle job started")
if !fileutils2.Exists(s.GetSnapshotDir()) {
procutils.NewCommand("mkdir", "-p", s.GetSnapshotDir()).Run()
}
cronman.GetCronJobManager(false).AddJob2("SnapshotRecycle", options.HostOptions.SnapshotRecycleDay, 2, 0, 0, s.snapshotRecycle, true)
}
func (s *SLocalStorage) snapshotRecycle(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
res, err := modules.Snapshots.GetById(hostutils.GetComputeSession(ctx), "max-count", nil)
if err != nil {
log.Errorln(err)
return
}
maxSnapshotCount, err := res.Int("max_count")
if err != nil {
log.Errorln("Request region get snapshot max count failed")
return
}
files, err := ioutil.ReadDir(s.GetSnapshotDir())
if err != nil {
log.Errorln(err)
return
}
for _, file := range files {
s.checkSnapshots(file.Name(), int(maxSnapshotCount))
}
}
func (s *SLocalStorage) checkSnapshots(snapshotDir string, maxSnapshotCount int) {
re := regexp.MustCompile(`^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}_snap$`)
if !re.MatchString(snapshotDir) {
log.Warningf("snapshot_dir got unexcept file %s", snapshotDir)
return
}
diskId := snapshotDir[:len(snapshotDir)-len(options.HostOptions.SnapshotDirSuffix)]
snapshotPath := path.Join(s.GetSnapshotDir(), snapshotDir)
// If disk is Deleted, request delete this disk all snapshots
if !fileutils2.Exists(path.Join(s.Path, diskId)) && fileutils2.Exists(snapshotPath) {
params := jsonutils.NewDict()
params.Set("disk_id", jsonutils.NewString(diskId))
_, err := modules.Snapshots.PerformClassAction(
hostutils.GetComputeSession(context.Background()),
"delete-disk-snapshots", params)
if err != nil {
log.Infof("Request delele disk %s snapshots failed %s", diskId, err)
}
return
}
snapshots, err := ioutil.ReadDir(snapshotPath)
if err != nil {
log.Errorln(err)
return
}
// if snapshot count greater than maxsnapshot count, do convert
if len(snapshots) >= maxSnapshotCount {
s.requestConvertSnapshot(snapshotPath, diskId)
}
}
func (s *SLocalStorage) requestConvertSnapshot(snapshotPath, diskId string) {
res, err := modules.Disks.GetSpecific(
hostutils.GetComputeSession(context.Background()), diskId, "convert-snapshot", nil)
if err != nil {
log.Errorln(err)
return
}
var (
deleteSnapshot, _ = res.GetString("delete_snapshot")
convertSnapshot, _ = res.GetString("convert_snapshot")
pendingDelete, _ = res.Bool("pending_delete")
)
log.Infof("start convert disk(%s) snapshot(%s), delete_snapshot is %s",
diskId, convertSnapshot, deleteSnapshot)
convertSnapshotPath := path.Join(snapshotPath, convertSnapshot)
outfile := convertSnapshotPath + ".tmp"
img, err := qemuimg.NewQemuImage(convertSnapshot)
if err != nil {
log.Errorln(err)
return
}
err = img.Convert2Qcow2To(outfile, true)
if err != nil {
log.Errorln(err)
return
}
s.requestDeleteSnapshot(
diskId, snapshotPath, deleteSnapshot, convertSnapshotPath, outfile, pendingDelete)
}
func (s *SLocalStorage) requestDeleteSnapshot(
diskId, snapshotPath, deleteSnapshot, convertSnapshotPath,
outfile string, pendingDelete bool,
) {
deleteSnapshotPath := path.Join(snapshotPath, deleteSnapshot)
DELETEING_SNAPSHOTS[diskId] = true
defer delete(DELETEING_SNAPSHOTS, diskId)
_, err := modules.Snapshots.PerformAction(hostutils.GetComputeSession(context.Background()),
deleteSnapshot, "deleted", nil)
if err != nil {
log.Errorln(err)
return
}
if out, err := procutils.NewCommand("rm", "-f", convertSnapshotPath).Run(); err != nil {
log.Errorf("%s", out)
return
}
if out, err := procutils.NewCommand("mv", "-f", outfile, convertSnapshotPath).Run(); err != nil {
log.Errorf("%s", out)
return
}
if !pendingDelete {
if out, err := procutils.NewCommand("rm", "-f", deleteSnapshotPath).Run(); err != nil {
log.Errorf("%s", out)
return
}
}
}
func (s *SLocalStorage) DestinationPrepareMigrate(ctx context.Context, liveMigrate bool, disksUri string, snapshotsUri string, desc, disksBackingFile, srcSnapshots jsonutils.JSONObject) error {
disks, _ := desc.GetArray("disks")
for i, diskinfo := range disks {
@@ -529,7 +368,7 @@ func (s *SLocalStorage) DestinationPrepareMigrate(ctx context.Context, liveMigra
} else {
// download disk form remote url
diskUrl := fmt.Sprintf("%s/%s/%s", disksUri, diskStorageId, diskId)
if err := disk.CreateFromUrl(ctx, diskUrl); err != nil {
if err := disk.CreateFromUrl(ctx, diskUrl, 0); err != nil {
log.Errorln(err)
return err
}
+11 -1
View File
@@ -17,6 +17,7 @@ package storageman
import (
"context"
"fmt"
"path"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -37,7 +38,16 @@ type SNasStorage struct {
}
func NewNasStorage(manager *SStorageManager, path string, ins INasStorage) *SNasStorage {
return &SNasStorage{*NewLocalStorage(manager, path, 0), ins}
ret := &SNasStorage{*NewLocalStorage(manager, path, 0), ins}
return ret
}
func (s *SNasStorage) GetComposedName() string {
return fmt.Sprintf("host_%s_%s_storage_%d", s.Manager.host.GetMasterIp(), s.ins.StorageType(), s.Index)
}
func (s *SNasStorage) GetSnapshotDir() string {
return path.Join(s.Path, s.GetComposedName(), _SNAPSHOT_PATH_)
}
func (s *SNasStorage) CreateDisk(diskId string) IDisk {
+3 -2
View File
@@ -45,15 +45,16 @@ func (factory *SNFSStorageFactory) StorageType() string {
}
type SNFSStorage struct {
SLocalStorage
SNasStorage
}
func NewNFSStorage(manager *SStorageManager, path string) *SNFSStorage {
ret := &SNFSStorage{}
ret.SLocalStorage = *NewLocalStorage(manager, path, 0)
ret.SNasStorage = *NewNasStorage(manager, path, ret)
if !fileutils2.Exists(path) {
procutils.NewCommand("mkdir", "-p", path).Run()
}
StartSnapshotRecycle(ret)
return ret
}
+10 -36
View File
@@ -31,7 +31,8 @@ import (
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/mcclient/modules"
@@ -476,34 +477,9 @@ func (s *SRbdStorage) onSaveToGlanceFailed(ctx context.Context, imageId string)
}
func (s *SRbdStorage) saveToGlance(ctx context.Context, imageId, imagePath string, compress bool, format string) error {
var (
kvmDisk = NewKVMGuestDisk(imagePath)
osInfo string
relInfo *fsdriver.SReleaseInfo
)
if err := func() error {
defer kvmDisk.Disconnect()
if kvmDisk.Connect() {
if root := kvmDisk.MountKvmRootfs(); root != nil {
defer kvmDisk.UmountKvmRootfs(root)
osInfo = root.GetOs()
relInfo = root.GetReleaseInfo(root.GetPartition())
if compress {
if err := root.PrepareFsForTemplate(root.GetPartition()); err != nil {
log.Errorln(err)
return err
}
}
}
if compress {
kvmDisk.Zerofree()
}
}
return nil
}(); err != nil {
ret, err := deployclient.GetDeployClient().SaveToGlance(context.Background(),
&deployapi.SaveToGlanceParams{DiskPath: imagePath, Compress: compress})
if err != nil {
return err
}
@@ -512,7 +488,7 @@ func (s *SRbdStorage) saveToGlance(ctx context.Context, imageId, imagePath strin
format = options.HostOptions.DefaultImageSaveFormat
}
_, err := procutils.NewCommand(qemutils.GetQemuImg(), "convert", "-f", "raw", "-O", format, imagePath, tmpImageFile).Run()
_, err = procutils.NewCommand(qemutils.GetQemuImg(), "convert", "-f", "raw", "-O", format, imagePath, tmpImageFile).Run()
if err != nil {
return err
}
@@ -521,8 +497,8 @@ func (s *SRbdStorage) saveToGlance(ctx context.Context, imageId, imagePath strin
if err != nil {
return err
}
defer os.Remove(tmpImageFile)
defer f.Close()
finfo, err := f.Stat()
if err != nil {
@@ -531,9 +507,10 @@ func (s *SRbdStorage) saveToGlance(ctx context.Context, imageId, imagePath strin
size := finfo.Size()
var params = jsonutils.NewDict()
if len(osInfo) > 0 {
params.Set("os_type", jsonutils.NewString(osInfo))
if len(ret.OsInfo) > 0 {
params.Set("os_type", jsonutils.NewString(ret.OsInfo))
}
relInfo := ret.ReleaseInfo
if relInfo != nil {
params.Set("os_distribution", jsonutils.NewString(relInfo.Distro))
if len(relInfo.Version) > 0 {
@@ -550,9 +527,6 @@ func (s *SRbdStorage) saveToGlance(ctx context.Context, imageId, imagePath strin
_, err = modules.Images.Upload(hostutils.GetImageSession(ctx, s.GetZone()),
params, f, size)
f.Close()
// TODO
// notify_template_ready
return err
}
@@ -0,0 +1 @@
package storagehandler // import "yunion.io/x/onecloud/pkg/hostman/storageman/storagehandler"
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package storageman
package storagehandler
import (
"context"
@@ -24,6 +24,7 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
@@ -76,7 +77,7 @@ func storageAttach(ctx context.Context, body jsonutils.JSONObject) (interface{},
}
storageType, _ := body.GetString("storage_type")
storage := storageManager.NewSharedStorageInstance(mountPoint, storageType)
storage := storageman.GetManager().NewSharedStorageInstance(mountPoint, storageType)
if storage == nil {
return nil, httperrors.NewBadRequestError("'Not Support Storage[%s] mount_point: %s", storageType, mountPoint)
}
@@ -92,8 +93,8 @@ func storageAttach(ctx context.Context, body jsonutils.JSONObject) (interface{},
if err != nil {
return nil, err
}
storageManager.InitSharedStorageImageCache(storageType, storagecacheId, imagecachePath, storage)
storageManager.Storages = append(storageManager.Storages, storage)
storageman.GetManager().InitSharedStorageImageCache(storageType, storagecacheId, imagecachePath, storage)
storageman.GetManager().Storages = append(storageman.GetManager().Storages, storage)
return resp, nil
}
@@ -102,13 +103,13 @@ func storageDetach(ctx context.Context, body jsonutils.JSONObject) (interface{},
if err != nil {
return nil, httperrors.NewMissingParameterError("mount_point")
}
storage := storageManager.GetStorageByPath(mountPoint)
storage := storageman.GetManager().GetStorageByPath(mountPoint)
name, _ := body.GetString("name")
if storage == nil {
return nil, httperrors.NewBadRequestError("ShareStorage[%s] Has detach from host ...", name)
}
storageManager.Remove(storage)
storageman.GetManager().Remove(storage)
return nil, nil
}
@@ -121,11 +122,11 @@ func storageUpdate(ctx context.Context, body jsonutils.JSONObject) (interface{},
if err != nil {
return nil, httperrors.NewMissingParameterError("storage_conf")
}
storage := storageManager.GetStorage(storageId)
storage := storageman.GetManager().GetStorage(storageId)
params := jsonutils.NewDict()
params.Set("details", jsonutils.JSONTrue)
ret, err := modules.Hoststorages.Get(hostutils.GetComputeSession(context.Background()),
storageManager.GetHostId(), storageId, params)
storageman.GetManager().GetHostId(), storageId, params)
if err != nil {
log.Errorln(err)
return nil, err
@@ -143,7 +144,7 @@ func storageUpdate(ctx context.Context, body jsonutils.JSONObject) (interface{},
func storageDeleteSnapshots(ctx context.Context, w http.ResponseWriter, r *http.Request) {
params, _, body := appsrv.FetchEnv(ctx, w, r)
var storageId = params["<storageId>"]
storage := storageManager.GetStorage(storageId)
storage := storageman.GetManager().GetStorage(storageId)
if storage == nil {
hostutils.Response(ctx, w, httperrors.NewNotFoundError("Stroage Not found"))
return
@@ -0,0 +1,17 @@
package system_service
type SHostDeployer struct {
*SBaseSystemService
}
func NewHostDeployerService() *SHostDeployer {
return &SHostDeployer{NewBaseSystemService("yunion-host-deployer", nil)}
}
func (s *SHostDeployer) Reload(kwargs map[string]interface{}) error {
return s.reload(s.GetConfig(kwargs), s.GetConfigFile())
}
func (s *SHostDeployer) BgReload(kwargs map[string]interface{}) {
go s.reload(s.GetConfig(kwargs), s.GetConfigFile())
}
@@ -45,6 +45,7 @@ var serviceMap = map[string]ISystemService{
"kube_agent": NewKubeAgentService(),
"lxcfs": NewLxcfsService(),
"docker": NewDockerService(),
"host-deployer": NewHostDeployerService(),
}
func GetService(name string) ISystemService {
+2 -1
View File
@@ -38,7 +38,8 @@ type SImageOptions struct {
TargetImageFormats []string `help:"target image formats that the system will automatically convert to" default:"qcow2,vmdk,vhd"`
TorrentClientPath string `help:"path to torrent executable" default:"/opt/yunion/bin/torrent"`
TorrentClientPath string `help:"path to torrent executable" default:"/opt/yunion/bin/torrent"`
DeployServerSocketPath string `help:"Deploy server listen socket path"`
}
var (
+4 -2
View File
@@ -28,7 +28,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/cronman"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/hostman/storageman/nbd"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
"yunion.io/x/onecloud/pkg/image/models"
"yunion.io/x/onecloud/pkg/image/options"
_ "yunion.io/x/onecloud/pkg/image/tasks"
@@ -104,7 +104,9 @@ func StartService() {
go models.CheckImages()
nbd.Init() // init nbd module for image probe
if len(options.Options.DeployServerSocketPath) > 0 {
deployclient.Init(options.Options.DeployServerSocketPath)
}
if !opts.IsSlaveNode {
cron := cronman.GetCronJobManager(true)
+13 -32
View File
@@ -25,8 +25,8 @@ import (
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"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
"yunion.io/x/onecloud/pkg/image/models"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/logclient"
@@ -48,6 +48,7 @@ func (self *ImageProbeTask) OnInit(ctx context.Context, obj db.IStandaloneModel,
func (self *ImageProbeTask) StartImageProbe(ctx context.Context, image *models.SImage) {
probeErr := self.doProbe(ctx, image)
// save chksum first
// 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,
@@ -65,20 +66,13 @@ func (self *ImageProbeTask) StartImageProbe(ctx context.Context, image *models.S
func (self *ImageProbeTask) doProbe(ctx context.Context, image *models.SImage) error {
diskPath := image.GetPath("")
kvmDisk := storageman.NewKVMGuestDisk(diskPath)
defer kvmDisk.DisconnectWithoutLvm()
if !kvmDisk.ConnectWithoutDetectLvm() {
return fmt.Errorf("Disk connector failed to connect image")
if deployclient.GetDeployClient() == nil {
return fmt.Errorf("deploy client not init")
}
// Fsck is executed during mount
rootfs := kvmDisk.MountKvmRootfs()
if rootfs == nil {
return fmt.Errorf("Failed mounting rootfs for kvm disk")
imageInfo, err := deployclient.GetDeployClient().ProbeImageInfo(ctx, &deployapi.ProbeImageInfoPramas{DiskPath: diskPath})
if err != nil {
return err
}
defer kvmDisk.UmountKvmRootfs(rootfs)
imageInfo := self.getImageInfo(kvmDisk, rootfs)
self.updateImageInfo(ctx, image, imageInfo)
return nil
}
@@ -120,15 +114,15 @@ func (self *ImageProbeTask) updateImageMetadata(
return nil
}
func (self *ImageProbeTask) updateImageInfo(ctx context.Context, image *models.SImage, imageInfo *sImageInfo) {
imageProperties := jsonutils.Marshal(imageInfo.osInfo).(*jsonutils.JSONDict)
func (self *ImageProbeTask) updateImageInfo(ctx context.Context, image *models.SImage, imageInfo *deployapi.ImageInfo) {
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 {
if imageInfo.IsUefiSupport {
imageProperties.Set(api.IMAGE_UEFI_SUPPORT, jsonutils.JSONTrue)
}
if imageInfo.IsLVMPartition {
if imageInfo.IsLvmPartition {
imageProperties.Set(api.IMAGE_IS_LVM_PARTITION, jsonutils.JSONTrue)
}
if imageInfo.IsReadonly {
@@ -145,7 +139,7 @@ func (self *ImageProbeTask) updateImageInfo(ctx context.Context, image *models.S
}
type sImageInfo struct {
osInfo *fsdriver.SReleaseInfo
osInfo *deployapi.ReleaseInfo
OsType string
IsUEFISupport bool
@@ -155,19 +149,6 @@ type sImageInfo struct {
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: %s", image.Name, reason)
db.OpsLog.LogEvent(image, db.ACT_PROBE_FAIL, reason, self.UserCred)
+25 -2
View File
@@ -30,6 +30,7 @@ import (
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/regutils2"
)
@@ -78,6 +79,28 @@ func GetPrivatePrefixes(privatePrefixes []string) []string {
}
}
func GetMainNicFromDeployApi(nics []*deployapi.Nic) (*deployapi.Nic, error) {
var mainIp netutils.IPV4Addr
var mainNic *deployapi.Nic
for _, n := range nics {
if len(n.Gateway) > 0 {
ip := n.Ip
ipInt, err := netutils.NewIPV4Addr(ip)
if err != nil {
return nil, err
}
if mainIp == 0 {
mainIp = ipInt
mainNic = n
} else if !netutils.IsPrivate(ipInt) && netutils.IsPrivate(mainIp) {
mainIp = ipInt
mainNic = n
}
}
}
return mainNic, nil
}
func GetMainNic(nics []jsonutils.JSONObject) (jsonutils.JSONObject, error) {
var mainIp netutils.IPV4Addr
var mainNic jsonutils.JSONObject
@@ -136,9 +159,9 @@ func addRoute(routes *[][]string, net, gw string) {
*routes = append(*routes, []string{net, gw})
}
func extendRoutes(routes *[][]string, nicRoutes []types.SRoute) error {
func extendRoutes(routes *[][]string, nicRoutes []*deployapi.Routes) error {
for i := 0; i < len(nicRoutes); i++ {
addRoute(routes, nicRoutes[i][0], nicRoutes[i][1])
addRoute(routes, nicRoutes[i].Route[0], nicRoutes[i].Route[1])
}
return nil
}
+19
View File
@@ -15,6 +15,7 @@
package sysutils
import (
"io/ioutil"
"os"
"path"
"regexp"
@@ -191,3 +192,21 @@ func IsKernelModuleLoaded(name string) bool {
}
return false
}
func SetSysConfig(cpath, val string) bool {
if fileutils2.Exists(cpath) {
oval, err := ioutil.ReadFile(cpath)
if err != nil {
log.Errorln(err)
return false
}
if string(oval) != val {
err = fileutils2.FilePutContents(cpath, val, false)
if err == nil {
return true
}
log.Errorln(err)
}
}
return false
}
-1
View File
@@ -186,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) {
if b&0x80 == 0 {
goto done
}
// x -= 0x80 << 63 // Always zero.
return 0, errOverflow
+63
View File
@@ -0,0 +1,63 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2018 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import "errors"
// Deprecated: do not use.
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
// Deprecated: do not use.
func GetStats() Stats { return Stats{} }
// Deprecated: do not use.
func MarshalMessageSet(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: do not use.
func UnmarshalMessageSet([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: do not use.
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: do not use.
func UnmarshalMessageSetJSON([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: do not use.
func RegisterMessageSetType(Message, int32, string) {}
+2 -1
View File
@@ -246,7 +246,8 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
return false
}
m1, m2 := e1.value, e2.value
m1 := extensionAsLegacyType(e1.value)
m2 := extensionAsLegacyType(e2.value)
if m1 == nil && m2 == nil {
// Both have only encoded form.
+71 -7
View File
@@ -185,9 +185,25 @@ type Extension struct {
// extension will have only enc set. When such an extension is
// accessed using GetExtension (or GetExtensions) desc and value
// will be set.
desc *ExtensionDesc
desc *ExtensionDesc
// value is a concrete value for the extension field. Let the type of
// desc.ExtensionType be the "API type" and the type of Extension.value
// be the "storage type". The API type and storage type are the same except:
// * For scalars (except []byte), the API type uses *T,
// while the storage type uses T.
// * For repeated fields, the API type uses []T, while the storage type
// uses *[]T.
//
// The reason for the divergence is so that the storage type more naturally
// matches what is expected of when retrieving the values through the
// protobuf reflection APIs.
//
// The value may only be populated if desc is also populated.
value interface{}
enc []byte
// enc is the raw bytes for the extension field.
enc []byte
}
// SetRawExtension is for testing only.
@@ -334,7 +350,7 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// descriptors with the same field number.
return nil, errors.New("proto: descriptor conflict")
}
return e.value, nil
return extensionAsLegacyType(e.value), nil
}
if extension.ExtensionType == nil {
@@ -349,11 +365,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// Remember the decoded version and drop the encoded version.
// That way it is safe to mutate what we return.
e.value = v
e.value = extensionAsStorageType(v)
e.desc = extension
e.enc = nil
emap[extension.Field] = e
return e.value, nil
return extensionAsLegacyType(e.value), nil
}
// defaultExtensionValue returns the default value for extension.
@@ -488,7 +504,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
}
typ := reflect.TypeOf(extension.ExtensionType)
if typ != reflect.TypeOf(value) {
return errors.New("proto: bad extension value type")
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType)
}
// nil extension values need to be caught early, because the
// encoder can't distinguish an ErrNil due to a nil extension
@@ -500,7 +516,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
}
extmap := epb.extensionsWrite()
extmap[extension.Field] = Extension{desc: extension, value: value}
extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)}
return nil
}
@@ -541,3 +557,51 @@ func RegisterExtension(desc *ExtensionDesc) {
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
return extensionMaps[reflect.TypeOf(pb).Elem()]
}
// extensionAsLegacyType converts an value in the storage type as the API type.
// See Extension.value.
func extensionAsLegacyType(v interface{}) interface{} {
switch rv := reflect.ValueOf(v); rv.Kind() {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
// Represent primitive types as a pointer to the value.
rv2 := reflect.New(rv.Type())
rv2.Elem().Set(rv)
v = rv2.Interface()
case reflect.Ptr:
// Represent slice types as the value itself.
switch rv.Type().Elem().Kind() {
case reflect.Slice:
if rv.IsNil() {
v = reflect.Zero(rv.Type().Elem()).Interface()
} else {
v = rv.Elem().Interface()
}
}
}
return v
}
// extensionAsStorageType converts an value in the API type as the storage type.
// See Extension.value.
func extensionAsStorageType(v interface{}) interface{} {
switch rv := reflect.ValueOf(v); rv.Kind() {
case reflect.Ptr:
// Represent slice types as the value itself.
switch rv.Type().Elem().Kind() {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
if rv.IsNil() {
v = reflect.Zero(rv.Type().Elem()).Interface()
} else {
v = rv.Elem().Interface()
}
}
case reflect.Slice:
// Represent slice types as a pointer to the value.
if rv.Type().Elem().Kind() != reflect.Uint8 {
rv2 := reflect.New(rv.Type())
rv2.Elem().Set(rv)
v = rv2.Interface()
}
}
return v
}
+12 -26
View File
@@ -341,26 +341,6 @@ type Message interface {
ProtoMessage()
}
// Stats records allocation details about the protocol buffer encoders
// and decoders. Useful for tuning the library itself.
type Stats struct {
Emalloc uint64 // mallocs in encode
Dmalloc uint64 // mallocs in decode
Encode uint64 // number of encodes
Decode uint64 // number of decodes
Chit uint64 // number of cache hits
Cmiss uint64 // number of cache misses
Size uint64 // number of sizes
}
// Set to true to enable stats collection.
const collectStats = false
var stats Stats
// GetStats returns a copy of the global Stats structure.
func GetStats() Stats { return stats }
// A Buffer is a buffer manager for marshaling and unmarshaling
// protocol buffers. It may be reused between invocations to
// reduce memory usage. It is not necessary to use a Buffer;
@@ -960,13 +940,19 @@ func isProto3Zero(v reflect.Value) bool {
return false
}
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
const ProtoPackageIsVersion2 = true
const (
// ProtoPackageIsVersion3 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
ProtoPackageIsVersion3 = true
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
const ProtoPackageIsVersion1 = true
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
ProtoPackageIsVersion2 = true
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package.
ProtoPackageIsVersion1 = true
)
// InternalMessageInfo is a type used internally by generated .pb.go files.
// This type is not intended to be used by non-generated code.
+2 -135
View File
@@ -36,13 +36,7 @@ package proto
*/
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"reflect"
"sort"
"sync"
)
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
@@ -145,46 +139,9 @@ func skipVarint(buf []byte) []byte {
return buf[i+1:]
}
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
func MarshalMessageSet(exts interface{}) ([]byte, error) {
return marshalMessageSet(exts, false)
}
// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
switch exts := exts.(type) {
case *XXX_InternalExtensions:
var u marshalInfo
siz := u.sizeMessageSet(exts)
b := make([]byte, 0, siz)
return u.appendMessageSet(b, exts, deterministic)
case map[int32]Extension:
// This is an old-style extension map.
// Wrap it in a new-style XXX_InternalExtensions.
ie := XXX_InternalExtensions{
p: &struct {
mu sync.Mutex
extensionMap map[int32]Extension
}{
extensionMap: exts,
},
}
var u marshalInfo
siz := u.sizeMessageSet(&ie)
b := make([]byte, 0, siz)
return u.appendMessageSet(b, &ie, deterministic)
default:
return nil, errors.New("proto: not an extension map")
}
}
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
func UnmarshalMessageSet(buf []byte, exts interface{}) error {
func unmarshalMessageSet(buf []byte, exts interface{}) error {
var m map[int32]Extension
switch exts := exts.(type) {
case *XXX_InternalExtensions:
@@ -222,93 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error {
}
return nil
}
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
var m map[int32]Extension
switch exts := exts.(type) {
case *XXX_InternalExtensions:
var mu sync.Locker
m, mu = exts.extensionsRead()
if m != nil {
// Keep the extensions map locked until we're done marshaling to prevent
// races between marshaling and unmarshaling the lazily-{en,de}coded
// values.
mu.Lock()
defer mu.Unlock()
}
case map[int32]Extension:
m = exts
default:
return nil, errors.New("proto: not an extension map")
}
var b bytes.Buffer
b.WriteByte('{')
// Process the map in key order for deterministic output.
ids := make([]int32, 0, len(m))
for id := range m {
ids = append(ids, id)
}
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
for i, id := range ids {
ext := m[id]
msd, ok := messageSetMap[id]
if !ok {
// Unknown type; we can't render it, so skip it.
continue
}
if i > 0 && b.Len() > 1 {
b.WriteByte(',')
}
fmt.Fprintf(&b, `"[%s]":`, msd.name)
x := ext.value
if x == nil {
x = reflect.New(msd.t.Elem()).Interface()
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
return nil, err
}
}
d, err := json.Marshal(x)
if err != nil {
return nil, err
}
b.Write(d)
}
b.WriteByte('}')
return b.Bytes(), nil
}
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
// Common-case fast path.
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
return nil
}
// This is fairly tricky, and it's not clear that it is needed.
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
}
// A global registry of types that can be used in a MessageSet.
var messageSetMap = make(map[int32]messageSetDesc)
type messageSetDesc struct {
t reflect.Type // pointer to struct
name string
}
// RegisterMessageSetType is called from the generated code.
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
messageSetMap[fieldNum] = messageSetDesc{
t: reflect.TypeOf(m),
name: name,
}
}
+4 -1
View File
@@ -79,10 +79,13 @@ func toPointer(i *Message) pointer {
// toAddrPointer converts an interface to a pointer that points to
// the interface data.
func toAddrPointer(i *interface{}, isptr bool) pointer {
func toAddrPointer(i *interface{}, isptr, deref bool) pointer {
v := reflect.ValueOf(*i)
u := reflect.New(v.Type())
u.Elem().Set(v)
if deref {
u = u.Elem()
}
return pointer{v: u}
}
+10 -5
View File
@@ -85,16 +85,21 @@ func toPointer(i *Message) pointer {
// toAddrPointer converts an interface to a pointer that points to
// the interface data.
func toAddrPointer(i *interface{}, isptr bool) pointer {
func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) {
// Super-tricky - read or get the address of data word of interface value.
if isptr {
// The interface is of pointer type, thus it is a direct interface.
// The data word is the pointer data itself. We take its address.
return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
} else {
// The interface is not of pointer type. The data word is the pointer
// to the data.
p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
}
// The interface is not of pointer type. The data word is the pointer
// to the data.
return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
if deref {
p.p = *(*unsafe.Pointer)(p.p)
}
return p
}
// valToPointer converts v to a pointer. v must be of pointer type.
+16 -15
View File
@@ -334,9 +334,6 @@ func GetProperties(t reflect.Type) *StructProperties {
sprop, ok := propertiesMap[t]
propertiesMu.RUnlock()
if ok {
if collectStats {
stats.Chit++
}
return sprop
}
@@ -346,17 +343,20 @@ func GetProperties(t reflect.Type) *StructProperties {
return sprop
}
type (
oneofFuncsIface interface {
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
}
oneofWrappersIface interface {
XXX_OneofWrappers() []interface{}
}
)
// getPropertiesLocked requires that propertiesMu is held.
func getPropertiesLocked(t reflect.Type) *StructProperties {
if prop, ok := propertiesMap[t]; ok {
if collectStats {
stats.Chit++
}
return prop
}
if collectStats {
stats.Cmiss++
}
prop := new(StructProperties)
// in case of recursive protos, fill this in now.
@@ -391,13 +391,14 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
// Re-order prop.order.
sort.Sort(prop)
type oneofMessage interface {
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
var oots []interface{}
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
case oneofFuncsIface:
_, _, _, oots = m.XXX_OneofFuncs()
case oneofWrappersIface:
oots = m.XXX_OneofWrappers()
}
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
var oots []interface{}
_, _, _, oots = om.XXX_OneofFuncs()
if len(oots) > 0 {
// Interpret oneof metadata.
prop.OneofTypes = make(map[string]*OneofProperties)
for _, oot := range oots {
+27 -18
View File
@@ -87,6 +87,7 @@ type marshalElemInfo struct {
sizer sizer
marshaler marshaler
isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only)
deref bool // dereference the pointer before operating on it; implies isptr
}
var (
@@ -320,8 +321,11 @@ func (u *marshalInfo) computeMarshalInfo() {
// get oneof implementers
var oneofImplementers []interface{}
if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
case oneofFuncsIface:
_, _, _, oneofImplementers = m.XXX_OneofFuncs()
case oneofWrappersIface:
oneofImplementers = m.XXX_OneofWrappers()
}
n := t.NumField()
@@ -407,13 +411,22 @@ func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo {
panic("tag is not an integer")
}
wt := wiretype(tags[0])
if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct {
t = t.Elem()
}
sizer, marshaler := typeMarshaler(t, tags, false, false)
var deref bool
if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
t = reflect.PtrTo(t)
deref = true
}
e = &marshalElemInfo{
wiretag: uint64(tag)<<3 | wt,
tagsize: SizeVarint(uint64(tag) << 3),
sizer: sizer,
marshaler: marshaler,
isptr: t.Kind() == reflect.Ptr,
deref: deref,
}
// update cache
@@ -448,7 +461,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) {
func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
fi.field = toField(f)
fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
fi.isPointer = true
fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
@@ -476,10 +489,6 @@ func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofI
}
}
type oneofMessage interface {
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
}
// wiretype returns the wire encoding of the type.
func wiretype(encoding string) uint64 {
switch encoding {
@@ -2310,8 +2319,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
for _, k := range m.MapKeys() {
ki := k.Interface()
vi := m.MapIndex(k).Interface()
kaddr := toAddrPointer(&ki, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
kaddr := toAddrPointer(&ki, false, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
n += siz + SizeVarint(uint64(siz)) + tagsize
}
@@ -2329,8 +2338,8 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
for _, k := range keys {
ki := k.Interface()
vi := m.MapIndex(k).Interface()
kaddr := toAddrPointer(&ki, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
kaddr := toAddrPointer(&ki, false, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value
b = appendVarint(b, tag)
siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
b = appendVarint(b, uint64(siz))
@@ -2399,7 +2408,7 @@ func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int {
// the last time this function was called.
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
n += ei.sizer(p, ei.tagsize)
}
mu.Unlock()
@@ -2434,7 +2443,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if !nerr.Merge(err) {
return b, err
@@ -2465,7 +2474,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if !nerr.Merge(err) {
return b, err
@@ -2510,7 +2519,7 @@ func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int {
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
n += ei.sizer(p, 1) // message, tag = 3 (size=1)
}
mu.Unlock()
@@ -2553,7 +2562,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
if !nerr.Merge(err) {
return b, err
@@ -2591,7 +2600,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
b = append(b, 1<<3|WireEndGroup)
if !nerr.Merge(err) {
@@ -2621,7 +2630,7 @@ func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int {
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
n += ei.sizer(p, ei.tagsize)
}
return n
@@ -2656,7 +2665,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
ei := u.getExtElemInfo(e.desc)
v := e.value
p := toAddrPointer(&v, ei.isptr)
p := toAddrPointer(&v, ei.isptr, ei.deref)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if !nerr.Merge(err) {
return b, err
+38 -36
View File
@@ -136,7 +136,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
u.computeUnmarshalInfo()
}
if u.isMessageSet {
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
}
var reqMask uint64 // bitmask of required fields we've seen.
var errLater error
@@ -362,46 +362,48 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
}
// Find any types associated with oneof fields.
// TODO: XXX_OneofFuncs returns more info than we need. Get rid of some of it?
fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("XXX_OneofFuncs")
if fn.IsValid() {
res := fn.Call(nil)[3] // last return value from XXX_OneofFuncs: []interface{}
for i := res.Len() - 1; i >= 0; i-- {
v := res.Index(i) // interface{}
tptr := reflect.ValueOf(v.Interface()).Type() // *Msg_X
typ := tptr.Elem() // Msg_X
var oneofImplementers []interface{}
switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) {
case oneofFuncsIface:
_, _, _, oneofImplementers = m.XXX_OneofFuncs()
case oneofWrappersIface:
oneofImplementers = m.XXX_OneofWrappers()
}
for _, v := range oneofImplementers {
tptr := reflect.TypeOf(v) // *Msg_X
typ := tptr.Elem() // Msg_X
f := typ.Field(0) // oneof implementers have one field
baseUnmarshal := fieldUnmarshaler(&f)
tags := strings.Split(f.Tag.Get("protobuf"), ",")
fieldNum, err := strconv.Atoi(tags[1])
if err != nil {
panic("protobuf tag field not an integer: " + tags[1])
}
var name string
for _, tag := range tags {
if strings.HasPrefix(tag, "name=") {
name = strings.TrimPrefix(tag, "name=")
break
}
}
// Find the oneof field that this struct implements.
// Might take O(n^2) to process all of the oneofs, but who cares.
for _, of := range oneofFields {
if tptr.Implements(of.ityp) {
// We have found the corresponding interface for this struct.
// That lets us know where this struct should be stored
// when we encounter it during unmarshaling.
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
u.setTag(fieldNum, of.field, unmarshal, 0, name)
}
f := typ.Field(0) // oneof implementers have one field
baseUnmarshal := fieldUnmarshaler(&f)
tags := strings.Split(f.Tag.Get("protobuf"), ",")
fieldNum, err := strconv.Atoi(tags[1])
if err != nil {
panic("protobuf tag field not an integer: " + tags[1])
}
var name string
for _, tag := range tags {
if strings.HasPrefix(tag, "name=") {
name = strings.TrimPrefix(tag, "name=")
break
}
}
// Find the oneof field that this struct implements.
// Might take O(n^2) to process all of the oneofs, but who cares.
for _, of := range oneofFields {
if tptr.Implements(of.ityp) {
// We have found the corresponding interface for this struct.
// That lets us know where this struct should be stored
// when we encounter it during unmarshaling.
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
u.setTag(fieldNum, of.field, unmarshal, 0, name)
}
}
}
// Get extension ranges, if any.
fn = reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray")
fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray")
if fn.IsValid() {
if !u.extensions.IsValid() && !u.oldExtensions.IsValid() {
panic("a message with extensions, but no extensions field in " + t.Name())
@@ -1948,7 +1950,7 @@ func encodeVarint(b []byte, x uint64) []byte {
// If there is an error, it returns 0,0.
func decodeVarint(b []byte) (uint64, int) {
var x, y uint64
if len(b) <= 0 {
if len(b) == 0 {
goto bad
}
x = uint64(b[0])
+27 -18
View File
@@ -1,11 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/any.proto
package any // import "github.com/golang/protobuf/ptypes/any"
package any
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -16,7 +18,7 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
@@ -99,17 +101,18 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// }
//
type Any struct {
// A URL/resource name whose content describes the type of the
// serialized protocol buffer message.
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// For URLs which use the scheme `http`, `https`, or no scheme, the
// following restrictions and interpretations apply:
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// The name should be in a canonical form (e.g., leading "." is
// not accepted).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
@@ -118,6 +121,10 @@ type Any struct {
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
@@ -133,17 +140,19 @@ func (m *Any) Reset() { *m = Any{} }
func (m *Any) String() string { return proto.CompactTextString(m) }
func (*Any) ProtoMessage() {}
func (*Any) Descriptor() ([]byte, []int) {
return fileDescriptor_any_744b9ca530f228db, []int{0}
return fileDescriptor_b53526c13ae22eb4, []int{0}
}
func (*Any) XXX_WellKnownType() string { return "Any" }
func (m *Any) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Any.Unmarshal(m, b)
}
func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Any.Marshal(b, m, deterministic)
}
func (dst *Any) XXX_Merge(src proto.Message) {
xxx_messageInfo_Any.Merge(dst, src)
func (m *Any) XXX_Merge(src proto.Message) {
xxx_messageInfo_Any.Merge(m, src)
}
func (m *Any) XXX_Size() int {
return xxx_messageInfo_Any.Size(m)
@@ -172,9 +181,9 @@ func init() {
proto.RegisterType((*Any)(nil), "google.protobuf.Any")
}
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) }
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_b53526c13ae22eb4) }
var fileDescriptor_any_744b9ca530f228db = []byte{
var fileDescriptor_b53526c13ae22eb4 = []byte{
// 185 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
+13 -8
View File
@@ -120,17 +120,18 @@ option objc_class_prefix = "GPB";
// }
//
message Any {
// A URL/resource name whose content describes the type of the
// serialized protocol buffer message.
// A URL/resource name that uniquely identifies the type of the serialized
// protocol buffer message. The last segment of the URL's path must represent
// the fully qualified name of the type (as in
// `path/google.protobuf.Duration`). The name should be in a canonical form
// (e.g., leading "." is not accepted).
//
// For URLs which use the scheme `http`, `https`, or no scheme, the
// following restrictions and interpretations apply:
// In practice, teams usually precompile into the binary all types that they
// expect it to use in the context of Any. However, for URLs which use the
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * The last segment of the URL's path must represent the fully
// qualified name of the type (as in `path/google.protobuf.Duration`).
// The name should be in a canonical form (e.g., leading "." is
// not accepted).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
@@ -139,6 +140,10 @@ message Any {
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
// type.googleapis.com.
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
+1 -1
View File
@@ -82,7 +82,7 @@ func Duration(p *durpb.Duration) (time.Duration, error) {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
}
if p.Nanos != 0 {
d += time.Duration(p.Nanos)
d += time.Duration(p.Nanos) * time.Nanosecond
if (d < 0) != (p.Nanos < 0) {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
}
+14 -12
View File
@@ -1,11 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/duration.proto
package duration // import "github.com/golang/protobuf/ptypes/duration"
package duration
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -16,7 +18,7 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
@@ -99,17 +101,19 @@ func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) {
return fileDescriptor_duration_e7d612259e3f0613, []int{0}
return fileDescriptor_23597b2ebd7ac6c5, []int{0}
}
func (*Duration) XXX_WellKnownType() string { return "Duration" }
func (m *Duration) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Duration.Unmarshal(m, b)
}
func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Duration.Marshal(b, m, deterministic)
}
func (dst *Duration) XXX_Merge(src proto.Message) {
xxx_messageInfo_Duration.Merge(dst, src)
func (m *Duration) XXX_Merge(src proto.Message) {
xxx_messageInfo_Duration.Merge(m, src)
}
func (m *Duration) XXX_Size() int {
return xxx_messageInfo_Duration.Size(m)
@@ -138,11 +142,9 @@ func init() {
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
}
func init() {
proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613)
}
func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_23597b2ebd7ac6c5) }
var fileDescriptor_duration_e7d612259e3f0613 = []byte{
var fileDescriptor_23597b2ebd7ac6c5 = []byte{
// 190 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
+2 -4
View File
@@ -111,11 +111,9 @@ func TimestampNow() *tspb.Timestamp {
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
// It returns an error if the resulting Timestamp is invalid.
func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
seconds := t.Unix()
nanos := int32(t.Sub(time.Unix(seconds, 0)))
ts := &tspb.Timestamp{
Seconds: seconds,
Nanos: nanos,
Seconds: t.Unix(),
Nanos: int32(t.Nanosecond()),
}
if err := validateTimestamp(ts); err != nil {
return nil, err
+19 -15
View File
@@ -1,11 +1,13 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/timestamp.proto
package timestamp // import "github.com/golang/protobuf/ptypes/timestamp"
package timestamp
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -16,7 +18,7 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// A Timestamp represents a point in time independent of any time zone
// or calendar, represented as seconds and fractions of seconds at
@@ -81,7 +83,9 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
// is required, though only UTC (as indicated by "Z") is presently supported.
// is required. A proto3 JSON serializer should always use UTC (as indicated by
// "Z") when printing the Timestamp type and a proto3 JSON parser should be
// able to accept both UTC and other timezones (as indicated by an offset).
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
// 01:30 UTC on January 15, 2017.
@@ -92,8 +96,8 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
// to obtain a formatter capable of generating timestamps in this format.
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--
// ) to obtain a formatter capable of generating timestamps in this format.
//
//
type Timestamp struct {
@@ -115,17 +119,19 @@ func (m *Timestamp) Reset() { *m = Timestamp{} }
func (m *Timestamp) String() string { return proto.CompactTextString(m) }
func (*Timestamp) ProtoMessage() {}
func (*Timestamp) Descriptor() ([]byte, []int) {
return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0}
return fileDescriptor_292007bbfe81227e, []int{0}
}
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
func (m *Timestamp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Timestamp.Unmarshal(m, b)
}
func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic)
}
func (dst *Timestamp) XXX_Merge(src proto.Message) {
xxx_messageInfo_Timestamp.Merge(dst, src)
func (m *Timestamp) XXX_Merge(src proto.Message) {
xxx_messageInfo_Timestamp.Merge(m, src)
}
func (m *Timestamp) XXX_Size() int {
return xxx_messageInfo_Timestamp.Size(m)
@@ -154,11 +160,9 @@ func init() {
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
}
func init() {
proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8)
}
func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_292007bbfe81227e) }
var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{
var fileDescriptor_292007bbfe81227e = []byte{
// 191 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
+5 -3
View File
@@ -103,7 +103,9 @@ option objc_class_prefix = "GPB";
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
// is required, though only UTC (as indicated by "Z") is presently supported.
// is required. A proto3 JSON serializer should always use UTC (as indicated by
// "Z") when printing the Timestamp type and a proto3 JSON parser should be
// able to accept both UTC and other timezones (as indicated by an offset).
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
// 01:30 UTC on January 15, 2017.
@@ -114,8 +116,8 @@ option objc_class_prefix = "GPB";
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
// to obtain a formatter capable of generating timestamps in this format.
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--
// ) to obtain a formatter capable of generating timestamps in this format.
//
//
message Timestamp {
+7 -7
View File
@@ -270,7 +270,7 @@ github.com/golang-plus/uuid/internal/random
github.com/golang-plus/uuid/internal/timebased
# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/glog
# github.com/golang/protobuf v1.2.0
# github.com/golang/protobuf v1.3.1
github.com/golang/protobuf/proto
github.com/golang/protobuf/ptypes
github.com/golang/protobuf/ptypes/any
@@ -509,16 +509,16 @@ golang.org/x/net/bpf
golang.org/x/net/ipv4
golang.org/x/net/proxy
golang.org/x/net/ipv6
golang.org/x/net/trace
golang.org/x/net/internal/iana
golang.org/x/net/internal/socket
golang.org/x/net/http2
golang.org/x/net/context
golang.org/x/net/trace
golang.org/x/net/internal/socks
golang.org/x/net/http/httpguts
golang.org/x/net/http2/hpack
golang.org/x/net/idna
golang.org/x/net/internal/timeseries
golang.org/x/net/http2/hpack
golang.org/x/net/http/httpguts
golang.org/x/net/idna
golang.org/x/net/context/ctxhttp
# golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890
golang.org/x/oauth2
@@ -551,14 +551,14 @@ google.golang.org/appengine/internal/urlfetch
google.golang.org/genproto/googleapis/rpc/status
# google.golang.org/grpc v1.19.0
google.golang.org/grpc
google.golang.org/grpc/codes
google.golang.org/grpc/status
google.golang.org/grpc/peer
google.golang.org/grpc/credentials
google.golang.org/grpc/codes
google.golang.org/grpc/grpclog
google.golang.org/grpc/health/grpc_health_v1
google.golang.org/grpc/keepalive
google.golang.org/grpc/metadata
google.golang.org/grpc/status
google.golang.org/grpc/balancer
google.golang.org/grpc/balancer/roundrobin
google.golang.org/grpc/connectivity