mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-07-03 12:54:38 +08:00
support usb controller type: qemu-xhci, usb-ehci. qemu-xhci is much more virtualization-friendly when compared to EHCI and UHCI. but guest supports XHCI which should be the case for any operating system released around 2010 or later. So sometimes wo need use usb controller type EHCI. Signed-off-by: wanyaoqi <d3lx.yq@gmail.com>
960 lines
31 KiB
Go
960 lines
31 KiB
Go
// 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 compute
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
|
|
"yunion.io/x/onecloud/cmd/climc/shell"
|
|
"yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
|
|
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
|
"yunion.io/x/onecloud/pkg/mcclient/options"
|
|
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
|
"yunion.io/x/onecloud/pkg/util/ssh"
|
|
)
|
|
|
|
func init() {
|
|
cmd := shell.NewResourceCmd(&modules.Servers)
|
|
cmd.List(new(options.ServerListOptions))
|
|
cmd.Show(new(options.ServerShowOptions))
|
|
cmd.BatchDeleteWithParam(new(options.ServerDeleteOptions))
|
|
cmd.BatchPerform("cancel-delete", new(options.ServerCancelDeleteOptions))
|
|
cmd.BatchPut(new(options.ServerUpdateOptions))
|
|
cmd.GetMetadata(new(options.ServerIdOptions))
|
|
cmd.Perform("clone", new(options.ServerCloneOptions))
|
|
cmd.BatchPerform("start", new(options.ServerIdsOptions))
|
|
cmd.BatchPerform("syncstatus", new(options.ServerIdsOptions))
|
|
cmd.BatchPerform("sync", new(options.ServerIdsOptions))
|
|
cmd.Perform("switch-to-backup", new(options.ServerSwitchToBackupOptions))
|
|
cmd.BatchPerform("reconcile-backup", new(options.ServerIdsOptions))
|
|
cmd.BatchPerform("create-backup", new(options.ServerIdsOptions))
|
|
cmd.Perform("delete-backup", new(options.ServerDeleteBackupOptions))
|
|
cmd.BatchPerform("stop", new(options.ServerStopOptions))
|
|
cmd.BatchPerform("suspend", new(options.ServerIdsOptions))
|
|
cmd.BatchPerform("resume", new(options.ServerIdsOptions))
|
|
cmd.BatchPerform("reset", new(options.ServerResetOptions))
|
|
cmd.BatchPerform("restart", new(options.ServerRestartOptions))
|
|
cmd.BatchPerform("purge", new(options.ServerIdsOptions))
|
|
cmd.PrintObjectYAML().Perform("migrate-forecast", new(options.ServerMigrateForecastOptions))
|
|
cmd.Perform("migrate", new(options.ServerMigrateOptions))
|
|
cmd.Perform("live-migrate", new(options.ServerLiveMigrateOptions))
|
|
cmd.Perform("modify-src-check", new(options.ServerModifySrcCheckOptions))
|
|
cmd.Perform("set-secgroup", new(options.ServerSecGroupsOptions))
|
|
cmd.Perform("add-secgroup", new(options.ServerSecGroupsOptions))
|
|
cmd.Perform("assign-secgroup", new(options.ServerSecGroupOptions))
|
|
cmd.Perform("assign-admin-secgroup", new(options.ServerSecGroupOptions))
|
|
cmd.Perform("revoke-secgroup", new(options.ServerSecGroupOptions))
|
|
cmd.Perform("revoke-admin-secgroup", new(options.ServerIdOptions))
|
|
cmd.Perform("save-image", new(options.ServerSaveImageOptions))
|
|
cmd.Perform("save-guest-image", new(options.ServerSaveGuestImageOptions))
|
|
cmd.Perform("change-owner", new(options.ServerChangeOwnerOptions))
|
|
cmd.Perform("rebuild-root", new(options.ServerRebuildRootOptions))
|
|
cmd.Perform("change-config", new(options.ServerChangeConfigOptions))
|
|
cmd.Perform("ejectiso", new(options.ServerIdOptions))
|
|
cmd.Perform("sendkeys", new(options.ServerSendKeyOptions))
|
|
cmd.Perform("deploy", new(options.ServerDeployOptions))
|
|
cmd.Perform("associate-eip", new(options.ServerAssociateEipOptions))
|
|
cmd.Perform("dissociate-eip", new(options.ServerDissociateEipOptions))
|
|
cmd.Perform("renew", new(options.ServerRenewOptions))
|
|
cmd.Perform("io-throttle", new(options.ServerIoThrottle))
|
|
cmd.Perform("publicip-to-eip", new(options.ServerPublicipToEip))
|
|
cmd.Perform("set-auto-renew", new(options.ServerSetAutoRenew))
|
|
cmd.Perform("save-template", new(options.ServerSaveImageOptions))
|
|
cmd.Perform("remote-update", new(options.ServerRemoteUpdateOptions))
|
|
cmd.Perform("create-eip", &options.ServerCreateEipOptions{})
|
|
cmd.Perform("make-sshable", &options.ServerMakeSshableOptions{})
|
|
cmd.Perform("migrate-network", &options.ServerMigrateNetworkOptions{})
|
|
cmd.Perform("set-sshport", &options.ServerSetSshportOptions{})
|
|
cmd.Perform("have-agent", &options.ServerHaveAgentOptions{})
|
|
cmd.Perform("change-disk-storage", &options.ServerChangeDiskStorageOptions{})
|
|
cmd.Perform("probe-isolated-devices", &options.ServerIdOptions{})
|
|
|
|
cmd.Get("vnc", new(options.ServerIdOptions))
|
|
cmd.Get("desc", new(options.ServerIdOptions))
|
|
cmd.Get("status", new(options.ServerIdOptions))
|
|
cmd.Get("iso", new(options.ServerIdOptions))
|
|
cmd.Get("create-params", new(options.ServerIdOptions))
|
|
cmd.Get("sshable", new(options.ServerIdOptions))
|
|
cmd.Get("make-sshable-cmd", new(options.ServerIdOptions))
|
|
cmd.Get("change-owner-candidate-domains", new(options.ServerChangeOwnerCandidateDomainsOptions))
|
|
cmd.Get("change-owner-candidate-domains", new(options.ServerChangeOwnerCandidateDomainsOptions))
|
|
cmd.Get("sshport", new(options.ServerIdOptions))
|
|
|
|
cmd.GetProperty(&options.ServerStatusStatisticsOptions{})
|
|
cmd.GetProperty(&options.ServerProjectStatisticsOptions{})
|
|
cmd.GetProperty(&options.ServerDomainStatisticsOptions{})
|
|
|
|
type ServerTaskShowOptions struct {
|
|
ID string `help:"ID or name of server" json:"-"`
|
|
Since string `help:"show tasks since this time point"`
|
|
Open bool `help:"show tasks that are not completed" json:"-"`
|
|
Complete bool `help:"show tasks that has been completed" json:"-"`
|
|
}
|
|
R(&ServerTaskShowOptions{}, "server-tasks", "Show tasks of a server", func(s *mcclient.ClientSession, opts *ServerTaskShowOptions) error {
|
|
params, err := options.StructToParams(opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if opts.Open {
|
|
params.Add(jsonutils.JSONTrue, "is_open")
|
|
} else if opts.Complete {
|
|
params.Add(jsonutils.JSONFalse, "is_open")
|
|
}
|
|
result, err := modules.Servers.GetSpecific(s, opts.ID, "tasks", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tasks, err := result.GetArray("tasks")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
listResult := modulebase.ListResult{}
|
|
listResult.Data = tasks
|
|
printList(&listResult, nil)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerBatchMetadataOptions{}, "server-batch-add-tag", "add tags for some server", func(s *mcclient.ClientSession, opts *options.ServerBatchMetadataOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := modules.Servers.PerformClassAction(s, "batch-user-metadata", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerBatchMetadataOptions{}, "server-batch-set-tag", "Set tags for some server", func(s *mcclient.ClientSession, opts *options.ServerBatchMetadataOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := modules.Servers.PerformClassAction(s, "batch-set-user-metadata", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ResourceMetadataOptions{}, "server-add-tag", "Set tag of a server", func(s *mcclient.ClientSession, opts *options.ResourceMetadataOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "user-metadata", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ResourceMetadataOptions{}, "server-set-tag", "Set tag of a server", func(s *mcclient.ClientSession, opts *options.ResourceMetadataOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "set-user-metadata", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ResourceMetadataOptions{}, "server-set-metadata", "Set raw metadata of a server", func(s *mcclient.ClientSession, opts *options.ResourceMetadataOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "metadata", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerCreateFromInstanceSnapshot{}, "server-create-from-instance-snapshot", "server create from instance snapshot",
|
|
func(s *mcclient.ClientSession, opts *options.ServerCreateFromInstanceSnapshot) error {
|
|
params := &compute.ServerCreateInput{}
|
|
params.InstanceSnapshotId = opts.InstaceSnapshotId
|
|
params.Name = opts.NAME
|
|
params.AutoStart = opts.AutoStart
|
|
params.Eip = opts.Eip
|
|
params.EipChargeType = opts.EipChargeType
|
|
params.EipBw = opts.EipBw
|
|
|
|
server, err := modules.Servers.Create(s, params.JSON(params))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(server)
|
|
return nil
|
|
},
|
|
)
|
|
|
|
R(&options.ServerCreateOptions{}, "server-check-create-data", "Check create server data", func(s *mcclient.ClientSession, opts *options.ServerCreateOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
server, err := modules.Servers.PerformClassAction(s, "check-create-data", params.JSON(params))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(server)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerCreateOptions{}, "server-create", "Create a server", func(s *mcclient.ClientSession, opts *options.ServerCreateOptions) error {
|
|
params, err := opts.Params()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
count := params.Count
|
|
if options.BoolV(opts.DryRun) {
|
|
listFields := []string{"id", "name", "capacity", "count", "score", "capacity_details", "score_details"}
|
|
input, err := opts.ToScheduleInput()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := modules.SchedManager.Test(s, input)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printList(modulebase.JSON2ListResult(result), listFields)
|
|
} else {
|
|
taskNotify := options.BoolV(opts.TaskNotify)
|
|
if taskNotify {
|
|
s.PrepareTask()
|
|
}
|
|
if count > 1 {
|
|
results := modules.Servers.BatchCreate(s, params.JSON(params), count)
|
|
printBatchResults(results, modules.Servers.GetColumns(s))
|
|
} else {
|
|
server, err := modules.Servers.Create(s, params.JSON(params))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(server)
|
|
}
|
|
if taskNotify {
|
|
s.WaitTaskNotify()
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerLoginInfoOptions{}, "server-logininfo", "Get login info of a server", func(s *mcclient.ClientSession, opts *options.ServerLoginInfoOptions) error {
|
|
srvid, e := modules.Servers.GetId(s, opts.ID, nil)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
|
|
params := jsonutils.NewDict()
|
|
if len(opts.Key) > 0 {
|
|
privateKey, e := ioutil.ReadFile(opts.Key)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
params.Add(jsonutils.NewString(string(privateKey)), "private_key")
|
|
}
|
|
|
|
i, e := modules.Servers.GetLoginInfo(s, srvid, params)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
printObject(i)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerMonitorOptions{}, "server-monitor", "Send commands to qemu monitor", func(s *mcclient.ClientSession, opts *options.ServerMonitorOptions) error {
|
|
params, err := options.StructToParams(opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ret, err := modules.Servers.PerformAction(s, opts.ID, "monitor", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result, err := ret.GetString("results")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerDiskSnapshotOptions struct {
|
|
SERVER string `help:"server ID or Name"`
|
|
DISK string `help:"create snapshot disk id"`
|
|
SNAPSHOTNAME string `help:"Snapshot name"`
|
|
}
|
|
R(&ServerDiskSnapshotOptions{}, "server-disk-create-snapshot", "Task server disk snapshot", func(s *mcclient.ClientSession, args *ServerDiskSnapshotOptions) error {
|
|
params := jsonutils.NewDict()
|
|
params.Set("disk_id", jsonutils.NewString(args.DISK))
|
|
params.Set("name", jsonutils.NewString(args.SNAPSHOTNAME))
|
|
srv, err := modules.Servers.PerformAction(s, args.SERVER, "disk-snapshot", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(srv)
|
|
return nil
|
|
})
|
|
|
|
type ServerInsertISOOptions struct {
|
|
ID string `help:"server ID or Name"`
|
|
ISO string `help:"Glance image ID of the ISO"`
|
|
}
|
|
R(&ServerInsertISOOptions{}, "server-insert-iso", "Insert an ISO image into server's cdrom", func(s *mcclient.ClientSession, opts *ServerInsertISOOptions) error {
|
|
img, err := modules.Images.Get(s, opts.ISO, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
imgId, err := img.GetString("id")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
params := jsonutils.NewDict()
|
|
params.Add(jsonutils.NewString(imgId), "image_id")
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "insertiso", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerUserDataOptions struct {
|
|
ID string `help:"ID or name of server"`
|
|
FILE string `help:"Path to user data file"`
|
|
}
|
|
R(&ServerUserDataOptions{}, "server-set-user-data", "Update server user_data", func(s *mcclient.ClientSession, args *ServerUserDataOptions) error {
|
|
params := jsonutils.NewDict()
|
|
content, err := ioutil.ReadFile(args.FILE)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
params.Add(jsonutils.NewString(string(content)), "user_data")
|
|
result, err := modules.Servers.PerformAction(s, args.ID, "user-data", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerAddExtraOption struct {
|
|
ID string `help:"ID or name of server"`
|
|
KEY string `help:"Option key"`
|
|
VALUE string `help:"Option value"`
|
|
}
|
|
R(&ServerAddExtraOption{}, "server-add-extra-options", "Add server extra options", func(s *mcclient.ClientSession, args *ServerAddExtraOption) error {
|
|
params := jsonutils.NewDict()
|
|
params.Add(jsonutils.NewString(args.KEY), "key")
|
|
params.Add(jsonutils.NewString(args.VALUE), "value")
|
|
result, err := modules.Servers.PerformAction(s, args.ID, "set-extra-option", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
type ServerRemoveExtraOption struct {
|
|
ID string `help:"ID or name of server"`
|
|
KEY string `help:"Option key"`
|
|
}
|
|
R(&ServerRemoveExtraOption{}, "server-remove-extra-options", "Remove server extra options", func(s *mcclient.ClientSession, args *ServerRemoveExtraOption) error {
|
|
params := jsonutils.NewDict()
|
|
params.Add(jsonutils.NewString(args.KEY), "key")
|
|
result, err := modules.Servers.PerformAction(s, args.ID, "del-extra-option", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerPrepaidRecycleOptions{}, "server-enable-recycle", "Put a prepaid server into recycle pool, so that it can be shared", func(s *mcclient.ClientSession, args *options.ServerPrepaidRecycleOptions) error {
|
|
params := jsonutils.NewDict()
|
|
if args.AutoDelete {
|
|
params.Add(jsonutils.JSONTrue, "auto_delete")
|
|
}
|
|
result, err := modules.Servers.PerformAction(s, args.ID, "prepaid-recycle", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerPrepaidRecycleOptions{}, "server-disable-recycle", "Pull a prepaid server from recycle pool, so that it will not be shared anymore", func(s *mcclient.ClientSession, args *options.ServerPrepaidRecycleOptions) error {
|
|
params := jsonutils.NewDict()
|
|
result, err := modules.Servers.PerformAction(s, args.ID, "undo-prepaid-recycle", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerImportOptions struct {
|
|
LOCATION string `help:"Server desc file location, should be desc file or workspace directory"`
|
|
HOST string `help:"Host id or name for this server"`
|
|
}
|
|
R(&ServerImportOptions{}, "server-import", "Import a server by desc file", func(s *mcclient.ClientSession, args *ServerImportOptions) error {
|
|
var descFiles []string
|
|
err := filepath.Walk(args.LOCATION, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
if info.Name() == "desc" {
|
|
descFiles = append(descFiles, path)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("Find desc files: %v", err)
|
|
}
|
|
|
|
importF := func(desc string) error {
|
|
ret, err := ioutil.ReadFile(desc)
|
|
if err != nil {
|
|
return fmt.Errorf("Read file %s: %v", desc, err)
|
|
}
|
|
jsonObj, err := jsonutils.Parse(ret)
|
|
if err != nil {
|
|
return fmt.Errorf("Parse %s to json: %v", string(ret), err)
|
|
}
|
|
params := jsonObj.(*jsonutils.JSONDict)
|
|
disks, err := params.GetArray("disks")
|
|
if err != nil || len(disks) == 0 {
|
|
return fmt.Errorf("Desc %s not have disks, skip it", desc)
|
|
}
|
|
params.Add(jsonutils.NewString(args.HOST), "host_id")
|
|
// project may not exists
|
|
params.Remove("tenant")
|
|
params.Remove("tenant_id")
|
|
_, err = modules.Servers.PerformClassAction(s, "import", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//printObject(result)
|
|
return nil
|
|
}
|
|
|
|
for _, descFile := range descFiles {
|
|
if err := importF(descFile); err != nil {
|
|
log.Errorf("Import %s error: %v", descFile, err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
type ServersImportFromLibvirtOptions struct {
|
|
CONFIG_FILE string `help:"File Path describing servers from libvirt"`
|
|
}
|
|
|
|
type Servers struct {
|
|
Mac string `yaml:"mac"`
|
|
Ip string `yaml:"ip"`
|
|
}
|
|
|
|
type Hosts struct {
|
|
HostIp string `yaml:"host_ip"`
|
|
XmlFilePath string `yaml:"xml_file_path"`
|
|
MonitorPath string `yaml:"monitor_path"`
|
|
Servers []Servers `yaml:"servers"`
|
|
}
|
|
|
|
type LibvirtImportOptions struct {
|
|
Hosts []Hosts `yaml:"hosts"`
|
|
}
|
|
|
|
R(&ServersImportFromLibvirtOptions{}, "servers-import-from-libvirt", "Import servers from libvrt", func(s *mcclient.ClientSession, args *ServersImportFromLibvirtOptions) error {
|
|
var (
|
|
rawConfig []byte
|
|
err error
|
|
)
|
|
|
|
rawConfig, err = ioutil.ReadFile(args.CONFIG_FILE)
|
|
if err != nil {
|
|
return fmt.Errorf("Read config file %s error: %s", args.CONFIG_FILE, err)
|
|
}
|
|
|
|
var (
|
|
params []jsonutils.JSONObject
|
|
config = &compute.SLibvirtImportConfig{}
|
|
)
|
|
|
|
// Try parse as json first
|
|
{
|
|
err = json.Unmarshal(rawConfig, config)
|
|
if err != nil {
|
|
goto YAML
|
|
}
|
|
for i := 0; i < len(config.Hosts); i++ {
|
|
if nIp := net.ParseIP(config.Hosts[i].HostIp); nIp == nil {
|
|
return fmt.Errorf("Parse host ip %s failed", config.Hosts[i].HostIp)
|
|
}
|
|
for _, server := range config.Hosts[i].Servers {
|
|
for mac, ip := range server.MacIp {
|
|
if _, err := net.ParseMAC(mac); err != nil {
|
|
return fmt.Errorf("Parse mac %s error %s", mac, err)
|
|
}
|
|
if nIp := net.ParseIP(ip); nIp == nil {
|
|
return fmt.Errorf("Parse ip %s failed", ip)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
goto REQUEST
|
|
}
|
|
|
|
YAML: // Try Parse as yaml
|
|
{
|
|
yamlConfig := &LibvirtImportOptions{}
|
|
err = yaml.Unmarshal(rawConfig, yamlConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
config.Hosts = make([]compute.SLibvirtHostConfig, len(yamlConfig.Hosts))
|
|
for i := 0; i < len(yamlConfig.Hosts); i++ {
|
|
if nIp := net.ParseIP(yamlConfig.Hosts[i].HostIp); nIp == nil {
|
|
return fmt.Errorf("Parse host ip %s failed", yamlConfig.Hosts[i].HostIp)
|
|
}
|
|
config.Hosts[i].HostIp = yamlConfig.Hosts[i].HostIp
|
|
config.Hosts[i].XmlFilePath = yamlConfig.Hosts[i].XmlFilePath
|
|
config.Hosts[i].Servers = make([]compute.SLibvirtServerConfig, len(yamlConfig.Hosts[i].Servers))
|
|
config.Hosts[i].MonitorPath = yamlConfig.Hosts[i].MonitorPath
|
|
for j := 0; j < len(yamlConfig.Hosts[i].Servers); j++ {
|
|
config.Hosts[i].Servers[j].MacIp = make(map[string]string)
|
|
mac := yamlConfig.Hosts[i].Servers[j].Mac
|
|
_, err := net.ParseMAC(mac)
|
|
if err != nil {
|
|
return fmt.Errorf("Parse mac address %s error %s", mac, err)
|
|
}
|
|
ip := yamlConfig.Hosts[i].Servers[j].Ip
|
|
nIp := net.ParseIP(ip)
|
|
if len(nIp) == 0 {
|
|
return fmt.Errorf("Parse ip address %s failed", ip)
|
|
}
|
|
config.Hosts[i].Servers[j].MacIp[mac] = ip
|
|
}
|
|
}
|
|
}
|
|
|
|
REQUEST:
|
|
params, err = jsonutils.Marshal(config.Hosts).GetArray()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//for i := 0; i < len(params); i++ {
|
|
// val := jsonutils.NewDict()
|
|
// val.Set(modules.Servers.KeywordPlural, params[i])
|
|
// params[i] = val
|
|
//}
|
|
|
|
results := modules.Servers.BatchPerformClassAction(s, "import-from-libvirt", params)
|
|
printBatchResults(results, modules.Servers.GetColumns(s))
|
|
return nil
|
|
})
|
|
|
|
type ServerExportVirtInstallCommand struct {
|
|
ID string `help:"Server Id" json:"-"`
|
|
LibvirtBridge string `help:"Libvirt default bridge" json:"libvirt_bridge"`
|
|
ExtraCmdline []string `help:"Extra virt-install arguments add to script, eg:'--extra-args ...', '--console ...'" json:"extra_cmdline"`
|
|
}
|
|
R(&ServerExportVirtInstallCommand{}, "server-export-virt-install-command", "Export virt-install command line from existing guest", func(s *mcclient.ClientSession, args *ServerExportVirtInstallCommand) error {
|
|
params := jsonutils.NewDict()
|
|
if len(args.LibvirtBridge) > 0 {
|
|
params.Set("libvirt_bridge", jsonutils.NewString(args.LibvirtBridge))
|
|
}
|
|
if len(args.ExtraCmdline) > 0 {
|
|
params.Set("extra_cmdline", jsonutils.NewStringArray(args.ExtraCmdline))
|
|
}
|
|
result, err := modules.Servers.GetSpecific(s, args.ID, "virt-install", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerIdOptions{}, "server-remote-nics", "Show remote nics of a server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error {
|
|
result, err := modules.Servers.GetSpecific(s, opts.ID, "remote-nics", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
listResult := modulebase.ListResult{}
|
|
listResult.Data, _ = result.GetArray()
|
|
printList(&listResult, nil)
|
|
return nil
|
|
})
|
|
|
|
type ServerSyncFixNicsOptions struct {
|
|
ID string `help:"ID or name of VM" json:"-"`
|
|
IP []string `help:"IP address of each NIC" json:"ip"`
|
|
}
|
|
R(&ServerSyncFixNicsOptions{}, "server-sync-fix-nics", "Fix missing IP for each nics after syncing VNICS", func(s *mcclient.ClientSession, opts *ServerSyncFixNicsOptions) error {
|
|
params := jsonutils.Marshal(opts)
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "sync-fix-nics", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerResizeDiskOptions struct {
|
|
Server string `help:"ID or name of VM" json:"-" optional:"false" positional:"true"`
|
|
Disk string `help:"ID or name of disk to resize" json:"disk" optional:"false" positional:"true"`
|
|
Size string `help:"new size of disk in MB" json:"size" optional:"false" positional:"true"`
|
|
}
|
|
R(&ServerResizeDiskOptions{}, "server-resize-disk", "Resize attached disk of a server", func(s *mcclient.ClientSession, args *ServerResizeDiskOptions) error {
|
|
params := jsonutils.Marshal(args)
|
|
result, err := modules.Servers.PerformAction(s, args.Server, "resize-disk", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerGroupsOptions struct {
|
|
ID string `help:"ID or name of VM"`
|
|
Group []string `help:"ids or names of group"`
|
|
}
|
|
|
|
R(&ServerGroupsOptions{}, "server-join-groups", "Join multiple groups", func(s *mcclient.ClientSession,
|
|
opts *ServerGroupsOptions) error {
|
|
|
|
params, err := options.StructToParams(opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
server, err := modules.Servers.PerformAction(s, opts.ID, "bind-groups", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(server)
|
|
return nil
|
|
})
|
|
|
|
R(&ServerGroupsOptions{}, "server-leave-groups", "Leave multiple groups", func(s *mcclient.ClientSession,
|
|
opts *ServerGroupsOptions) error {
|
|
|
|
params, err := options.StructToParams(opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
server, err := modules.Servers.PerformAction(s, opts.ID, "unbind-groups", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(server)
|
|
return nil
|
|
})
|
|
|
|
type ServerQemuParams struct {
|
|
ID string `help:"ID or name of VM"`
|
|
DisableIsaSerial string `help:"disable isa serial device" choices:"true|false"`
|
|
DisablePvpanic string `help:"disable pvpanic device" choices:"true|false"`
|
|
DisableUsbKbd string `help:"disable usb kbd" choices:"true|false"`
|
|
UsbControllerType string `help:"usb controller type" choices:"usb-ehci|qemu-xhci"`
|
|
}
|
|
|
|
R(&ServerQemuParams{}, "server-set-qemu-params", "config qemu params", func(s *mcclient.ClientSession,
|
|
opts *ServerQemuParams) error {
|
|
params := jsonutils.NewDict()
|
|
if len(opts.DisableIsaSerial) > 0 {
|
|
params.Set("disable_isa_serial", jsonutils.NewString(opts.DisableIsaSerial))
|
|
}
|
|
if len(opts.DisablePvpanic) > 0 {
|
|
params.Set("disable_pvpanic", jsonutils.NewString(opts.DisablePvpanic))
|
|
}
|
|
if len(opts.DisableUsbKbd) > 0 {
|
|
params.Set("disable_usb_kbd", jsonutils.NewString(opts.DisableUsbKbd))
|
|
}
|
|
if len(opts.UsbControllerType) > 0 {
|
|
params.Set("usb_controller_type", jsonutils.NewString(opts.UsbControllerType))
|
|
}
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "set-qemu-params", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
type ServerCreateSnapshot struct {
|
|
ID string `help:"ID or name of VM" json:"-"`
|
|
SNAPSHOT string `help:"Instance snapshot name" json:"name"`
|
|
}
|
|
R(&ServerCreateSnapshot{}, "instance-snapshot-create", "create instance snapshot", func(s *mcclient.ClientSession, opts *ServerCreateSnapshot) error {
|
|
params := jsonutils.Marshal(opts)
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "instance-snapshot", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
type ServerCreateBackup struct {
|
|
ID string `help:"ID or name of VM" json:"-"`
|
|
BACKUP string `help:"Instance backup name" json:"name"`
|
|
BACKUPSTORAGEID string `help:"backup storage id" json:"backup_storage_id"`
|
|
}
|
|
R(&ServerCreateBackup{}, "instance-backup-create", "create instance backup", func(s *mcclient.ClientSession, opts *ServerCreateBackup) error {
|
|
params := jsonutils.Marshal(opts)
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "instance-backup", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerSnapshotAndClone struct {
|
|
ID string `help:"ID or name of VM" json:"-"`
|
|
NAME string `help:"Newly instance name" json:"name"`
|
|
AutoStart bool `help:"Auto start new guest"`
|
|
AllowDelete bool `help:"Allow new guest delete" json:"-"`
|
|
Count int `help:"Guest count"`
|
|
}
|
|
R(&ServerSnapshotAndClone{}, "instance-snapshot-and-clone", "create instance snapshot and clone new instance", func(s *mcclient.ClientSession, opts *ServerSnapshotAndClone) error {
|
|
params := jsonutils.Marshal(opts)
|
|
dictParams := params.(*jsonutils.JSONDict)
|
|
if opts.AllowDelete {
|
|
dictParams.Set("disable_delete", jsonutils.JSONFalse)
|
|
}
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "snapshot-and-clone", dictParams)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerRollBackSnapshot struct {
|
|
ID string `help:"ID or name of VM" json:"-"`
|
|
InstanceSnapshot string `help:"Instance snapshot id or name" json:"instance_snapshot"`
|
|
AutoStart bool `help:"Auto start VM"`
|
|
}
|
|
R(&ServerRollBackSnapshot{}, "instance-snapshot-reset", "reset instance snapshot", func(s *mcclient.ClientSession, opts *ServerRollBackSnapshot) error {
|
|
params := jsonutils.Marshal(opts)
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "instance-snapshot-reset", params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
|
|
type ServerJnlpOptions struct {
|
|
ID string `help:"ID or name of server"`
|
|
Save string `help:"save xml into this file"`
|
|
}
|
|
R(&ServerJnlpOptions{}, "server-jnlp", "Get baremetal server jnlp file contentn", func(s *mcclient.ClientSession, args *ServerJnlpOptions) error {
|
|
spec, err := modules.Servers.GetSpecific(s, args.ID, "jnlp", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jnlp, err := spec.GetString("jnlp")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(args.Save) > 0 {
|
|
return fileutils2.FilePutContents(args.Save, jnlp, false)
|
|
} else {
|
|
fmt.Println(jnlp)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerSSHLoginOptions{}, "server-ssh", "Use SSH login a server", func(s *mcclient.ClientSession, opts *options.ServerSSHLoginOptions) error {
|
|
srv, err := modules.Servers.Get(s, opts.ID, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
srvid, err := srv.GetString("id")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
eip, err := srv.GetString("eip")
|
|
if err != nil && err.Error() != "Get: key not found" {
|
|
return err
|
|
}
|
|
|
|
vpcid, err := srv.GetString("vpc_id")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
address := make([]string, 0)
|
|
nics, err := srv.GetArray("nics")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, nic := range nics {
|
|
if addr, err := nic.GetString("ip_addr"); err == nil {
|
|
address = append(address, addr)
|
|
}
|
|
}
|
|
if len(address) == 0 {
|
|
return fmt.Errorf("Not found ip address from server %s", opts.ID)
|
|
}
|
|
|
|
privateKey := ""
|
|
params := jsonutils.NewDict()
|
|
if len(opts.Key) > 0 {
|
|
key, e := ioutil.ReadFile(opts.Key)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
params.Add(jsonutils.NewString(string(key)), "private_key")
|
|
privateKey = string(key)
|
|
}
|
|
|
|
i, e := modules.Servers.GetLoginInfo(s, srvid, params)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
passwd, err := i.GetString("password")
|
|
if err != nil && !opts.UseCloudroot {
|
|
return err
|
|
}
|
|
if opts.Password != "" {
|
|
passwd = opts.Password
|
|
}
|
|
user, err := i.GetString("username")
|
|
if err != nil && !opts.UseCloudroot {
|
|
return err
|
|
}
|
|
if opts.User != "" {
|
|
user = opts.User
|
|
}
|
|
port := 22
|
|
if opts.Port != 22 {
|
|
port = opts.Port
|
|
}
|
|
|
|
var forwardItem *forwardInfo = nil
|
|
host := address[0]
|
|
if opts.Host != "" {
|
|
host = opts.Host
|
|
} else {
|
|
if eip != "" {
|
|
host = eip
|
|
} else {
|
|
if vpcid != "default" {
|
|
forwardItem, err = openForward(s, srvid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
host = forwardItem.ProxyAddr
|
|
port = forwardItem.ProxyPort
|
|
}
|
|
}
|
|
}
|
|
|
|
if opts.UseCloudroot {
|
|
var err error
|
|
privateKey, err = modules.Sshkeypairs.FetchPrivateKeyBySession(context.Background(), s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
passwd = ""
|
|
user = "cloudroot"
|
|
}
|
|
|
|
var sshCli *ssh.Client
|
|
err = nil
|
|
for ; sshCli == nil; sshCli, err = ssh.NewClient(host, port, user, passwd, privateKey) {
|
|
if err == nil {
|
|
continue
|
|
}
|
|
if opts.Host != "" {
|
|
return err
|
|
}
|
|
if forwardItem != nil {
|
|
closeForward(s, srvid, forwardItem)
|
|
return err
|
|
} else {
|
|
if vpcid != "default" {
|
|
forwardItem, e = openForward(s, srvid)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
host = forwardItem.ProxyAddr
|
|
port = forwardItem.ProxyPort
|
|
}
|
|
}
|
|
}
|
|
|
|
log.Infof("ssh %s:%d", host, port)
|
|
if err := sshCli.RunTerminal(); err != nil {
|
|
if forwardItem != nil {
|
|
closeForward(s, srvid, forwardItem)
|
|
}
|
|
return err
|
|
}
|
|
|
|
if forwardItem != nil {
|
|
closeForward(s, srvid, forwardItem)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
R(&options.ServerConvertToKvmOptions{}, "server-convert-to-kvm", "Convert esxi server to kvm", func(s *mcclient.ClientSession, opts *options.ServerConvertToKvmOptions) error {
|
|
params := jsonutils.Marshal(opts)
|
|
dict := params.(*jsonutils.JSONDict)
|
|
dict.Set("target_hypervisor", jsonutils.NewString("kvm"))
|
|
result, err := modules.Servers.PerformAction(s, opts.ID, "convert", dict)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
printObject(result)
|
|
return nil
|
|
})
|
|
}
|