mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
feat(region,host,host-deployer):use qga set network
This commit is contained in:
@@ -115,6 +115,8 @@ func init() {
|
||||
cmd.Perform("qga-set-password", &options.ServerQgaSetPassword{})
|
||||
cmd.Perform("qga-command", &options.ServerQgaCommand{})
|
||||
cmd.Perform("qga-ping", &options.ServerQgaPing{})
|
||||
cmd.Perform("qga-guest-info-task", &options.ServerQgaGuestInfoTask{})
|
||||
cmd.Perform("qga-get-network", &options.ServerQgaGetNetwork{})
|
||||
cmd.Perform("set-password", &options.ServerSetPasswordOptions{})
|
||||
cmd.Perform("set-boot-index", &options.ServerSetBootIndexOptions{})
|
||||
cmd.Perform("reset-nic-traffic-limit", &options.ServerNicTrafficLimitOptions{})
|
||||
|
||||
@@ -167,6 +167,9 @@ const (
|
||||
VM_QGA_COMMAND_EXECUTING = "qga_command_executing"
|
||||
VM_QGA_EXEC_COMMAND_FAILED = "qga_exec_command_failed"
|
||||
|
||||
VM_QGA_SET_NETWORK = "qga_set_network"
|
||||
VM_QGA_SET_NETWORK_FAILED = "qga_set_network_failed"
|
||||
|
||||
SHUTDOWN_STOP = "stop"
|
||||
SHUTDOWN_TERMINATE = "terminate"
|
||||
|
||||
|
||||
@@ -985,11 +985,46 @@ type ServerQemuInfo struct {
|
||||
Cmdline string `json:"cmdline"`
|
||||
}
|
||||
|
||||
type IPAddress struct {
|
||||
IPAddress string `json:"ip-address"`
|
||||
IPAddressType string `json:"ip-address-type"`
|
||||
Prefix int `json:"prefix"`
|
||||
}
|
||||
|
||||
type IfnameDetail struct {
|
||||
HardwareAddress string `json:"hardware-address"`
|
||||
IPAddresses []IPAddress `json:"ip-addresses"`
|
||||
Name string `json:"name"`
|
||||
Statistics struct {
|
||||
RxBytes int `json:"rx-bytes"`
|
||||
RxDropped int `json:"rx-dropped"`
|
||||
RxErrs int `json:"rx-errs"`
|
||||
RxPackets int `json:"rx-packets"`
|
||||
TxBytes int `json:"tx-bytes"`
|
||||
TxDropped int `json:"tx-dropped"`
|
||||
TxErrs int `json:"tx-errs"`
|
||||
TxPackets int `json:"tx-packets"`
|
||||
} `json:"statistics"`
|
||||
}
|
||||
|
||||
type ServerQgaSetPasswordInput struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type ServerQgaGuestInfoTaskInput struct {
|
||||
}
|
||||
|
||||
type ServerQgaSetNetworkInput struct {
|
||||
ServerQgaTimeoutInput
|
||||
Device string
|
||||
Ipmask string
|
||||
Gateway string
|
||||
}
|
||||
|
||||
type ServerQgaGetNetworkInput struct {
|
||||
}
|
||||
|
||||
type ServerQgaTimeoutInput struct {
|
||||
// qga execute timeout millisecond
|
||||
Timeout int
|
||||
|
||||
@@ -504,6 +504,18 @@ func (drv *SBaseGuestDriver) QgaRequestSetUserPassword(ctx context.Context, task
|
||||
return httperrors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) QgaRequestGuestInfoTask(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
return nil, httperrors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) QgaRequestSetNetwork(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
return nil, httperrors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) QgaRequestGetNetwork(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
return nil, httperrors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (drv *SBaseGuestDriver) RequestQgaCommand(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
return nil, httperrors.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -1052,6 +1052,39 @@ func (self *SKVMGuestDriver) QgaRequestGuestPing(ctx context.Context, header htt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) QgaRequestGuestInfoTask(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/qga-guest-info-task", host.ManagerUri, guest.Id)
|
||||
httpClient := httputils.GetDefaultClient()
|
||||
header := mcclient.GetTokenHeaders(userCred)
|
||||
_, res, err := httputils.JSONRequest(httpClient, ctx, "POST", url, header, nil, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "host request")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) QgaRequestSetNetwork(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/qga-set-network", host.ManagerUri, guest.Id)
|
||||
httpClient := httputils.GetDefaultClient()
|
||||
header := mcclient.GetTokenHeaders(userCred)
|
||||
_, res, err := httputils.JSONRequest(httpClient, ctx, "POST", url, header, body, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "host request")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) QgaRequestGetNetwork(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) (jsonutils.JSONObject, error) {
|
||||
url := fmt.Sprintf("%s/servers/%s/qga-get-network", host.ManagerUri, guest.Id)
|
||||
httpClient := httputils.GetDefaultClient()
|
||||
header := mcclient.GetTokenHeaders(userCred)
|
||||
_, res, err := httputils.JSONRequest(httpClient, ctx, "POST", url, header, nil, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "host request")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) QgaRequestSetUserPassword(ctx context.Context, task taskman.ITask, host *models.SHost, guest *models.SGuest, input *api.ServerQgaSetPasswordInput) error {
|
||||
url := fmt.Sprintf("%s/servers/%s/qga-set-password", host.ManagerUri, guest.Id)
|
||||
httpClient := httputils.GetDefaultClient()
|
||||
|
||||
@@ -937,6 +937,22 @@ func (self *SGuest) StartRestartNetworkTask(ctx context.Context, userCred mcclie
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SGuest) StartQgaRestartNetworkTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, device string, ipMask string, gateway string, prevIp string, inBlockStream bool) error {
|
||||
data := jsonutils.NewDict()
|
||||
data.Set("device", jsonutils.NewString(device))
|
||||
data.Set("ip_mask", jsonutils.NewString(ipMask))
|
||||
data.Set("gateway", jsonutils.NewString(gateway))
|
||||
data.Set("prev_ip", jsonutils.NewString(prevIp))
|
||||
data.Set("in_block_stream", jsonutils.NewBool(inBlockStream))
|
||||
if task, err := taskman.TaskManager.NewTask(ctx, "GuestQgaRestartNetworkTask", self, userCred, data, parentTaskId, "", nil); err != nil {
|
||||
log.Errorln(err)
|
||||
return err
|
||||
} else {
|
||||
task.ScheduleRun(nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SGuest) startSyncTask(ctx context.Context, userCred mcclient.TokenCredential, firewallOnly bool, parentTaskId string, data *jsonutils.JSONDict) error {
|
||||
if firewallOnly {
|
||||
data.Add(jsonutils.JSONTrue, "fw_only")
|
||||
@@ -948,15 +964,7 @@ func (self *SGuest) startSyncTask(ctx context.Context, userCred mcclient.TokenCr
|
||||
}
|
||||
|
||||
func (self *SGuest) StartSyncTask(ctx context.Context, userCred mcclient.TokenCredential, firewallOnly bool, parentTaskId string) error {
|
||||
|
||||
data := jsonutils.NewDict()
|
||||
if firewallOnly {
|
||||
data.Add(jsonutils.JSONTrue, "fw_only")
|
||||
} else if err := self.SetStatus(userCred, api.VM_SYNC_CONFIG, ""); err != nil {
|
||||
log.Errorln(err)
|
||||
return err
|
||||
}
|
||||
return self.doSyncTask(ctx, data, userCred, parentTaskId)
|
||||
return self.startSyncTask(ctx, userCred, firewallOnly, parentTaskId, jsonutils.NewDict())
|
||||
}
|
||||
|
||||
func (self *SGuest) StartSyncTaskWithoutSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, fwOnly bool, parentTaskId string) error {
|
||||
@@ -2368,6 +2376,14 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Get the detailed description of the NIC
|
||||
networkJsonDesc := ngn[0].getJsonDesc()
|
||||
newIpAddr := networkJsonDesc.Ip
|
||||
newMacAddr := networkJsonDesc.Mac
|
||||
newMaskLen := networkJsonDesc.Masklen
|
||||
newGateway := networkJsonDesc.Gateway
|
||||
ipMask := fmt.Sprintf("%s/%d", newIpAddr, newMaskLen)
|
||||
|
||||
notes := jsonutils.NewDict()
|
||||
if gn != nil {
|
||||
notes.Add(jsonutils.NewString(gn.IpAddr), "prev_ip")
|
||||
@@ -2383,12 +2399,38 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T
|
||||
if self.Hypervisor == api.HYPERVISOR_KVM && restartNetwork && (self.Status == api.VM_RUNNING || self.Status == api.VM_BLOCK_STREAM) {
|
||||
taskData.Set("restart_network", jsonutils.JSONTrue)
|
||||
taskData.Set("prev_ip", jsonutils.NewString(gn.IpAddr))
|
||||
taskData.Set("prev_mac", jsonutils.NewString(newMacAddr))
|
||||
net := ngn[0].GetNetwork()
|
||||
taskData.Set("is_vpc_network", jsonutils.NewBool(net.isOneCloudVpcNetwork()))
|
||||
taskData.Set("ip_mask", jsonutils.NewString(ipMask))
|
||||
taskData.Set("gateway", jsonutils.NewString(newGateway))
|
||||
if self.Status == api.VM_BLOCK_STREAM {
|
||||
taskData.Set("in_block_stream", jsonutils.JSONTrue)
|
||||
}
|
||||
self.SetStatus(userCred, api.VM_RESTART_NETWORK, "restart network")
|
||||
}
|
||||
return nil, self.startSyncTask(ctx, userCred, true, "", taskData)
|
||||
return nil, self.startSyncTask(ctx, userCred, false, "", taskData)
|
||||
}
|
||||
|
||||
func (self *SGuest) GetIfNameByMac(ctx context.Context, userCred mcclient.TokenCredential, mac string) (string, error) {
|
||||
//Find the network card according to the mac address, if it is empty, it means no network card is found
|
||||
ifnameData, err := self.PerformQgaGetNetwork(ctx, userCred, nil, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//Get the name of the network card
|
||||
var parsedData []api.IfnameDetail
|
||||
if err := ifnameData.Unmarshal(&parsedData); err != nil {
|
||||
return "", err
|
||||
}
|
||||
var ifnameDevice string
|
||||
//Finding a network card by its mac address
|
||||
for _, detail := range parsedData {
|
||||
if detail.HardwareAddress == mac {
|
||||
ifnameDevice = detail.Name
|
||||
}
|
||||
}
|
||||
return ifnameDevice, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformDetachnetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerDetachnetworkInput) (jsonutils.JSONObject, error) {
|
||||
|
||||
@@ -234,6 +234,9 @@ type IGuestDriver interface {
|
||||
QgaRequestGuestPing(ctx context.Context, header http.Header, host *SHost, guest *SGuest, async bool, input *api.ServerQgaTimeoutInput) error
|
||||
QgaRequestSetUserPassword(ctx context.Context, task taskman.ITask, host *SHost, guest *SGuest, input *api.ServerQgaSetPasswordInput) error
|
||||
RequestQgaCommand(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *SHost, guest *SGuest) (jsonutils.JSONObject, error)
|
||||
QgaRequestGuestInfoTask(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *SHost, guest *SGuest) (jsonutils.JSONObject, error)
|
||||
QgaRequestSetNetwork(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *SHost, guest *SGuest) (jsonutils.JSONObject, error)
|
||||
QgaRequestGetNetwork(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject, host *SHost, guest *SGuest) (jsonutils.JSONObject, error)
|
||||
|
||||
FetchMonitorUrl(ctx context.Context, guest *SGuest) string
|
||||
RequestResetNicTrafficLimit(ctx context.Context, task taskman.ITask, host *SHost, guest *SGuest, input *api.ServerNicTrafficLimit) error
|
||||
|
||||
@@ -103,3 +103,29 @@ func (self *SGuest) PerformQgaCommand(
|
||||
host, _ := self.GetHost()
|
||||
return self.GetDriver().RequestQgaCommand(ctx, userCred, jsonutils.Marshal(input), host, self)
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformQgaGuestInfoTask(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
input *api.ServerQgaGuestInfoTaskInput,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
if self.PowerStates != api.VM_POWER_STATES_ON {
|
||||
return nil, httperrors.NewBadRequestError("can't use qga in vm status: %s", self.Status)
|
||||
}
|
||||
host, _ := self.GetHost()
|
||||
return self.GetDriver().QgaRequestGuestInfoTask(ctx, userCred, nil, host, self)
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformQgaGetNetwork(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
input *api.ServerQgaGetNetworkInput,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
if self.PowerStates != api.VM_POWER_STATES_ON {
|
||||
return nil, httperrors.NewBadRequestError("can't use qga in vm status: %s", self.Status)
|
||||
}
|
||||
host, _ := self.GetHost()
|
||||
return self.GetDriver().QgaRequestGetNetwork(ctx, userCred, nil, host, self)
|
||||
}
|
||||
|
||||
93
pkg/compute/tasks/guest_qga_restart_network_task.go
Normal file
93
pkg/compute/tasks/guest_qga_restart_network_task.go
Normal file
@@ -0,0 +1,93 @@
|
||||
// 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 tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type GuestQgaRestartNetworkTask struct {
|
||||
SGuestBaseTask
|
||||
}
|
||||
|
||||
func init() {
|
||||
taskman.RegisterTask(GuestQgaRestartNetworkTask{})
|
||||
}
|
||||
|
||||
func (self *GuestQgaRestartNetworkTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
guest.SetStatus(self.UserCred, api.VM_QGA_SET_NETWORK, "")
|
||||
self.OnRestartNetwork(ctx, guest)
|
||||
}
|
||||
|
||||
func (self *GuestQgaRestartNetworkTask) OnRestartNetwork(ctx context.Context, guest *models.SGuest) {
|
||||
device, _ := self.Params.GetString("device")
|
||||
ipMask, _ := self.Params.GetString("ip_mask")
|
||||
gateway, _ := self.Params.GetString("gateway")
|
||||
prevIp, _ := self.Params.GetString("prev_ip")
|
||||
inBlockStream, _ := self.Params.Bool("in_block_stream")
|
||||
|
||||
_, err := self.requestSetNetwork(ctx, guest, device, ipMask, gateway)
|
||||
//the first set maybe fail,if failed, try again
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_RESTART_NETWORK, err, self.UserCred, false)
|
||||
_, err = self.requestSetNetwork(ctx, guest, device, ipMask, gateway)
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_RESTART_NETWORK, err, self.UserCred, false)
|
||||
self.taskFailed(ctx, guest, prevIp, inBlockStream, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_QGA_NETWORK_SUCCESS, "qga restart network success", self.UserCred, true)
|
||||
guest.UpdateQgaStatus(api.QGA_STATUS_AVAILABLE)
|
||||
guest.StartSyncstatus(ctx, self.UserCred, "")
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
func (self *GuestQgaRestartNetworkTask) requestSetNetwork(ctx context.Context, guest *models.SGuest, device string, ipMask string, gateway string) (jsonutils.JSONObject, error) {
|
||||
host, err := guest.GetHost()
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, guest, "", false, err)
|
||||
return nil, err
|
||||
}
|
||||
inputQgaNet := &api.ServerQgaSetNetworkInput{
|
||||
Device: device,
|
||||
Ipmask: ipMask,
|
||||
Gateway: gateway,
|
||||
}
|
||||
|
||||
// if success, log network related information
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_QGA_NETWORK_INPUT, inputQgaNet, self.UserCred, true)
|
||||
return guest.GetDriver().QgaRequestSetNetwork(ctx, self.UserCred, jsonutils.Marshal(inputQgaNet), host, guest)
|
||||
}
|
||||
|
||||
func (self *GuestQgaRestartNetworkTask) taskFailed(ctx context.Context, guest *models.SGuest, prevIp string, inBlockStream bool, err error) {
|
||||
guest.SetStatus(self.GetUserCred(), api.VM_QGA_SET_NETWORK_FAILED, err.Error())
|
||||
guest.UpdateQgaStatus(api.QGA_STATUS_EXECUTE_FAILED)
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_RESTART_NETWORK, jsonutils.NewString(err.Error()), self.UserCred, false)
|
||||
if prevIp != "" {
|
||||
//use ansible to restart network
|
||||
guest.StartRestartNetworkTask(ctx, self.UserCred, "", prevIp, inBlockStream)
|
||||
}
|
||||
self.SetStageFailed(ctx, nil)
|
||||
}
|
||||
@@ -16,14 +16,19 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/vpcagent"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
@@ -52,24 +57,8 @@ func (self *GuestSyncConfTask) OnInit(ctx context.Context, obj db.IStandaloneMod
|
||||
|
||||
func (self *GuestSyncConfTask) OnSyncComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
if fwOnly, _ := self.GetParams().Bool("fw_only"); fwOnly {
|
||||
db.OpsLog.LogEvent(guest, db.ACT_SYNC_CONF, nil, self.UserCred)
|
||||
if restart, _ := self.Params.Bool("restart_network"); !restart {
|
||||
self.SetStageComplete(ctx, nil)
|
||||
return
|
||||
}
|
||||
prevIp, err := self.Params.GetString("prev_ip")
|
||||
if err != nil {
|
||||
log.Errorf("unable to get prev_ip when restart_network is true when sync guest")
|
||||
self.SetStageComplete(ctx, nil)
|
||||
return
|
||||
}
|
||||
if inBlockStream := jsonutils.QueryBoolean(self.Params, "in_block_stream", false); inBlockStream {
|
||||
guest.StartRestartNetworkTask(ctx, self.UserCred, "", prevIp, true)
|
||||
} else {
|
||||
guest.StartRestartNetworkTask(ctx, self.UserCred, "", prevIp, false)
|
||||
}
|
||||
self.SetStageComplete(ctx, guest.GetShortDesc(ctx))
|
||||
if restart, _ := self.Params.Bool("restart_network"); restart {
|
||||
self.StartRestartNetworkTask(ctx, guest)
|
||||
} else if data.Contains("task") {
|
||||
// XXX this is only applied to KVM, which will call task_complete twice
|
||||
self.SetStage("on_disk_sync_complete", nil)
|
||||
@@ -78,6 +67,67 @@ func (self *GuestSyncConfTask) OnSyncComplete(ctx context.Context, obj db.IStand
|
||||
}
|
||||
}
|
||||
|
||||
func (self *GuestSyncConfTask) StartRestartNetworkTask(ctx context.Context, guest *models.SGuest) {
|
||||
defer self.SetStageComplete(ctx, guest.GetShortDesc(ctx))
|
||||
prevIp, err := self.Params.GetString("prev_ip")
|
||||
if err != nil {
|
||||
log.Errorf("unable to get prev_ip when restart_network is true when sync guest")
|
||||
return
|
||||
}
|
||||
inBlockStream := jsonutils.QueryBoolean(self.Params, "in_block_stream", false)
|
||||
if guest.Hypervisor != api.HYPERVISOR_KVM {
|
||||
guest.StartRestartNetworkTask(ctx, self.UserCred, "", prevIp, inBlockStream)
|
||||
return
|
||||
}
|
||||
preMac, err := self.Params.GetString("prev_mac")
|
||||
if err != nil {
|
||||
log.Errorf("unable to get prev_mac when restart_network is true when sync guest")
|
||||
return
|
||||
}
|
||||
ipMask, err := self.Params.GetString("ip_mask")
|
||||
if err != nil {
|
||||
log.Errorf("unable to get ip_mask when restart_network is true when sync guest")
|
||||
return
|
||||
}
|
||||
gateway, err := self.Params.GetString("gateway")
|
||||
if err != nil {
|
||||
log.Errorf("unable to get gateway when restart_network is true when sync guest")
|
||||
return
|
||||
}
|
||||
isVpcNetwork := jsonutils.QueryBoolean(self.Params, "is_vpc_network", false)
|
||||
|
||||
// try use qga restart network
|
||||
err = func() error {
|
||||
host, _ := guest.GetHost()
|
||||
err = guest.GetDriver().QgaRequestGuestPing(ctx, self.GetTaskRequestHeader(), host, guest, false, &api.ServerQgaTimeoutInput{1000})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "qga guest-ping")
|
||||
}
|
||||
ifnameDevice, err := guest.GetIfNameByMac(ctx, self.UserCred, preMac)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get ifname by mac")
|
||||
}
|
||||
if ifnameDevice == "" {
|
||||
return errors.Errorf("failed find ifname")
|
||||
}
|
||||
|
||||
if isVpcNetwork {
|
||||
err = vpcagent.VpcAgent.DoSync(auth.GetAdminSession(ctx, options.Options.Region))
|
||||
if err != nil {
|
||||
log.Errorf("vpcagent.VpcAgent.DoSync fail %s", err)
|
||||
}
|
||||
// wait for vpcagent sync network topo
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
return guest.StartQgaRestartNetworkTask(
|
||||
ctx, self.UserCred, "", ifnameDevice, ipMask, gateway, prevIp, inBlockStream)
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("guest %s failed start qga restart network task: %s", guest.GetName(), err)
|
||||
guest.StartRestartNetworkTask(ctx, self.UserCred, "", prevIp, inBlockStream)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *GuestSyncConfTask) OnDiskSyncComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
|
||||
if jsonutils.QueryBoolean(self.Params, "without_sync_status", false) {
|
||||
self.OnSyncStatusComplete(ctx, guest, nil)
|
||||
|
||||
@@ -129,6 +129,9 @@ func DoDeployGuestFs(rootfs fsdriver.IRootFsDriver, guestDesc *deployapi.GuestDe
|
||||
if err = rootfs.DeployHosts(partition, hn, domain, ips); err != nil {
|
||||
return nil, errors.Wrap(err, "DeployHosts")
|
||||
}
|
||||
if err = rootfs.DeployQgaBlackList(partition); err != nil {
|
||||
return nil, fmt.Errorf("DeployQgaBlackList: %v", err)
|
||||
}
|
||||
if err = rootfs.DeployNetworkingScripts(partition, nics); err != nil {
|
||||
return nil, errors.Wrap(err, "DeployNetworkingScripts")
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ func (m *sBaseAndroidRootFs) DeployHosts(part IDiskPartition, hn, domain string,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *sBaseAndroidRootFs) DeployQgaBlackList(part IDiskPartition) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *sBaseAndroidRootFs) GetOs() string {
|
||||
return "Android"
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ func (m *SEsxiRootFs) DeployHostname(part IDiskPartition, hostname, domain strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SEsxiRootFs) DeployQgaBlackList(part IDiskPartition) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SEsxiRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ type IRootFsDriver interface {
|
||||
GetOs() string
|
||||
DeployHostname(part IDiskPartition, hn, domain string) error
|
||||
DeployHosts(part IDiskPartition, hn, domain string, ips []string) error
|
||||
DeployQgaBlackList(part IDiskPartition) error
|
||||
DeployNetworkingScripts(IDiskPartition, []*types.SServerNic) error
|
||||
DeployStandbyNetworkingScripts(part IDiskPartition, nics, nicsStandby []*types.SServerNic) error
|
||||
DeployUdevSubsystemScripts(IDiskPartition) error
|
||||
|
||||
@@ -80,6 +80,35 @@ func getHostname(hostname, domain string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *sLinuxRootFs) DeployQgaBlackList(rootFs IDiskPartition) error {
|
||||
etcSysconfigQemuga := "/etc/sysconfig/qemu-ga"
|
||||
blackListContent := `# This is a systemd environment file, not a shell script.
|
||||
# It provides settings for \"/lib/systemd/system/qemu-guest-agent.service\".
|
||||
|
||||
# Comma-separated blacklist of RPCs to disable, or empty list to enable all.
|
||||
#
|
||||
# You can get the list of RPC commands using \"qemu-ga --blacklist='?'\".
|
||||
# There should be no spaces between commas and commands in the blacklist.
|
||||
# BLACKLIST_RPC=guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush,guest-exec,guest-exec-status
|
||||
|
||||
# Fsfreeze hook script specification.
|
||||
#
|
||||
# FSFREEZE_HOOK_PATHNAME=/dev/null : disables the feature.
|
||||
#
|
||||
# FSFREEZE_HOOK_PATHNAME=/path/to/executable : enables the feature with the
|
||||
# specified binary or shell script.
|
||||
#
|
||||
# FSFREEZE_HOOK_PATHNAME= : enables the feature with the
|
||||
# default value (invoke \"qemu-ga --help\" to interrogate).
|
||||
FSFREEZE_HOOK_PATHNAME=/etc/qemu-ga/fsfreeze-hook"
|
||||
`
|
||||
|
||||
if err := rootFs.FilePutContents(etcSysconfigQemuga, blackListContent, false, false); err != nil {
|
||||
return errors.Wrap(err, "etcSysconfigQemuga error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *sLinuxRootFs) DeployHosts(rootFs IDiskPartition, hostname, domain string, ips []string) error {
|
||||
var etcHosts = "/etc/hosts"
|
||||
var oldHostFile string
|
||||
@@ -160,6 +189,37 @@ func (l *sLinuxRootFs) DeployPublicKey(rootFs IDiskPartition, selUsr string, pub
|
||||
return DeployAuthorizedKeys(rootFs, usrDir, pubkeys, false)
|
||||
}
|
||||
|
||||
func (d *SCoreOsRootFs) DeployQgaBlackList(rootFs IDiskPartition) error {
|
||||
etcSysconfigQemuga := "/etc/sysconfig/qemu-ga"
|
||||
blackListContent := `# This is a systemd environment file, not a shell script.
|
||||
# It provides settings for \"/lib/systemd/system/qemu-guest-agent.service\".
|
||||
|
||||
# Comma-separated blacklist of RPCs to disable, or empty list to enable all.
|
||||
#
|
||||
# You can get the list of RPC commands using \"qemu-ga --blacklist='?'\".
|
||||
# There should be no spaces between commas and commands in the blacklist.
|
||||
# BLACKLIST_RPC=guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush,guest-exec,guest-exec-status
|
||||
|
||||
# Fsfreeze hook script specification.
|
||||
#
|
||||
# FSFREEZE_HOOK_PATHNAME=/dev/null : disables the feature.
|
||||
#
|
||||
# FSFREEZE_HOOK_PATHNAME=/path/to/executable : enables the feature with the
|
||||
# specified binary or shell script.
|
||||
#
|
||||
# FSFREEZE_HOOK_PATHNAME= : enables the feature with the
|
||||
# default value (invoke \"qemu-ga --help\" to interrogate).
|
||||
FSFREEZE_HOOK_PATHNAME=/etc/qemu-ga/fsfreeze-hook"
|
||||
`
|
||||
|
||||
if rootFs.Exists(etcSysconfigQemuga, false) {
|
||||
if err := rootFs.FilePutContents(etcSysconfigQemuga, blackListContent, false, false); err != nil {
|
||||
return errors.Wrap(err, "etcSysconfigQemuga error")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *sLinuxRootFs) DeployYunionroot(rootFs IDiskPartition, pubkeys *deployapi.SSHKeys, isInit, enableCloudInit bool) error {
|
||||
if !consts.AllowVmSELinux() {
|
||||
l.DisableSelinux(rootFs)
|
||||
|
||||
@@ -116,6 +116,10 @@ func (m *SMacOSRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips [
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SMacOSRootFs) DeployQgaBlackList(part IDiskPartition) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SMacOSRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo {
|
||||
spath := "/System/Library/CoreServices/SystemVersion.plist"
|
||||
sInfo, _ := m.rootFs.FileGetContents(spath, false)
|
||||
|
||||
@@ -277,6 +277,10 @@ func (w *SWindowsRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips
|
||||
return w.rootFs.FilePutContents(ETC_HOSTS, hf.String(), false, true)
|
||||
}
|
||||
|
||||
func (w *SWindowsRootFs) DeployQgaBlackList(part IDiskPartition) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*types.SServerNic) error {
|
||||
mainNic, err := netutils2.GetMainNicFromDeployApi(nics)
|
||||
if err != nil {
|
||||
|
||||
@@ -104,3 +104,59 @@ func (m *SGuestManager) QgaCommand(cmd *monitor.Command, sid string, execTimeout
|
||||
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
func (m *SGuestManager) QgaGuestInfoTask(sid string) (string, error) {
|
||||
guest, err := m.checkAndInitGuestQga(sid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var res []byte
|
||||
if guest.guestAgent.TryLock() {
|
||||
defer guest.guestAgent.Unlock()
|
||||
res, err = guest.guestAgent.GuestInfoTask()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "qga guest info task")
|
||||
}
|
||||
return string(res), nil
|
||||
}
|
||||
return "", errors.Errorf("qga unfinished last cmd, is qga unavailable?")
|
||||
}
|
||||
|
||||
func (m *SGuestManager) QgaSetNetwork(netmod *monitor.NetworkModify, sid string, execTimeout int) (string, error) {
|
||||
guest, err := m.checkAndInitGuestQga(sid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var res []byte
|
||||
if guest.guestAgent.TryLock() {
|
||||
defer guest.guestAgent.Unlock()
|
||||
|
||||
if execTimeout > 0 {
|
||||
guest.guestAgent.SetTimeout(execTimeout)
|
||||
defer guest.guestAgent.ResetTimeout()
|
||||
}
|
||||
err = guest.guestAgent.QgaSetNetwork(netmod)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "modify %s network failed", netmod.Device)
|
||||
}
|
||||
return string(res), nil
|
||||
}
|
||||
return "", errors.Errorf("qga unfinished last cmd, is qga unavailable?")
|
||||
}
|
||||
|
||||
func (m *SGuestManager) QgaGetNetwork(sid string) (string, error) {
|
||||
guest, err := m.checkAndInitGuestQga(sid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var res []byte
|
||||
if guest.guestAgent.TryLock() {
|
||||
defer guest.guestAgent.Unlock()
|
||||
res, err = guest.guestAgent.QgaGetNetwork()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "qga get network fail")
|
||||
}
|
||||
return string(res), nil
|
||||
}
|
||||
return "", errors.Errorf("qga unfinished last cmd, is qga unavailable?")
|
||||
}
|
||||
|
||||
@@ -99,6 +99,9 @@ func AddGuestTaskHandler(prefix string, app *appsrv.Application) {
|
||||
"qga-command": qgaCommand,
|
||||
"reset-nic-traffic-limit": guestResetNicTrafficLimit,
|
||||
"set-nic-traffic-limit": guestSetNicTrafficLimit,
|
||||
"qga-guest-info-task": qgaGuestInfoTask,
|
||||
"qga-get-network": qgaGetNetwork,
|
||||
"qga-set-network": qgaSetNetwork,
|
||||
} {
|
||||
app.AddHandler("POST",
|
||||
fmt.Sprintf("%s/%s/<sid>/%s", prefix, keyWord, action),
|
||||
@@ -878,3 +881,38 @@ func qgaCommand(ctx context.Context, userCred mcclient.TokenCredential, sid stri
|
||||
|
||||
return gm.QgaCommand(qgaCmd, sid, input.Timeout)
|
||||
}
|
||||
|
||||
func qgaGuestInfoTask(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) {
|
||||
gm := guestman.GetGuestManager()
|
||||
return gm.QgaGuestInfoTask(sid)
|
||||
}
|
||||
|
||||
func qgaGetNetwork(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) {
|
||||
gm := guestman.GetGuestManager()
|
||||
return gm.QgaGetNetwork(sid)
|
||||
}
|
||||
|
||||
func qgaSetNetwork(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) {
|
||||
gm := guestman.GetGuestManager()
|
||||
input := computeapi.ServerQgaSetNetworkInput{}
|
||||
err := body.Unmarshal(&input)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError("unmarshal input to ServerQgaSetNetworkInput: %s", err.Error())
|
||||
}
|
||||
if input.Device == "" {
|
||||
return nil, httperrors.NewMissingParameterError("device")
|
||||
}
|
||||
if input.Ipmask == "" {
|
||||
return nil, httperrors.NewMissingParameterError("ipmask")
|
||||
}
|
||||
if input.Gateway == "" {
|
||||
return nil, httperrors.NewMissingParameterError("gateway")
|
||||
}
|
||||
|
||||
qgaNetMod := &monitor.NetworkModify{
|
||||
Device: input.Device,
|
||||
Ipmask: input.Ipmask,
|
||||
Gateway: input.Gateway,
|
||||
}
|
||||
return gm.QgaSetNetwork(qgaNetMod, sid, input.Timeout)
|
||||
}
|
||||
|
||||
@@ -2025,6 +2025,7 @@ func getNicBridge(nic *desc.SGuestNetwork) string {
|
||||
}
|
||||
|
||||
func onNicChange(oldNic, newNic *desc.SGuestNetwork) error {
|
||||
log.Infof("nic changed old: %s new: %s", jsonutils.Marshal(oldNic), jsonutils.Marshal(newNic))
|
||||
// override network base desc
|
||||
oldNic.GuestnetworkBaseDesc = newNic.GuestnetworkBaseDesc
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -173,7 +176,7 @@ func (qga *QemuGuestAgent) execCmd(cmd *monitor.Command, expectResp bool, readTi
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if readTimeout < 0 {
|
||||
if readTimeout <= 0 {
|
||||
readTimeout = qga.readTimeout
|
||||
}
|
||||
err = qga.rwc.SetReadDeadline(time.Now().Add(time.Duration(readTimeout) * time.Millisecond))
|
||||
@@ -245,6 +248,217 @@ func (qga *QemuGuestAgent) GuestInfo() (*GuestInfo, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) GuestInfoTask() ([]byte, error) {
|
||||
info, err := qga.GuestInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd := &monitor.Command{
|
||||
Execute: "guest-info",
|
||||
}
|
||||
var i = 0
|
||||
for ; i < len(info.SupportedCommands); i++ {
|
||||
if info.SupportedCommands[i].Name == cmd.Execute {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i > len(info.SupportedCommands) {
|
||||
return nil, errors.Errorf("unsupported command %s", cmd.Execute)
|
||||
}
|
||||
if !info.SupportedCommands[i].Enabled {
|
||||
return nil, errors.Errorf("command %s not enabled", cmd.Execute)
|
||||
}
|
||||
res, err := qga.execCmd(cmd, true, -1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return *res, nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaGetNetwork() ([]byte, error) {
|
||||
cmd := &monitor.Command{
|
||||
Execute: "guest-network-get-interfaces",
|
||||
}
|
||||
res, err := qga.execCmd(cmd, true, -1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return *res, nil
|
||||
}
|
||||
|
||||
type GuestOsInfo struct {
|
||||
Id string `json:"id"`
|
||||
KernelRelease string `json:"kernel-release"`
|
||||
KernelVersion string `json:"kernel-version"`
|
||||
Machine string `json:"machine"`
|
||||
Name string `json:"name"`
|
||||
PrettyName string `json:"pretty-name"`
|
||||
Version string `json:"version"`
|
||||
VersionId string `json:"version-id"`
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaGuestGetOsInfo() (*GuestOsInfo, error) {
|
||||
//run guest-get-osinfo
|
||||
cmdOsInfo := &monitor.Command{
|
||||
Execute: "guest-get-osinfo",
|
||||
}
|
||||
rawResOsInfo, err := qga.execCmd(cmdOsInfo, true, -1)
|
||||
resOsInfo := new(GuestOsInfo)
|
||||
err = json.Unmarshal(*rawResOsInfo, resOsInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal raw response")
|
||||
}
|
||||
return resOsInfo, nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaFileOpen(path string) (int, error) {
|
||||
//file open
|
||||
cmdFileOpen := &monitor.Command{
|
||||
Execute: "guest-file-open",
|
||||
Args: map[string]interface{}{
|
||||
"path": path,
|
||||
"mode": "w+",
|
||||
},
|
||||
}
|
||||
rawResFileOpen, err := qga.execCmd(cmdFileOpen, true, -1)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
fileNum, err := strconv.ParseInt(string(*rawResFileOpen), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(fileNum), nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaFileWrite(fileNum int, content string) error {
|
||||
contentEncode := base64.StdEncoding.EncodeToString([]byte(content))
|
||||
//write shell to file
|
||||
cmdFileWrite := &monitor.Command{
|
||||
Execute: "guest-file-write",
|
||||
Args: map[string]interface{}{
|
||||
"handle": fileNum,
|
||||
"buf-b64": contentEncode,
|
||||
},
|
||||
}
|
||||
_, err := qga.execCmd(cmdFileWrite, true, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaFileClose(fileNum int) error {
|
||||
//close file
|
||||
cmdFileClose := &monitor.Command{
|
||||
Execute: "guest-file-close",
|
||||
Args: map[string]interface{}{
|
||||
"handle": fileNum,
|
||||
},
|
||||
}
|
||||
_, err := qga.execCmd(cmdFileClose, true, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseIPAndSubnet(input string) (string, string, error) {
|
||||
//Converting IP/MASK format to IP and MASK
|
||||
parts := strings.Split(input, "/")
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("Invalid input format")
|
||||
}
|
||||
|
||||
ip := parts[0]
|
||||
subnetSizeStr := parts[1]
|
||||
|
||||
subnetSize := 0
|
||||
for _, c := range subnetSizeStr {
|
||||
if c < '0' || c > '9' {
|
||||
return "", "", fmt.Errorf("Invalid subnet size")
|
||||
}
|
||||
subnetSize = subnetSize*10 + int(c-'0')
|
||||
}
|
||||
|
||||
mask := net.CIDRMask(subnetSize, 32)
|
||||
subnetMask := net.IP(mask).To4().String()
|
||||
return ip, subnetMask, nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaAddFileExec(filePath string) error {
|
||||
//Adding execution permissions to file
|
||||
shellAddAuth := "chmod +x " + filePath
|
||||
arg := []string{"-c", shellAddAuth}
|
||||
cmdAddAuth := &monitor.Command{
|
||||
Execute: "guest-exec",
|
||||
Args: map[string]interface{}{
|
||||
"path": "/bin/bash",
|
||||
"arg": arg,
|
||||
"env": []string{},
|
||||
"input-data": "",
|
||||
"capture-output": true,
|
||||
},
|
||||
}
|
||||
_, err := qga.execCmd(cmdAddAuth, true, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaSetWindowsNetwork(qgaNetMod *monitor.NetworkModify) error {
|
||||
ip, subnetMask, err := ParseIPAndSubnet(qgaNetMod.Ipmask)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
networkCmd := fmt.Sprintf(
|
||||
"netsh interface ip set address name=\"%s\" source=static addr=%s mask=%s gateway=%s & "+
|
||||
"netsh interface ip set address name=\"%s\" dhcp",
|
||||
qgaNetMod.Device, ip, subnetMask, qgaNetMod.Gateway, qgaNetMod.Device,
|
||||
)
|
||||
|
||||
log.Infof("networkCmd: %s", networkCmd)
|
||||
arg := []string{"/C", networkCmd}
|
||||
cmdExecNet := &monitor.Command{
|
||||
Execute: "guest-exec",
|
||||
Args: map[string]interface{}{
|
||||
"path": "C:\\Windows\\System32\\cmd.exe",
|
||||
"arg": arg,
|
||||
"env": []string{},
|
||||
"input-data": "",
|
||||
"capture-output": true,
|
||||
},
|
||||
}
|
||||
_, err = qga.execCmd(cmdExecNet, true, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaSetLinuxNetwork(qgaNetMod *monitor.NetworkModify) error {
|
||||
args := []string{"-c", fmt.Sprintf("/sbin/dhclient -r %s && /sbin/dhclient -1 %s", qgaNetMod.Device, qgaNetMod.Device)}
|
||||
_, err := qga.GuestExecCommand("/bin/bash", args, []string{}, "", false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) QgaSetNetwork(qgaNetMod *monitor.NetworkModify) error {
|
||||
//Getting information about the operating system
|
||||
resOsInfo, err := qga.QgaGuestGetOsInfo()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get os info")
|
||||
}
|
||||
|
||||
//Judgement based on id, currently only windows and other systems are judged
|
||||
switch resOsInfo.Id {
|
||||
case "mswindows":
|
||||
return qga.QgaSetWindowsNetwork(qgaNetMod)
|
||||
default:
|
||||
return qga.QgaSetLinuxNetwork(qgaNetMod)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
# @username: the user account whose password to change
|
||||
# @password: the new password entry string, base64 encoded
|
||||
|
||||
@@ -82,6 +82,12 @@ type Command struct {
|
||||
Args interface{} `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
type NetworkModify struct {
|
||||
Device string `json:"device"`
|
||||
Ipmask string `json:"ipmask"`
|
||||
Gateway string `json:"gateway"`
|
||||
}
|
||||
|
||||
type Version struct {
|
||||
Package string `json:"package"`
|
||||
QEMU struct {
|
||||
|
||||
@@ -857,6 +857,22 @@ func (o *ServerQgaPing) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(o)
|
||||
}
|
||||
|
||||
type ServerQgaGuestInfoTask struct {
|
||||
ServerIdOptions
|
||||
}
|
||||
|
||||
func (o *ServerQgaGuestInfoTask) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(o)
|
||||
}
|
||||
|
||||
type ServerQgaGetNetwork struct {
|
||||
ServerIdOptions
|
||||
}
|
||||
|
||||
func (o *ServerQgaGetNetwork) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(o)
|
||||
}
|
||||
|
||||
type ServerSetPasswordOptions struct {
|
||||
ServerIdOptions
|
||||
|
||||
|
||||
@@ -227,6 +227,10 @@ const (
|
||||
|
||||
ACT_RESTART_NETWORK = "restart_network"
|
||||
|
||||
ACT_QGA_NETWORK_INPUT = "qga_network_input"
|
||||
ACT_QGA_STATUS_UPDATE = "qga_status_update"
|
||||
ACT_QGA_NETWORK_SUCCESS = "qga_network_success"
|
||||
|
||||
ACT_RECOVERY = "recovery"
|
||||
ACT_PACK = "pack"
|
||||
ACT_UNPACK = "unpack"
|
||||
|
||||
Reference in New Issue
Block a user