Merge pull request #4419 from rainzm/feature/esxi_agent_bb

Feature(esxi-agent): Esxi Agent Go Version
This commit is contained in:
yunion-ci-robot
2020-01-04 21:07:37 +08:00
committed by GitHub
48 changed files with 4124 additions and 175 deletions
+4
View File
@@ -0,0 +1,4 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/onecloud-base:latest
COPY ./build/esxi-agent/root/opt/ /opt/
ADD ./_output/bin/esxi-agent /opt/yunion/bin/esxi-agent
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common"
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
xmlns:vmw="http://www.vmware.com/schema/ovf"
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<References>
<File ovf:href="{{ .Name }}" ovf:id="file1" ovf:size="{{ .Size }}"/>
</References>
<DiskSection>
<Info>Virtual disk information</Info>
<Disk ovf:capacity="{{ .Capacity }}" ovf:capacityAllocationUnits="byte" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/>
</DiskSection>
<VirtualSystem ovf:id="{{ .ImportName }}">
<Info>A virtual machine</Info>
<Name>{{ .ImportName }}</Name>
<OperatingSystemSection ovf:id="100" vmw:osType="other26xLinux64Guest">
<Info>The kind of installed guest operating system</Info>
</OperatingSystemSection>
<VirtualHardwareSection>
<Info>Virtual hardware requirements</Info>
<System>
<vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
<vssd:InstanceID>0</vssd:InstanceID>
<vssd:VirtualSystemIdentifier>{{ .ImportName }}</vssd:VirtualSystemIdentifier>
<vssd:VirtualSystemType>vmx-07</vssd:VirtualSystemType>
</System>
<Item>
<rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
<rasd:Description>Number of Virtual CPUs</rasd:Description>
<rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
<rasd:InstanceID>1</rasd:InstanceID>
<rasd:ResourceType>3</rasd:ResourceType>
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
<rasd:Description>Memory Size</rasd:Description>
<rasd:ElementName>1024MB of memory</rasd:ElementName>
<rasd:InstanceID>2</rasd:InstanceID>
<rasd:ResourceType>4</rasd:ResourceType>
<rasd:VirtualQuantity>1024</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:Address>0</rasd:Address>
<rasd:Description>SCSI Controller</rasd:Description>
<rasd:ElementName>SCSI Controller 0</rasd:ElementName>
<rasd:InstanceID>3</rasd:InstanceID>
<rasd:ResourceSubType>VirtualSCSI</rasd:ResourceSubType>
<rasd:ResourceType>6</rasd:ResourceType>
</Item>
<Item>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
<rasd:ElementName>Hard Disk 1</rasd:ElementName>
<rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
<rasd:InstanceID>9</rasd:InstanceID>
<rasd:Parent>3</rasd:Parent>
<rasd:ResourceType>17</rasd:ResourceType>
<vmw:Config ovf:required="false" vmw:key="backing.writeThrough" vmw:value="false"/>
</Item>
</VirtualHardwareSection>
</VirtualSystem>
</Envelope>
+2
View File
@@ -0,0 +1,2 @@
DESCRIPTION="Esxi Agent"
# SERVICE="yes"
+26
View File
@@ -0,0 +1,26 @@
// 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 main
import (
"yunion.io/x/onecloud/pkg/esxi/service"
"yunion.io/x/onecloud/pkg/util/atexit"
)
func main() {
defer atexit.Handle()
service.New().StartService()
}
+4 -16
View File
@@ -24,6 +24,7 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/version"
"yunion.io/x/onecloud/pkg/cloudcommon/agent/iagent"
"yunion.io/x/onecloud/pkg/cloudcommon/object"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -31,19 +32,6 @@ import (
"yunion.io/x/onecloud/pkg/util/httputils"
)
type IAgent interface {
GetAgentType() string
GetAccessIP() (net.IP, error)
GetListenIP() (net.IP, error)
GetPort() int
GetEnableSsl() bool
GetZoneName() string
GetAdminSession() *mcclient.ClientSession
TuneSystem() error
StartService() error
StopService() error
}
type SZoneInfo struct {
Name string `json:"name"`
Id string `json:"id"`
@@ -80,11 +68,11 @@ func getIfaceIPs(iface *net.Interface) ([]net.IP, error) {
return ips, nil
}
func (agent *SBaseAgent) IAgent() IAgent {
return agent.GetVirtualObject().(IAgent)
func (agent *SBaseAgent) IAgent() iagent.IAgent {
return agent.GetVirtualObject().(iagent.IAgent)
}
func (agent *SBaseAgent) Init(iagent IAgent, ifname string, cachePath string) error {
func (agent *SBaseAgent) Init(iagent iagent.IAgent, ifname string, cachePath string) error {
iface, err := net.InterfaceByName(ifname)
if err != nil {
return err
+15
View File
@@ -0,0 +1,15 @@
// 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 iagent // import "yunion.io/x/onecloud/pkg/cloudcommon/agent/iagent"
+34
View File
@@ -0,0 +1,34 @@
// 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 iagent
import (
"net"
"yunion.io/x/onecloud/pkg/mcclient"
)
type IAgent interface {
GetAgentType() string
GetAccessIP() (net.IP, error)
GetListenIP() (net.IP, error)
GetPort() int
GetEnableSsl() bool
GetZoneName() string
GetAdminSession() *mcclient.ClientSession
TuneSystem() error
StartService() error
StopService() error
}
+4
View File
@@ -65,6 +65,8 @@ func (w *SWorkManager) delayTask(ctx context.Context, task DelayTaskFunc, params
w.delayTaskWithoutReqctx(ctx, task, params, worker)
return
} else {
// delayTask should have a new context.Context with value 'taskid'
ctx = context.WithValue(context.Background(), appctx.APP_CONTEXT_KEY_TASK_ID, ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID))
w.add()
worker.Run(func() {
defer w.done()
@@ -109,6 +111,8 @@ func (w *SWorkManager) DelayTaskWithoutReqctx(ctx context.Context, task DelayTas
func (w *SWorkManager) delayTaskWithoutReqctx(
ctx context.Context, task DelayTaskFunc, params interface{}, worker *appsrv.SWorkerManager,
) {
// delayTaskWithReqctx should have a new context.Context
ctx = context.Background()
w.add()
w.worker.Run(func() {
defer w.done()
+175
View File
@@ -0,0 +1,175 @@
// 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 esxi
import (
"context"
"fmt"
"net"
"net/http"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/agent"
"yunion.io/x/onecloud/pkg/cloudcommon/workmanager"
"yunion.io/x/onecloud/pkg/esxi/options"
"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"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
const (
_ = compute.AgentTypeEsxi
)
var (
EsxiAgent *SEsxiAgent
)
type SEsxiAgent struct {
agent.SBaseAgent
agentImageCache *storageman.SAgentImageCacheManager
AgentStorage *storageman.SAgentStorage
ListenNic netutils2.SNetInterface
}
func NewEsxiAgent() (*SEsxiAgent, error) {
agent := &SEsxiAgent{}
err := agent.Init(agent, options.Options.ListenInterface, options.Options.ImageCachePath)
if err != nil {
return nil, err
}
return agent, nil
}
func (ea *SEsxiAgent) GetAgentType() string {
return string(compute.AgentTypeEsxi)
}
func (ea *SEsxiAgent) GetAccessIP() (net.IP, error) {
return ea.GetListenIP()
}
func (ea *SEsxiAgent) GetListenIP() (net.IP, error) {
return ea.FindListenIP(options.Options.ListenAddress)
}
func (ea *SEsxiAgent) GetPort() int {
return options.Options.Port
}
func (ea *SEsxiAgent) GetEnableSsl() bool {
return options.Options.EnableSsl
}
func (ea *SEsxiAgent) GetZoneName() string {
return options.Options.Zone
}
func (ea *SEsxiAgent) GetAdminSession() *mcclient.ClientSession {
return auth.GetAdminSession(context.TODO(), options.Options.Region, "v2")
}
func (ea *SEsxiAgent) TuneSystem() error {
return nil
}
func (ea *SEsxiAgent) StartService() error {
ea.DoOnline(ea.GetAdminSession())
return nil
}
func (ea *SEsxiAgent) StopService() error {
return nil
}
func (ea *SEsxiAgent) Start() error {
err := ea.SBaseAgent.Start()
if err != nil {
return err
}
// add agent image cache
ea.agentImageCache = storageman.NewAgentImageCacheManager(ea.CacheManager)
ea.AgentStorage = storageman.NewAgentStorage(&storageman.SStorageManager{LocalStorageImagecacheManager: ea.CacheManager},
ea, options.Options.AgentTempPath)
return nil
}
func Start(app *appsrv.Application) error {
var err error
if EsxiAgent != nil {
log.Warningf("Global EsxiAgent already start")
return nil
}
EsxiAgent, err = NewEsxiAgent()
if err != nil {
return err
}
err = EsxiAgent.Start()
if err != nil {
return err
}
EsxiAgent.AddImageCacheHandler("", app)
return nil
}
func (agent *SEsxiAgent) AddImageCacheHandler(prefix string, app *appsrv.Application) {
hostutils.InitWorkerManager()
app.AddHandler("POST",
fmt.Sprintf("%s/disks/image_cache", prefix),
auth.Authenticate(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
performImageCache(ctx, w, r, agent.agentImageCache.PrefetchImageCache)
}))
app.AddHandler("DELETE",
fmt.Sprintf("%s/disks/image_cache", prefix),
auth.Authenticate(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
performImageCache(ctx, w, r, agent.agentImageCache.DeleteImageCache)
}))
}
func performImageCache(
ctx context.Context,
w http.ResponseWriter,
r *http.Request,
performTask workmanager.DelayTaskFunc,
) {
_, _, body := appsrv.FetchEnv(ctx, w, r)
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "disk")
return
}
hostutils.DelayTask(ctx, performTask, disk)
hostutils.ResponseOk(ctx, w)
}
func Stop() error {
if EsxiAgent != nil {
log.Infof("EsxiAgent stop...")
tmpAgent := EsxiAgent
EsxiAgent = nil
tmpAgent.Stop()
}
return nil
}
+15
View File
@@ -0,0 +1,15 @@
// 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 esxi // import "yunion.io/x/onecloud/pkg/esxi"
+15
View File
@@ -0,0 +1,15 @@
// 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 handler // import "yunion.io/x/onecloud/pkg/esxi/handler"
+181
View File
@@ -0,0 +1,181 @@
// 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 handler
import (
"context"
"fmt"
"net/http"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/appctx"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/esxi"
"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"
)
const (
AGENT_PREFIX = "disks/agent"
)
func InitHandlers(app *appsrv.Application) {
initESXIHandler(app)
}
var defaultHandler = func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
httperrors.NotImplementedError(w, "")
return
}
func IdAgentPrefix(action string) string {
return fmt.Sprintf("%s/%s/<disk_id>", AGENT_PREFIX, action)
}
func AgentPrefix(action string) string {
return fmt.Sprintf("%s/%s", AGENT_PREFIX, action)
}
func initESXIHandler(app *appsrv.Application) {
app.AddHandler("POST", AgentPrefix("upload"), auth.Authenticate(uploadHandler))
app.AddHandler("POST", AgentPrefix("deploy"), auth.Authenticate(deployHandler))
app.AddHandler("POST", IdAgentPrefix("delete"), auth.Authenticate(deleteHandler))
app.AddHandler("POST", IdAgentPrefix("create"), auth.Authenticate(createHandler))
app.AddHandler("POST", IdAgentPrefix("save-prepare"), auth.Authenticate(savePrepareHandler))
app.AddHandler("POST", IdAgentPrefix("resize"), auth.Authenticate(resizeHandler))
app.AddHandler("POST", IdAgentPrefix("clone"), auth.Authenticate(defaultHandler))
app.AddHandler("POST", IdAgentPrefix("fetch"), auth.Authenticate(defaultHandler))
app.AddHandler("POST", IdAgentPrefix("post-migrate"), auth.Authenticate(defaultHandler))
app.AddHandler("POST", IdAgentPrefix("snapshot"), auth.Authenticate(defaultHandler))
app.AddHandler("POST", IdAgentPrefix("reset"), auth.Authenticate(defaultHandler))
app.AddHandler("POST", IdAgentPrefix("cleanup-snapshots"), auth.Authenticate(defaultHandler))
}
func uploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
_, _, body := appsrv.FetchEnv(ctx, w, r)
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "miss disk")
return
}
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.SaveToGlance, disk)
hostutils.ResponseOk(ctx, w)
}
func deployHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
log.Debugf("enter deployHandler")
_, _, body := appsrv.FetchEnv(ctx, w, r)
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "miss disk")
return
}
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.AgentDeployGuest, disk)
hostutils.ResponseOk(ctx, w)
}
func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
params, _, _ := appsrv.FetchEnv(ctx, w, r)
diskId := params["<disk_id>"]
disk := esxi.EsxiAgent.AgentStorage.GetDiskById(diskId)
if taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID); taskId == nil {
if disk != nil {
_, err := disk.Delete(ctx, nil)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
hostutils.ResponseOk(ctx, w)
return
}
}
hostutils.ResponseOk(ctx, w)
hostutils.DelayTask(ctx, disk.Delete, nil)
}
func createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.CreateDiskByDiskInfo,
storageman.SDiskCreateByDiskinfo{DiskId: disk.GetId(), Disk: disk, DiskInfo: diskInfo})
hostutils.ResponseOk(ctx, w)
}
func savePrepareHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID).(string)
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
hostutils.DelayTask(ctx, disk.PrepareSaveToGlance, storageman.PrepareSaveToGlanceParams{taskId, diskInfo})
hostutils.ResponseOk(ctx, w)
}
func resizeHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
hostutils.DelayTask(ctx, disk.Resize, diskInfo)
hostutils.ResponseOk(ctx, w)
}
/*
func fetchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
params, _, body := appsrv.FetchEnv(ctx, w, r)
diskId := params["<disk_id>"]
disk := esxi.EsxiAgent.AgentStorage.GetDiskById(diskId)
if disk != nil {
httperrors.GeneralServerError(w, httperrors.NewDuplicateResourceError("disk '%s'", diskId))
return
}
disk := esxi.EsxiAgent.AgentStorage.CreateDisk(diskId)
diskInfo, err := body.Get("disk")
if err != nil {
httperrors.InputParameterError(w, "miss disk")
}
url, err := diskInfo.GetString("url")
if err != nil {
httperrors.InputParameterError(w, "miss disk.url")
}
hostutils.DelayTask(ctx, disk.CreateFromUrl)
hostutils.ResponseOk(ctx, w)
}
*/
func diskAndDiskInfo(ctx context.Context, w http.ResponseWriter, r *http.Request) (storageman.IDisk, jsonutils.JSONObject, error) {
params, _, body := appsrv.FetchEnv(ctx, w, r)
diskId := params["<disk_id>"]
disk := esxi.EsxiAgent.AgentStorage.GetDiskById(diskId)
if disk == nil {
return nil, nil, httperrors.NewNotFoundError("disk '%s'", diskId)
}
diskInfo, err := body.Get("disk")
if err != nil {
return nil, nil, httperrors.NewMissingParameterError("miss disk")
}
return disk, diskInfo, nil
}
+15
View File
@@ -0,0 +1,15 @@
// 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 options // import "yunion.io/x/onecloud/pkg/esxi/options"
+38
View File
@@ -0,0 +1,38 @@
// 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 options
import common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
type EsxiOptions struct {
common_options.CommonOptions
ListenInterface string `help:"Master address of host server" default:"br0"`
ListenAddress string `help:"Host serve IP address to select when multiple address bind to ListenInterface"`
EsxiAgentPath string `default:"/opt/cloud/workspace/esxi_agent" help:"Path for esxi agent configuration files"`
ImageCachePath string `help:"Path for storing image caches"`
ImageCacheLimit int `help:"Maximal storage space for image caching, in GB" default:"20"`
AgentTempPath string `help:"Path for ESXI Agent"`
AgentTempLimit int `help:"Maximal storage space for ESXi agent, in GB" default:"20"`
LinuxDefaultRootUser bool `help:"Default account for Linux system is root" default:"false"`
WindowsDefaultAdminUser bool `help:"Default account for Windows system is Administrator" default:"true"`
DefaultImageSaveFormat string `help:"Default image save format, default is vmdk, canbe qcow2" default:"vmdk"`
Zone string `help:"Zone where the agent locates"`
DeployServerSocketPath string `help:"Deploy server listen socket path" default:"/var/run/deploy.sock"`
}
var (
Options EsxiOptions
)
+15
View File
@@ -0,0 +1,15 @@
// 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 service // import "yunion.io/x/onecloud/pkg/esxi/service"
+94
View File
@@ -0,0 +1,94 @@
// 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 service
import (
"os"
"path/filepath"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/appsrv"
app_common "yunion.io/x/onecloud/pkg/cloudcommon/app"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
options_common "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/cloudcommon/service"
"yunion.io/x/onecloud/pkg/esxi"
"yunion.io/x/onecloud/pkg/esxi/handler"
"yunion.io/x/onecloud/pkg/esxi/options"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
)
type SExsiAgentService struct {
service.SServiceBase
}
func New() *SExsiAgentService {
return &SExsiAgentService{}
}
func (s *SExsiAgentService) StartService() {
options_common.ParseOptions(&options.Options, os.Args, "esxiagent.conf", "esxiagent")
if len(options.Options.ImageCachePath) == 0 {
options.Options.ImageCachePath = filepath.Join(filepath.Dir(options.Options.EsxiAgentPath), "image_cache")
log.Infof("No cachepath, use default %s", options.Options.ImageCachePath)
err := os.MkdirAll(options.Options.ImageCachePath, 0760)
if err != nil {
log.Fatalf("fail to create ImageCachePath %s", options.Options.ImageCachePath)
}
}
if len(options.Options.AgentTempPath) == 0 {
options.Options.AgentTempPath = filepath.Join(filepath.Dir(options.Options.EsxiAgentPath), "agent_tmp")
log.Infof("No agent temp path, use default %s", options.Options.AgentTempPath)
err := os.MkdirAll(options.Options.AgentTempPath, 0760)
if err != nil {
log.Fatalf("fail to create AgentTempPath %s", options.Options.AgentTempPath)
}
}
// init lockman
s.InitLockman()
app_common.InitAuth(&options.Options.CommonOptions, func() {
log.Infof("auth complete")
})
fsdriver.Init(nil)
deployclient.Init(options.Options.DeployServerSocketPath)
app := app_common.InitApp(&options.Options.BaseOptions, false)
handler.InitHandlers(app)
s.startAgent(app)
app_common.ServeForeverWithCleanup(app, &options.Options.BaseOptions, func() {
esxi.Stop()
})
}
func (s *SExsiAgentService) startAgent(app *appsrv.Application) {
err := esxi.Start(app)
if err != nil {
log.Fatalf("Start agent error: %v", err)
}
}
func (s *SExsiAgentService) InitLockman() {
log.Infof("using inmemory lockman")
lm := lockman.NewInMemoryLockManager()
lockman.Init(lm)
}
+26
View File
@@ -0,0 +1,26 @@
package diskutils
import (
comapi "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
type IDisk interface {
Connect() bool
Disconnect() bool
MountRootfs() fsdriver.IRootFsDriver
UmountRootfs(driver fsdriver.IRootFsDriver)
}
func GetIDisk(params *apis.DeployParams) IDisk {
hypervisor := params.GuestDesc.Hypervisor
switch hypervisor {
case comapi.HYPERVISOR_KVM:
return NewKVMGuestDisk(params.DiskPath)
case comapi.HYPERVISOR_ESXI:
return NewVDDKDisk(params.VddkInfo, params.DiskPath)
default:
return NewKVMGuestDisk(params.DiskPath)
}
}
+8
View File
@@ -308,6 +308,10 @@ func (d *SKVMGuestDisk) DetectIsUEFISupport(rootfs fsdriver.IRootFsDriver) bool
return false
}
func (d *SKVMGuestDisk) MountRootfs() fsdriver.IRootFsDriver {
return d.MountKvmRootfs()
}
func (d *SKVMGuestDisk) MountKvmRootfs() fsdriver.IRootFsDriver {
return d.mountKvmRootfs(false)
}
@@ -340,6 +344,10 @@ func (d *SKVMGuestDisk) UmountKvmRootfs(fd fsdriver.IRootFsDriver) {
}
}
func (d *SKVMGuestDisk) UmountRootfs(fd fsdriver.IRootFsDriver) {
d.UmountKvmRootfs(fd)
}
func (d *SKVMGuestDisk) MakePartition(fs string) error {
return Mkpartition(d.nbdDev, fs)
}
+381
View File
@@ -0,0 +1,381 @@
// 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 diskutils
import (
"bytes"
"crypto/sha1"
"crypto/tls"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
)
const (
TMPDIR = "/tmp/vmware-root"
)
var (
MNT_PATTERN = regexp.MustCompile(`Disk flat file mounted under ([^\s]+)`)
)
type VDDKDisk struct {
Host string
Port int
User string
Passwd string
VmRef string
DiskPath string
FUseDir string
PartDirs []string
Proc *Command
Pid int
}
func NewVDDKDisk(vddkInfo *apis.VDDKConInfo, diskPath string) *VDDKDisk {
return &VDDKDisk{
Host: vddkInfo.Host,
Port: int(vddkInfo.Port),
User: vddkInfo.User,
Passwd: vddkInfo.Passwd,
VmRef: vddkInfo.Vmref,
DiskPath: diskPath,
}
}
type Command struct {
*exec.Cmd
done chan error
stdouterr *bytes.Buffer
stdin io.Writer
}
func NewCommand(name string, arg ...string) *Command {
cmd := Command{
Cmd: exec.Command(name, arg...),
done: make(chan error, 1),
}
cmd.stdouterr = bytes.NewBuffer([]byte{})
cmd.Stdout = cmd.stdouterr
cmd.Stderr = cmd.stdouterr
cmd.stdin, _ = cmd.StdinPipe()
return &cmd
}
func (c *Command) Send(msg []byte) error {
_, err := c.stdin.Write(msg)
return err
}
func (c *Command) Start() error {
if err := c.Cmd.Start(); err != nil {
return err
}
go func() {
c.done <- c.Cmd.Wait()
}()
return nil
}
func (c *Command) Exited() bool {
return len(c.done) == 1
}
// Wait will block
func (c *Command) Wait() error {
return <-c.done
}
func (c *Command) Kill() {
c.Process.Kill()
}
func execpath() string {
return "/opt/vmware-vddk/bin/vix-mntapi-sample"
}
func libdir() string {
return "/usr/lib/vmware"
}
func logpath(pid int) string {
return fmt.Sprintf("%s/vixDiskLib-%d.log", TMPDIR, pid)
}
func (vd *VDDKDisk) Connect() bool {
return true
}
func (vd *VDDKDisk) Disconnect() bool {
return true
}
func (vd *VDDKDisk) MountRootfs() fsdriver.IRootFsDriver {
if err := vd.Mount(); err == nil {
for _, mntPath := range vd.PartDirs {
part := newVDDKPartition(mntPath)
if fs := guestfs.DetectRootFs(part); fs != nil {
log.Infof("Use rootfs %s", fs)
return fs
}
}
}
return nil
}
func (vd *VDDKDisk) UmountRootfs(fd fsdriver.IRootFsDriver) {
err := vd.Umount()
if err != nil {
log.Errorf("VDDKDisk Umount failed: %s", err)
}
}
func (vd *VDDKDisk) ParsePartitions(buf string) error {
// Disk flat file mounted under /run/vmware/fuse/7673253059900458465
// Mounted Volume 1, Type 1, isMounted 1, symLink /tmp/vmware-root/7673253059900458465_1, numGuestMountPoints 0 (<null>)
// print buf
ms := MNT_PATTERN.FindAllStringSubmatch(buf, -1)
if len(ms) != 0 {
vd.FUseDir = ms[0][1]
diskId := filepath.Base(vd.FUseDir)
files, err := ioutil.ReadDir(TMPDIR)
if err != nil {
return errors.Wrapf(err, "ioutil.ReadDir for %s", TMPDIR)
}
for _, f := range files {
if strings.HasPrefix(f.Name(), diskId) {
vd.PartDirs = append(vd.PartDirs, filepath.Join(TMPDIR, f.Name()))
}
}
}
log.Infof("Fuse path: %s partitiaons: %s", vd.FUseDir, vd.PartDirs)
return nil
}
func (vd *VDDKDisk) Mount() (err error) {
defer func() {
if err == nil {
return
}
vd.Proc = nil
log.Errorf("Exec vix-mntapi-sample error: %s", err)
}()
err = vd.ExecProg()
if err != nil {
return errors.Wrap(err, "VDDKDisk.ExecProg")
}
err = vd.WaitMounted()
if err != nil {
return errors.Wrap(err, "VDDKDisk.Mount")
}
return nil
}
func (vd *VDDKDisk) Umount() error {
if vd.Proc != nil {
err := vd.Proc.Send([]byte{'y'})
if err != nil {
errors.Wrap(err, "send 'y' to VDDKDisk.Proc")
}
err = vd.Proc.Wait()
if err != nil {
return errors.Wrap(err, "vd.Proc.Wait")
}
}
if len(vd.FUseDir) != 0 {
for _, p := range append(vd.PartDirs, vd.FUseDir) {
vd.fuseUmount(p)
}
}
if vd.Pid != 0 {
logpath := logpath(vd.Pid)
_, err := os.Stat(logpath)
if err == nil || os.IsExist(err) {
os.Remove(logpath)
}
}
return nil
}
func (vd *VDDKDisk) fuseUmount(path string) {
maxTries, tried := 4, 0
_, err := os.Stat(path)
if err != nil && os.IsNotExist(err) {
// no such path
return
}
for tried < maxTries {
tried += 1
err := exec.Command("umount", path).Run()
if err != nil {
time.Sleep(time.Duration(tried) * 15 * time.Second)
log.Errorf("Fail to umount %s: %s", path, err)
continue
}
_, err = os.Stat(path)
if err == nil || os.IsExist(err) {
err = exec.Command("rm", "-rf", path).Run()
if err != nil {
time.Sleep(time.Duration(tried) * 15 * time.Second)
log.Errorf("Fail to umount %s: %s", path, err)
continue
}
}
}
}
func (vd *VDDKDisk) ExecProg() error {
thumb, err := vd.getServerCertThumbSha1(fmt.Sprintf("%s:%d", vd.Host, vd.Port))
if err != nil {
return errors.Wrapf(err, "Fail contact server %s", vd.Host)
}
cmd := NewCommand(execpath(), "-info", "-host", vd.Host, "-port", strconv.Itoa(vd.Port), "-user", vd.User,
"-password", vd.Passwd, "-mode", "nbd", "-thumb", thumb, "-vm", fmt.Sprintf("moref=%s", vd.VmRef), vd.DiskPath)
env := os.Environ()
env = append(env, fmt.Sprintf("LD_LIBRARY_PATH=%s", libdir()))
cmd.Env = env
vd.Proc = cmd
err = vd.Proc.Start()
if err != nil {
return errors.Wrap(err, "vd.Proc.Start")
}
vd.Pid = cmd.Process.Pid
return nil
}
// getServerCertBin try to obtain the remote ssl certificate
func (vd *VDDKDisk) getServerCertBin(addr string) ([]byte, error) {
rawConn, err := net.Dial("tcp", addr)
if err != nil {
return nil, errors.Wrapf(err, "net.Dial for addr '%s'", addr)
}
defer rawConn.Close()
// get the wrpped conn
sslWrappedConn := tls.Client(rawConn, &tls.Config{InsecureSkipVerify: true})
err = sslWrappedConn.Handshake()
if err != nil {
return nil, errors.Wrapf(err, "fail to complete ssl handshake with addr '%s'", addr)
}
return sslWrappedConn.ConnectionState().PeerCertificates[0].Raw, nil
}
func (vd *VDDKDisk) getServerCertThumbSha1(addr string) (string, error) {
certBin, err := vd.getServerCertBin(addr)
if err != nil {
return "", err
}
sha := sha1.Sum(certBin)
shaHex := hex.EncodeToString(sha[:])
length := len(shaHex) / 2 * 2
tmp := make([][]byte, 0, length)
for i := 1; i < length; i += 2 {
tmp = append(tmp, []byte{shaHex[i-1], shaHex[i]})
}
return string(bytes.Join(tmp, []byte{':'})), nil
}
func (vd *VDDKDisk) WaitMounted() error {
endStr := []byte("Do you want to procede to unmount the volume")
timeout := 30 * time.Second
endClock := time.After(timeout)
isEnd := false
Loop:
for !vd.Proc.Exited() {
select {
case <-endClock:
break Loop
default:
if bytes.Contains(vd.Proc.stdouterr.Bytes(), endStr) {
log.Debugf("find the mark")
isEnd = true
break Loop
}
}
// Reduce inspection density
time.Sleep(100 * time.Millisecond)
}
backup := vd.Proc.stdouterr.String()
err := vd.ParsePartitions(backup)
if err != nil {
return errors.Wrap(err, "VDDKDisk.ParsePartitions")
}
if vd.Proc.Exited() {
retCode := vd.Proc.ProcessState.ExitCode()
// ignore the error
vd.Proc.Kill()
vd.Proc = nil
return errors.Error(fmt.Sprintf("VDDKDisk prog exit error(%d): %s", retCode, backup))
} else if !isEnd {
// timeout
vd.Proc.Kill()
return errors.Error(fmt.Sprintf("VDDKDisk read timeout, program blocked"))
}
return nil
}
type VDDKPartition struct {
*guestfs.SLocalGuestFS
}
func (vp *VDDKPartition) Mount() bool {
log.Debugf("VDDKPartition.Mount not implement")
return true
}
func (vp *VDDKPartition) MountPartReadOnly() bool {
log.Debugf("VDDKPartition.MountPartReadOnly not implement")
return true
}
func (vp *VDDKPartition) Umount() bool {
log.Debugf("VDDKPartition.Umount not implement")
return true
}
func (vp *VDDKPartition) IsReadonly() bool {
return guestfs.IsPartitionReadonly(vp)
}
func (vp *VDDKPartition) GetPhysicalPartitionType() string {
log.Debugf("VDDKPartition.GetPhysicalPartitionType not implement")
return ""
}
func newVDDKPartition(mntPath string) *VDDKPartition {
return &VDDKPartition{guestfs.NewLocalGuestFS(mntPath)}
}
+208 -115
View File
@@ -46,6 +46,7 @@ type GuestDesc struct {
Nics []*Nic `protobuf:"bytes,4,rep,name=nics,proto3" json:"nics,omitempty"`
NicsStandby []*Nic `protobuf:"bytes,5,rep,name=nics_standby,json=nicsStandby,proto3" json:"nics_standby,omitempty"`
Disks []*Disk `protobuf:"bytes,6,rep,name=disks,proto3" json:"disks,omitempty"`
Hypervisor string `protobuf:"bytes,7,opt,name=Hypervisor,proto3" json:"Hypervisor,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -118,6 +119,13 @@ func (m *GuestDesc) GetDisks() []*Disk {
return nil
}
func (m *GuestDesc) GetHypervisor() string {
if m != nil {
return m.Hypervisor
}
return ""
}
type Disk struct {
DiskId string `protobuf:"bytes,1,opt,name=disk_id,json=diskId,proto3" json:"disk_id,omitempty"`
Driver string `protobuf:"bytes,2,opt,name=driver,proto3" json:"driver,omitempty"`
@@ -524,6 +532,77 @@ func (m *Nic) GetName() string {
return ""
}
type VDDKConInfo struct {
Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
User string `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"`
Passwd string `protobuf:"bytes,4,opt,name=passwd,proto3" json:"passwd,omitempty"`
Vmref string `protobuf:"bytes,5,opt,name=vmref,proto3" json:"vmref,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *VDDKConInfo) Reset() { *m = VDDKConInfo{} }
func (m *VDDKConInfo) String() string { return proto.CompactTextString(m) }
func (*VDDKConInfo) ProtoMessage() {}
func (*VDDKConInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{3}
}
func (m *VDDKConInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VDDKConInfo.Unmarshal(m, b)
}
func (m *VDDKConInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_VDDKConInfo.Marshal(b, m, deterministic)
}
func (m *VDDKConInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_VDDKConInfo.Merge(m, src)
}
func (m *VDDKConInfo) XXX_Size() int {
return xxx_messageInfo_VDDKConInfo.Size(m)
}
func (m *VDDKConInfo) XXX_DiscardUnknown() {
xxx_messageInfo_VDDKConInfo.DiscardUnknown(m)
}
var xxx_messageInfo_VDDKConInfo proto.InternalMessageInfo
func (m *VDDKConInfo) GetHost() string {
if m != nil {
return m.Host
}
return ""
}
func (m *VDDKConInfo) GetPort() int32 {
if m != nil {
return m.Port
}
return 0
}
func (m *VDDKConInfo) GetUser() string {
if m != nil {
return m.User
}
return ""
}
func (m *VDDKConInfo) GetPasswd() string {
if m != nil {
return m.Passwd
}
return ""
}
func (m *VDDKConInfo) GetVmref() string {
if m != nil {
return m.Vmref
}
return ""
}
type DeployInfo struct {
PublicKey *SSHKeys `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
Deploys []*DeployContent `protobuf:"bytes,2,rep,name=deploys,proto3" json:"deploys,omitempty"`
@@ -542,7 +621,7 @@ func (m *DeployInfo) Reset() { *m = DeployInfo{} }
func (m *DeployInfo) String() string { return proto.CompactTextString(m) }
func (*DeployInfo) ProtoMessage() {}
func (*DeployInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{3}
return fileDescriptor_05f09e103004e384, []int{4}
}
func (m *DeployInfo) XXX_Unmarshal(b []byte) error {
@@ -633,7 +712,7 @@ func (m *SSHKeys) Reset() { *m = SSHKeys{} }
func (m *SSHKeys) String() string { return proto.CompactTextString(m) }
func (*SSHKeys) ProtoMessage() {}
func (*SSHKeys) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{4}
return fileDescriptor_05f09e103004e384, []int{5}
}
func (m *SSHKeys) XXX_Unmarshal(b []byte) error {
@@ -695,7 +774,7 @@ func (m *DeployContent) Reset() { *m = DeployContent{} }
func (m *DeployContent) String() string { return proto.CompactTextString(m) }
func (*DeployContent) ProtoMessage() {}
func (*DeployContent) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{5}
return fileDescriptor_05f09e103004e384, []int{6}
}
func (m *DeployContent) XXX_Unmarshal(b []byte) error {
@@ -747,7 +826,7 @@ func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{6}
return fileDescriptor_05f09e103004e384, []int{7}
}
func (m *Empty) XXX_Unmarshal(b []byte) error {
@@ -785,7 +864,7 @@ func (m *DeployGuestFsResponse) Reset() { *m = DeployGuestFsResponse{} }
func (m *DeployGuestFsResponse) String() string { return proto.CompactTextString(m) }
func (*DeployGuestFsResponse) ProtoMessage() {}
func (*DeployGuestFsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{7}
return fileDescriptor_05f09e103004e384, []int{8}
}
func (m *DeployGuestFsResponse) XXX_Unmarshal(b []byte) error {
@@ -856,19 +935,20 @@ func (m *DeployGuestFsResponse) GetKey() string {
}
type DeployParams struct {
DiskPath string `protobuf:"bytes,1,opt,name=disk_path,json=diskPath,proto3" json:"disk_path,omitempty"`
GuestDesc *GuestDesc `protobuf:"bytes,2,opt,name=guest_desc,json=guestDesc,proto3" json:"guest_desc,omitempty"`
DeployInfo *DeployInfo `protobuf:"bytes,3,opt,name=deploy_info,json=deployInfo,proto3" json:"deploy_info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
DiskPath string `protobuf:"bytes,1,opt,name=disk_path,json=diskPath,proto3" json:"disk_path,omitempty"`
GuestDesc *GuestDesc `protobuf:"bytes,2,opt,name=guest_desc,json=guestDesc,proto3" json:"guest_desc,omitempty"`
DeployInfo *DeployInfo `protobuf:"bytes,3,opt,name=deploy_info,json=deployInfo,proto3" json:"deploy_info,omitempty"`
VddkInfo *VDDKConInfo `protobuf:"bytes,4,opt,name=vddk_info,json=vddkInfo,proto3" json:"vddk_info,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeployParams) Reset() { *m = DeployParams{} }
func (m *DeployParams) String() string { return proto.CompactTextString(m) }
func (*DeployParams) ProtoMessage() {}
func (*DeployParams) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{8}
return fileDescriptor_05f09e103004e384, []int{9}
}
func (m *DeployParams) XXX_Unmarshal(b []byte) error {
@@ -910,6 +990,13 @@ func (m *DeployParams) GetDeployInfo() *DeployInfo {
return nil
}
func (m *DeployParams) GetVddkInfo() *VDDKConInfo {
if m != nil {
return m.VddkInfo
}
return nil
}
type ResizeFsParams struct {
DiskPath string `protobuf:"bytes,1,opt,name=disk_path,json=diskPath,proto3" json:"disk_path,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -921,7 +1008,7 @@ func (m *ResizeFsParams) Reset() { *m = ResizeFsParams{} }
func (m *ResizeFsParams) String() string { return proto.CompactTextString(m) }
func (*ResizeFsParams) ProtoMessage() {}
func (*ResizeFsParams) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{9}
return fileDescriptor_05f09e103004e384, []int{10}
}
func (m *ResizeFsParams) XXX_Unmarshal(b []byte) error {
@@ -962,7 +1049,7 @@ func (m *FormatFsParams) Reset() { *m = FormatFsParams{} }
func (m *FormatFsParams) String() string { return proto.CompactTextString(m) }
func (*FormatFsParams) ProtoMessage() {}
func (*FormatFsParams) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{10}
return fileDescriptor_05f09e103004e384, []int{11}
}
func (m *FormatFsParams) XXX_Unmarshal(b []byte) error {
@@ -1018,7 +1105,7 @@ func (m *ReleaseInfo) Reset() { *m = ReleaseInfo{} }
func (m *ReleaseInfo) String() string { return proto.CompactTextString(m) }
func (*ReleaseInfo) ProtoMessage() {}
func (*ReleaseInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{11}
return fileDescriptor_05f09e103004e384, []int{12}
}
func (m *ReleaseInfo) XXX_Unmarshal(b []byte) error {
@@ -1079,7 +1166,7 @@ func (m *SaveToGlanceParams) Reset() { *m = SaveToGlanceParams{} }
func (m *SaveToGlanceParams) String() string { return proto.CompactTextString(m) }
func (*SaveToGlanceParams) ProtoMessage() {}
func (*SaveToGlanceParams) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{12}
return fileDescriptor_05f09e103004e384, []int{13}
}
func (m *SaveToGlanceParams) XXX_Unmarshal(b []byte) error {
@@ -1126,7 +1213,7 @@ func (m *SaveToGlanceResponse) Reset() { *m = SaveToGlanceResponse{} }
func (m *SaveToGlanceResponse) String() string { return proto.CompactTextString(m) }
func (*SaveToGlanceResponse) ProtoMessage() {}
func (*SaveToGlanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{13}
return fileDescriptor_05f09e103004e384, []int{14}
}
func (m *SaveToGlanceResponse) XXX_Unmarshal(b []byte) error {
@@ -1172,7 +1259,7 @@ func (m *ProbeImageInfoPramas) Reset() { *m = ProbeImageInfoPramas{} }
func (m *ProbeImageInfoPramas) String() string { return proto.CompactTextString(m) }
func (*ProbeImageInfoPramas) ProtoMessage() {}
func (*ProbeImageInfoPramas) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{14}
return fileDescriptor_05f09e103004e384, []int{15}
}
func (m *ProbeImageInfoPramas) XXX_Unmarshal(b []byte) error {
@@ -1217,7 +1304,7 @@ func (m *ImageInfo) Reset() { *m = ImageInfo{} }
func (m *ImageInfo) String() string { return proto.CompactTextString(m) }
func (*ImageInfo) ProtoMessage() {}
func (*ImageInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_05f09e103004e384, []int{15}
return fileDescriptor_05f09e103004e384, []int{16}
}
func (m *ImageInfo) XXX_Unmarshal(b []byte) error {
@@ -1291,6 +1378,7 @@ func init() {
proto.RegisterType((*GuestDesc)(nil), "apis.GuestDesc")
proto.RegisterType((*Disk)(nil), "apis.Disk")
proto.RegisterType((*Nic)(nil), "apis.Nic")
proto.RegisterType((*VDDKConInfo)(nil), "apis.VDDKConInfo")
proto.RegisterType((*DeployInfo)(nil), "apis.DeployInfo")
proto.RegisterType((*SSHKeys)(nil), "apis.SSHKeys")
proto.RegisterType((*DeployContent)(nil), "apis.DeployContent")
@@ -1309,102 +1397,107 @@ func init() {
func init() { proto.RegisterFile("deploy.proto", fileDescriptor_05f09e103004e384) }
var fileDescriptor_05f09e103004e384 = []byte{
// 1512 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xdd, 0x6e, 0x1b, 0x37,
0x16, 0x86, 0xfe, 0x47, 0x47, 0xb6, 0x6c, 0x33, 0xfe, 0x99, 0x28, 0x9b, 0x8d, 0x21, 0x60, 0x17,
0x46, 0x90, 0x18, 0x58, 0x67, 0x77, 0x6f, 0x16, 0x0b, 0x6c, 0x10, 0x6f, 0x52, 0x21, 0x4d, 0x60,
0x8c, 0x63, 0xf4, 0xae, 0x03, 0x6a, 0x86, 0x92, 0x59, 0xcf, 0x90, 0x03, 0x92, 0x63, 0x45, 0x7d,
0x88, 0x3e, 0x49, 0xaf, 0x02, 0xf4, 0xa6, 0x8f, 0xd1, 0xbb, 0xbe, 0x42, 0x9f, 0xa2, 0x38, 0x24,
0x67, 0x34, 0x4e, 0x02, 0x34, 0x37, 0xbd, 0x12, 0xcf, 0x77, 0x0e, 0xc9, 0xc3, 0xf3, 0xf3, 0x9d,
0x11, 0x6c, 0xa5, 0xac, 0xc8, 0xe4, 0xfa, 0xb4, 0x50, 0xd2, 0x48, 0xd2, 0xa5, 0x05, 0xd7, 0xd3,
0x9f, 0x5b, 0x30, 0x7c, 0x55, 0x32, 0x6d, 0xce, 0x99, 0x4e, 0x08, 0x81, 0xae, 0xa0, 0x39, 0x0b,
0x5b, 0xc7, 0xad, 0x93, 0x61, 0x64, 0xd7, 0x88, 0x95, 0x25, 0x4f, 0xc3, 0xb6, 0xc3, 0x70, 0x4d,
0x0e, 0xa1, 0x9f, 0xca, 0x9c, 0x72, 0x11, 0x76, 0x2c, 0xea, 0x25, 0xf2, 0x10, 0xba, 0x82, 0x27,
0x3a, 0xec, 0x1e, 0x77, 0x4e, 0x46, 0x67, 0xc3, 0x53, 0xbc, 0xe2, 0xf4, 0x2d, 0x4f, 0x22, 0x0b,
0x93, 0x27, 0xb0, 0x85, 0xbf, 0xb1, 0x36, 0x54, 0xa4, 0xf3, 0x75, 0xd8, 0xfb, 0xd8, 0x6c, 0x84,
0xea, 0x4b, 0xa7, 0x25, 0xc7, 0xd0, 0x4b, 0xb9, 0xbe, 0xd1, 0x61, 0xdf, 0x9a, 0x81, 0x33, 0x3b,
0xe7, 0xfa, 0x26, 0x72, 0x8a, 0xe9, 0xaf, 0x1d, 0xe8, 0xa2, 0x4c, 0x8e, 0x60, 0x80, 0x48, 0xcc,
0x53, 0xef, 0x7a, 0x1f, 0xc5, 0x99, 0x73, 0x54, 0xf1, 0x5b, 0xa6, 0xbc, 0xfb, 0x5e, 0x22, 0x0f,
0x01, 0x12, 0x9a, 0x5c, 0xb3, 0x38, 0x97, 0x29, 0xf3, 0x8f, 0x18, 0x5a, 0xe4, 0x8d, 0x4c, 0x19,
0xb9, 0x0f, 0x01, 0xe5, 0xd2, 0x29, 0xbb, 0x56, 0x39, 0xa0, 0x5c, 0x5a, 0x15, 0x81, 0xae, 0xe6,
0xdf, 0xb3, 0xb0, 0x77, 0xdc, 0x3a, 0xe9, 0x44, 0x76, 0x4d, 0x1e, 0xc1, 0xc8, 0xb0, 0xbc, 0xc8,
0xa8, 0x61, 0xe8, 0x42, 0xdf, 0xee, 0x80, 0x0a, 0x9a, 0xa5, 0x78, 0x1d, 0xcf, 0xe9, 0x92, 0xc5,
0x05, 0x35, 0xd7, 0xe1, 0xc0, 0x5d, 0x67, 0x91, 0x0b, 0x6a, 0xae, 0x51, 0xad, 0x8d, 0x54, 0x68,
0xc0, 0xd3, 0x30, 0x70, 0x6a, 0x8f, 0xcc, 0x52, 0xf2, 0x17, 0x18, 0xe6, 0x7c, 0xa9, 0xa8, 0xe1,
0x62, 0x19, 0x0e, 0x8f, 0x5b, 0x27, 0x41, 0xb4, 0x01, 0xc8, 0x63, 0xd8, 0x33, 0x54, 0x2d, 0x99,
0x89, 0x1b, 0x67, 0x80, 0x3d, 0x63, 0xc7, 0x29, 0x2e, 0xeb, 0x93, 0x08, 0x74, 0xad, 0x07, 0x23,
0x97, 0x4b, 0x5c, 0x63, 0x88, 0x16, 0x52, 0xe5, 0xd4, 0x84, 0x5b, 0x2e, 0x44, 0x4e, 0x22, 0xfb,
0xd0, 0xe3, 0x22, 0x65, 0xef, 0xc3, 0xed, 0xe3, 0xd6, 0x49, 0x2f, 0x72, 0x02, 0xf9, 0x1b, 0x8c,
0x73, 0xa6, 0x96, 0x2c, 0xd6, 0x82, 0x16, 0xfa, 0x5a, 0x9a, 0x70, 0x6c, 0x1d, 0xda, 0xb6, 0xe8,
0xa5, 0x07, 0xc9, 0x18, 0xda, 0x0b, 0x1d, 0xee, 0xd8, 0x03, 0xdb, 0x0b, 0x4d, 0xfe, 0x0a, 0x90,
0xcb, 0x52, 0x98, 0x42, 0x72, 0x61, 0xc2, 0x5d, 0x17, 0xa0, 0x0d, 0x42, 0x76, 0xa1, 0x93, 0xb2,
0xdb, 0x70, 0xcf, 0x2a, 0x70, 0x39, 0xfd, 0xad, 0x0b, 0x9d, 0xb7, 0x3c, 0x41, 0x4d, 0x4e, 0x13,
0x9f, 0x56, 0x5c, 0xe2, 0xd9, 0xbc, 0xf0, 0xf9, 0x6c, 0xf3, 0x02, 0x2d, 0x04, 0x33, 0x3e, 0x89,
0xb8, 0x24, 0x07, 0xd0, 0x17, 0xcc, 0x60, 0x1c, 0x5c, 0xf2, 0x7a, 0x82, 0x99, 0x59, 0x4a, 0x42,
0x18, 0xdc, 0x72, 0x65, 0x4a, 0x9a, 0xd9, 0xec, 0x05, 0x51, 0x25, 0xa2, 0x66, 0x49, 0x0d, 0x5b,
0xd1, 0xb5, 0x4f, 0x5e, 0x25, 0x5a, 0xc7, 0x84, 0xf6, 0x29, 0xc3, 0x65, 0xa3, 0xf6, 0x83, 0x3b,
0xb5, 0x7f, 0x08, 0x7d, 0x25, 0x4b, 0xc3, 0xb4, 0x4d, 0xd1, 0x30, 0xf2, 0x12, 0xe2, 0x7c, 0x61,
0xbb, 0xca, 0x25, 0xc5, 0x4b, 0x78, 0x67, 0x4e, 0xf5, 0x4d, 0xc6, 0x84, 0x4d, 0x47, 0x2f, 0xaa,
0xc4, 0x46, 0xd1, 0x6e, 0xdd, 0x29, 0xda, 0x43, 0xe8, 0xcf, 0x15, 0x4f, 0x97, 0xcc, 0xa6, 0x64,
0x18, 0x79, 0x09, 0xab, 0x7f, 0xc5, 0x95, 0xcd, 0xfb, 0xd8, 0x29, 0x50, 0x74, 0xe9, 0xbe, 0xcd,
0xa8, 0xb0, 0x79, 0xe8, 0x45, 0x76, 0x8d, 0xc5, 0xc4, 0x85, 0x61, 0x6a, 0x41, 0x13, 0xe6, 0x13,
0xb1, 0x01, 0x30, 0xb6, 0xf3, 0x95, 0x4d, 0x43, 0x2f, 0x6a, 0xcf, 0x57, 0x9b, 0x22, 0x20, 0xcd,
0x22, 0x78, 0x04, 0x23, 0x1f, 0xb9, 0x98, 0x17, 0x3a, 0xbc, 0x77, 0xdc, 0xc1, 0x74, 0x7a, 0x68,
0x56, 0x68, 0x34, 0x60, 0xef, 0x0d, 0x53, 0x82, 0x65, 0xe8, 0xd5, 0xbe, 0xcb, 0x77, 0x05, 0xcd,
0x52, 0xf2, 0x00, 0x86, 0x86, 0xd1, 0x3c, 0x5e, 0x71, 0x73, 0x1d, 0x1e, 0x58, 0x75, 0x80, 0xc0,
0x37, 0xdc, 0x55, 0x64, 0x4e, 0x05, 0xa6, 0xe9, 0xd0, 0xa6, 0xc9, 0x4b, 0xd8, 0x95, 0x82, 0x27,
0xb1, 0x59, 0x17, 0x2c, 0x3c, 0x72, 0x69, 0x12, 0x3c, 0x79, 0xb7, 0x2e, 0x6c, 0x08, 0x32, 0x2e,
0x6e, 0xe2, 0xb2, 0x08, 0x43, 0xb7, 0x07, 0xc5, 0x2b, 0x5b, 0x1c, 0xb9, 0x29, 0xc3, 0xfb, 0xb6,
0x5b, 0x71, 0x59, 0x73, 0xdc, 0x64, 0xc3, 0x71, 0xd3, 0x5f, 0xda, 0x00, 0xe7, 0x96, 0x1c, 0x67,
0x62, 0x21, 0xc9, 0x13, 0x80, 0xa2, 0x9c, 0x67, 0x3c, 0x89, 0x6f, 0xd8, 0xda, 0x96, 0xde, 0xe8,
0x6c, 0xdb, 0xd1, 0xcf, 0xe5, 0xe5, 0x57, 0xaf, 0xd9, 0x5a, 0x47, 0x43, 0x67, 0xf0, 0x9a, 0xad,
0xc9, 0x53, 0x18, 0x38, 0x62, 0xd5, 0x61, 0xdb, 0x32, 0xd5, 0x3d, 0xcf, 0x54, 0x16, 0x7c, 0x21,
0x85, 0x61, 0xc2, 0x44, 0x95, 0x0d, 0x99, 0x40, 0x50, 0x50, 0xad, 0x57, 0x52, 0xa5, 0xbe, 0x66,
0x6b, 0x19, 0x9f, 0xc1, 0x75, 0xcc, 0x05, 0x37, 0xb6, 0x72, 0x83, 0xa8, 0xcf, 0xf5, 0x4c, 0x70,
0x83, 0x0c, 0xc1, 0x04, 0x9d, 0x67, 0x2c, 0x36, 0x66, 0xed, 0xab, 0x77, 0xe8, 0x90, 0x77, 0x66,
0x8d, 0x1c, 0x90, 0xb2, 0x05, 0x2d, 0x33, 0x13, 0x2b, 0x29, 0x4d, 0x5c, 0x6a, 0xa6, 0x6c, 0x25,
0x07, 0xd1, 0x8e, 0x57, 0x44, 0x52, 0x9a, 0x2b, 0xcd, 0x14, 0xf9, 0x0f, 0x4c, 0x56, 0x5c, 0xa4,
0x72, 0xa5, 0xe3, 0x6a, 0x0f, 0x4d, 0x73, 0x2e, 0xdc, 0xa6, 0x81, 0xdd, 0x74, 0xe4, 0x2d, 0xce,
0x9d, 0xc1, 0x73, 0xd4, 0xdb, 0xcd, 0x8f, 0x61, 0xcf, 0xfb, 0x91, 0x64, 0xb2, 0x4c, 0x9d, 0xab,
0x81, 0xbb, 0xc8, 0x29, 0x5e, 0x20, 0x8e, 0x3e, 0x4f, 0x7f, 0x6c, 0xc1, 0xc0, 0x87, 0x0b, 0xfd,
0xff, 0x28, 0xa2, 0xc3, 0x66, 0x08, 0xad, 0xff, 0x19, 0x33, 0x2c, 0x6e, 0x58, 0xb9, 0x0e, 0xdf,
0x71, 0x8a, 0x8b, 0xda, 0xf6, 0x04, 0x76, 0x9d, 0xbf, 0x0d, 0x53, 0x17, 0xc7, 0xb1, 0xc5, 0x37,
0x96, 0x4f, 0x80, 0x14, 0x4a, 0x7e, 0xc7, 0x12, 0xd3, 0xb4, 0x75, 0x94, 0xb0, 0xeb, 0x35, 0xb5,
0xf5, 0xf4, 0x0a, 0xb6, 0xef, 0x64, 0xac, 0x26, 0xcb, 0x56, 0x83, 0x2c, 0x43, 0x18, 0x24, 0x4e,
0xed, 0xdd, 0xab, 0x44, 0x2c, 0x5a, 0x9a, 0x18, 0x2e, 0xeb, 0x91, 0xe8, 0xa4, 0xe9, 0x00, 0x7a,
0xff, 0xcf, 0x0b, 0xb3, 0x9e, 0xfe, 0xd4, 0x82, 0x03, 0x77, 0x81, 0x9d, 0xb7, 0x2f, 0x75, 0xc4,
0x74, 0x21, 0x85, 0x66, 0xb6, 0xdf, 0xb9, 0x36, 0x4a, 0x36, 0x86, 0x97, 0x51, 0xd2, 0xf2, 0x15,
0x53, 0x1a, 0xcf, 0xf4, 0x97, 0x79, 0x11, 0x5d, 0xa3, 0x2a, 0xb9, 0xf6, 0x57, 0xd9, 0x35, 0xd6,
0x55, 0x46, 0xc5, 0xb2, 0xa4, 0xcb, 0x6a, 0x66, 0xd5, 0x32, 0xb6, 0xb5, 0xd4, 0xb6, 0x6c, 0x86,
0x51, 0x5b, 0x6a, 0x3c, 0x99, 0x26, 0x09, 0xd2, 0x6f, 0xc5, 0x77, 0x5e, 0xc4, 0x7e, 0xc1, 0x20,
0x79, 0xbe, 0xbb, 0x61, 0xeb, 0xe9, 0x0f, 0x2d, 0xd8, 0x72, 0x7e, 0x5f, 0x50, 0x45, 0x73, 0x8d,
0xbd, 0x6b, 0x87, 0x6d, 0x23, 0x38, 0x01, 0x02, 0x76, 0x94, 0x9d, 0x02, 0x2c, 0xf1, 0x79, 0x71,
0xca, 0x74, 0x62, 0xdd, 0x1e, 0x9d, 0xed, 0xb8, 0x7e, 0xa8, 0x3f, 0x33, 0xa2, 0xe1, 0xb2, 0xfe,
0xe2, 0xf8, 0x07, 0x8c, 0x5c, 0x63, 0xc4, 0x5c, 0x2c, 0xa4, 0x7d, 0xd0, 0xe8, 0x6c, 0xb7, 0xd9,
0x40, 0xd8, 0x91, 0x11, 0xa4, 0xf5, 0x7a, 0xfa, 0x14, 0xc6, 0x11, 0xc3, 0xb9, 0xfb, 0x52, 0x7f,
0x81, 0x47, 0xd3, 0x6f, 0x61, 0xfc, 0xd2, 0x4e, 0xb4, 0x2f, 0x32, 0x47, 0xe5, 0x42, 0xc7, 0x7e,
0x22, 0xba, 0xb0, 0x07, 0x0b, 0xed, 0x4e, 0xa8, 0xbf, 0x85, 0x3a, 0x9b, 0x6f, 0xa1, 0xa9, 0x84,
0x51, 0xc4, 0x32, 0x46, 0x35, 0xb3, 0xdc, 0xf1, 0xa7, 0x27, 0x73, 0xfa, 0x06, 0xc8, 0x25, 0xbd,
0x65, 0xef, 0xe4, 0xab, 0x8c, 0x8a, 0x84, 0x7d, 0xc9, 0xa3, 0x26, 0x10, 0x24, 0x32, 0x2f, 0x14,
0xd3, 0xda, 0xde, 0x1e, 0x44, 0xb5, 0x3c, 0x65, 0xb0, 0xdf, 0x3c, 0xae, 0xae, 0xca, 0x23, 0x18,
0x48, 0xed, 0xb2, 0xe2, 0x5f, 0x22, 0xb5, 0x7d, 0xe1, 0x3f, 0x61, 0x4b, 0xb9, 0x07, 0x3b, 0xad,
0x4b, 0xf2, 0x9e, 0xcb, 0x59, 0x23, 0x14, 0xd1, 0x48, 0x6d, 0x84, 0xe9, 0x33, 0xd8, 0xbf, 0x50,
0x72, 0xce, 0x66, 0xf8, 0xd5, 0x83, 0xc8, 0x85, 0xa2, 0x39, 0xfd, 0x83, 0xdc, 0x7d, 0x68, 0xc3,
0xb0, 0xde, 0x40, 0x1e, 0xdf, 0xf5, 0xe8, 0xb3, 0x77, 0x56, 0x4e, 0x3a, 0xef, 0xed, 0xa8, 0x68,
0x57, 0xde, 0xdb, 0x49, 0xf1, 0x77, 0xd8, 0xe1, 0x3a, 0x2e, 0xd9, 0x82, 0xc7, 0xba, 0x2c, 0x0a,
0xa9, 0xdc, 0x97, 0x43, 0x10, 0x6d, 0x73, 0x7d, 0xc5, 0x16, 0xfc, 0xd2, 0x81, 0x48, 0x33, 0x5c,
0xc7, 0xd9, 0x6d, 0x1e, 0x17, 0x54, 0x19, 0x6e, 0x3b, 0xdb, 0x71, 0xf2, 0x98, 0xeb, 0xaf, 0x6f,
0xf3, 0x8b, 0x0a, 0xc5, 0x61, 0xc7, 0x75, 0xac, 0x18, 0x4d, 0xa5, 0xc8, 0x2a, 0x72, 0x06, 0xae,
0x23, 0x8f, 0x90, 0x7f, 0xc3, 0x51, 0x71, 0xbd, 0xd6, 0x3c, 0xa1, 0xd9, 0xe6, 0x30, 0xe7, 0x9b,
0xeb, 0xbe, 0x83, 0x4a, 0x5d, 0x1f, 0x6a, 0x5d, 0xfd, 0x17, 0x1c, 0xd9, 0x69, 0xa0, 0x0d, 0xcd,
0x32, 0x96, 0x36, 0x29, 0xd7, 0xd1, 0xf4, 0x3e, 0x4e, 0x07, 0xaf, 0xad, 0x79, 0xf7, 0xec, 0x43,
0x1b, 0x46, 0xae, 0x75, 0x9e, 0x2f, 0x91, 0x99, 0xfe, 0x57, 0x11, 0x9b, 0xe7, 0x1d, 0x42, 0x9a,
0xed, 0xe5, 0xca, 0x67, 0xf2, 0xa0, 0x89, 0x7d, 0x4c, 0x50, 0x4f, 0x21, 0xa8, 0x3a, 0x8e, 0xec,
0x57, 0x31, 0x6f, 0x76, 0xe0, 0x64, 0xe4, 0x50, 0xcb, 0x74, 0x68, 0x5e, 0x75, 0x5c, 0x65, 0x7e,
0xb7, 0x03, 0xef, 0x9a, 0x9f, 0xc3, 0x56, 0xb3, 0x00, 0x49, 0xe8, 0x27, 0xed, 0x27, 0x35, 0x3e,
0x99, 0x7c, 0xaa, 0xa9, 0x7d, 0xfc, 0x2f, 0x8c, 0xef, 0xd6, 0x17, 0xf1, 0xd6, 0x9f, 0xab, 0xba,
0x89, 0xa7, 0xa4, 0x1a, 0x9e, 0xf7, 0xed, 0x9f, 0xa2, 0x67, 0xbf, 0x07, 0x00, 0x00, 0xff, 0xff,
0xdf, 0xa7, 0xb1, 0x31, 0x24, 0x0d, 0x00, 0x00,
// 1591 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6e, 0x23, 0xb9,
0x11, 0x86, 0xfe, 0xd5, 0x25, 0x8f, 0xec, 0xe1, 0x7a, 0xc6, 0xbd, 0xda, 0x6c, 0xd6, 0x10, 0x90,
0xc0, 0x18, 0xcc, 0x18, 0x88, 0x37, 0xc9, 0x25, 0x08, 0x90, 0xc5, 0x38, 0xb3, 0x2b, 0x4c, 0x76,
0x61, 0xb4, 0xc7, 0xc9, 0x2d, 0x0d, 0xba, 0x9b, 0x92, 0x18, 0x77, 0x93, 0x0d, 0x92, 0x92, 0x56,
0x79, 0xa6, 0x9c, 0x16, 0xc8, 0x35, 0x0f, 0x91, 0x5b, 0xf2, 0x08, 0x79, 0x8a, 0xa0, 0x8a, 0xec,
0x56, 0x7b, 0x76, 0x80, 0xcc, 0x25, 0x27, 0x55, 0x7d, 0x55, 0x24, 0x8b, 0xf5, 0xf3, 0xb1, 0x05,
0x47, 0xb9, 0xa8, 0x0a, 0xbd, 0xbf, 0xac, 0x8c, 0x76, 0x9a, 0xf5, 0x79, 0x25, 0xed, 0xfc, 0xdf,
0x1d, 0x88, 0xbe, 0xde, 0x08, 0xeb, 0xae, 0x85, 0xcd, 0x18, 0x83, 0xbe, 0xe2, 0xa5, 0x88, 0x3b,
0xe7, 0x9d, 0x8b, 0x28, 0x21, 0x19, 0xb1, 0xcd, 0x46, 0xe6, 0x71, 0xd7, 0x63, 0x28, 0xb3, 0xe7,
0x30, 0xcc, 0x75, 0xc9, 0xa5, 0x8a, 0x7b, 0x84, 0x06, 0x8d, 0x7d, 0x0e, 0x7d, 0x25, 0x33, 0x1b,
0xf7, 0xcf, 0x7b, 0x17, 0x93, 0xab, 0xe8, 0x12, 0x8f, 0xb8, 0xfc, 0x4e, 0x66, 0x09, 0xc1, 0xec,
0x25, 0x1c, 0xe1, 0x6f, 0x6a, 0x1d, 0x57, 0xf9, 0xfd, 0x3e, 0x1e, 0xbc, 0xef, 0x36, 0x41, 0xf3,
0xad, 0xb7, 0xb2, 0x73, 0x18, 0xe4, 0xd2, 0x3e, 0xd8, 0x78, 0x48, 0x6e, 0xe0, 0xdd, 0xae, 0xa5,
0x7d, 0x48, 0xbc, 0x81, 0xfd, 0x14, 0xe0, 0x9b, 0x7d, 0x25, 0xcc, 0x56, 0x5a, 0x6d, 0xe2, 0x11,
0x85, 0xd2, 0x42, 0xe6, 0xff, 0xea, 0x41, 0x1f, 0xfd, 0xd9, 0x19, 0x8c, 0x70, 0x45, 0x2a, 0xf3,
0x70, 0xb5, 0x21, 0xaa, 0x0b, 0x7f, 0x11, 0x23, 0xb7, 0xc2, 0x84, 0xeb, 0x05, 0x8d, 0x7d, 0x0e,
0x90, 0xf1, 0x6c, 0x2d, 0xd2, 0x52, 0xe7, 0x22, 0x5c, 0x32, 0x22, 0xe4, 0x5b, 0x9d, 0x0b, 0xf6,
0x29, 0x8c, 0xb9, 0xd4, 0xde, 0xd8, 0x27, 0xe3, 0x88, 0x4b, 0x4d, 0x26, 0x06, 0x7d, 0x2b, 0xff,
0x2a, 0xe2, 0xc1, 0x79, 0xe7, 0xa2, 0x97, 0x90, 0xcc, 0xbe, 0x80, 0x89, 0x13, 0x65, 0x55, 0x70,
0x27, 0x30, 0x84, 0xa1, 0x0f, 0xb4, 0x86, 0x16, 0x39, 0x1e, 0x27, 0x4b, 0xbe, 0x12, 0x69, 0xc5,
0xdd, 0x3a, 0x5c, 0x24, 0x22, 0xe4, 0x86, 0xbb, 0x35, 0x9a, 0xad, 0xd3, 0x06, 0x1d, 0x64, 0x1e,
0x8f, 0xbd, 0x39, 0x20, 0x8b, 0x9c, 0xfd, 0x04, 0xa2, 0x52, 0xae, 0x0c, 0x77, 0x52, 0xad, 0xe2,
0xe8, 0xbc, 0x73, 0x31, 0x4e, 0x0e, 0x00, 0x7b, 0x01, 0x4f, 0x1d, 0x37, 0x2b, 0xe1, 0xd2, 0xd6,
0x1e, 0x40, 0x7b, 0x1c, 0x7b, 0xc3, 0x6d, 0xb3, 0x13, 0x83, 0x3e, 0x45, 0x30, 0xf1, 0xb5, 0x46,
0x19, 0x53, 0xb4, 0xd4, 0xa6, 0xe4, 0x2e, 0x3e, 0xf2, 0x29, 0xf2, 0x1a, 0x3b, 0x85, 0x81, 0x54,
0xb9, 0xf8, 0x3e, 0x7e, 0x72, 0xde, 0xb9, 0x18, 0x24, 0x5e, 0x61, 0x3f, 0x83, 0x69, 0x29, 0xcc,
0x4a, 0xa4, 0x56, 0xf1, 0xca, 0xae, 0xb5, 0x8b, 0xa7, 0x14, 0xd0, 0x13, 0x42, 0x6f, 0x03, 0xc8,
0xa6, 0xd0, 0x5d, 0xda, 0xf8, 0x98, 0x36, 0xec, 0x2e, 0xa9, 0x92, 0xa5, 0xde, 0x28, 0x57, 0x69,
0xa9, 0x5c, 0x7c, 0xe2, 0x13, 0x74, 0x40, 0xd8, 0x09, 0xf4, 0x72, 0xb1, 0x8d, 0x9f, 0x92, 0x01,
0xc5, 0xf9, 0x7f, 0xfa, 0xd0, 0xfb, 0x4e, 0x66, 0x68, 0x29, 0x79, 0x16, 0xca, 0x8a, 0x22, 0xee,
0x2d, 0xab, 0x50, 0xcf, 0xae, 0xac, 0xd0, 0x43, 0x09, 0x17, 0x8a, 0x88, 0x22, 0x7b, 0x06, 0x43,
0x25, 0x1c, 0xe6, 0xc1, 0x17, 0x6f, 0xa0, 0x84, 0x5b, 0xe4, 0x2c, 0x86, 0xd1, 0x56, 0x1a, 0xb7,
0xe1, 0x05, 0x55, 0x6f, 0x9c, 0xd4, 0x2a, 0x5a, 0x56, 0xdc, 0x89, 0x1d, 0xdf, 0x87, 0xe2, 0xd5,
0x2a, 0x05, 0xa6, 0x6c, 0x28, 0x19, 0x8a, 0xad, 0xd9, 0x18, 0x3f, 0x9a, 0x8d, 0xe7, 0x30, 0x34,
0x7a, 0xe3, 0x84, 0xa5, 0x12, 0x45, 0x49, 0xd0, 0x10, 0x97, 0x4b, 0x9a, 0x3a, 0x5f, 0x94, 0xa0,
0xe1, 0x99, 0x25, 0xb7, 0x0f, 0x85, 0x50, 0x54, 0x8e, 0x41, 0x52, 0xab, 0xad, 0xa6, 0x3d, 0x7a,
0xd4, 0xb4, 0xcf, 0x61, 0x78, 0x6f, 0x64, 0xbe, 0x12, 0x54, 0x92, 0x28, 0x09, 0x1a, 0x76, 0xff,
0x4e, 0x1a, 0xaa, 0xfb, 0xd4, 0x1b, 0x50, 0xf5, 0xe5, 0xde, 0x16, 0x5c, 0x51, 0x1d, 0x06, 0x09,
0xc9, 0xd8, 0x4c, 0x52, 0x39, 0x61, 0x96, 0x3c, 0x13, 0xa1, 0x10, 0x07, 0x00, 0x73, 0x7b, 0xbf,
0xa3, 0x32, 0x0c, 0x92, 0xee, 0xfd, 0xee, 0xd0, 0x04, 0xac, 0xdd, 0x04, 0x5f, 0xc0, 0x24, 0x64,
0x2e, 0x95, 0x95, 0x8d, 0x3f, 0x39, 0xef, 0x61, 0x39, 0x03, 0xb4, 0xa8, 0x2c, 0x3a, 0x88, 0xef,
0x9d, 0x30, 0x4a, 0x14, 0x18, 0xd5, 0xa9, 0xaf, 0x77, 0x0d, 0x2d, 0x72, 0xf6, 0x19, 0x44, 0x4e,
0xf0, 0x32, 0xdd, 0x49, 0xb7, 0x8e, 0x9f, 0x91, 0x79, 0x8c, 0xc0, 0x9f, 0xa4, 0xef, 0xc8, 0x92,
0x2b, 0x2c, 0xd3, 0x73, 0x2a, 0x53, 0xd0, 0x70, 0x2a, 0x95, 0xcc, 0x52, 0xb7, 0xaf, 0x44, 0x7c,
0xe6, 0xcb, 0xa4, 0x64, 0xf6, 0x6e, 0x5f, 0x51, 0x0a, 0x0a, 0xa9, 0x1e, 0xd2, 0x4d, 0x15, 0xc7,
0x7e, 0x0d, 0xaa, 0x77, 0xd4, 0x1c, 0xa5, 0xdb, 0xc4, 0x9f, 0xd2, 0xb4, 0xa2, 0xd8, 0x70, 0xe0,
0xec, 0xc0, 0x81, 0xf3, 0x1d, 0x4c, 0xfe, 0x78, 0x7d, 0xfd, 0xf6, 0xb5, 0x56, 0x0b, 0xb5, 0xd4,
0xe8, 0xb2, 0xd6, 0xd6, 0xd5, 0x34, 0x89, 0x32, 0x8d, 0x8e, 0x36, 0x8e, 0xfa, 0x6e, 0x90, 0x90,
0x4c, 0xd4, 0x69, 0x85, 0x09, 0xad, 0x47, 0x32, 0x06, 0x5f, 0x71, 0x6b, 0x77, 0x75, 0xef, 0x05,
0x0d, 0x33, 0xb9, 0x2d, 0x8d, 0x58, 0x52, 0xeb, 0x45, 0x89, 0x57, 0xe6, 0xff, 0xec, 0x02, 0x5c,
0x13, 0x6b, 0xd3, 0xc1, 0x2f, 0x01, 0xaa, 0xcd, 0x7d, 0x21, 0xb3, 0xf4, 0x41, 0xec, 0xe9, 0xf8,
0xc9, 0xd5, 0x13, 0xcf, 0x8b, 0xb7, 0xb7, 0xdf, 0xbc, 0x15, 0x7b, 0x9b, 0x44, 0xde, 0xe1, 0xad,
0xd8, 0xb3, 0x57, 0x30, 0xf2, 0x8c, 0x6f, 0xe3, 0x2e, 0x51, 0xe8, 0x27, 0x81, 0x42, 0x09, 0x7c,
0xad, 0x95, 0x13, 0xca, 0x25, 0xb5, 0x0f, 0x9b, 0xc1, 0x98, 0x62, 0xd1, 0x26, 0x0f, 0x11, 0x37,
0x3a, 0xe6, 0x4f, 0xda, 0x54, 0x2a, 0xe9, 0x28, 0xec, 0x71, 0x32, 0x94, 0x76, 0xa1, 0xa4, 0x43,
0x6a, 0x12, 0x8a, 0xdf, 0x17, 0x22, 0x75, 0x6e, 0x1f, 0xc6, 0x26, 0xf2, 0xc8, 0x3b, 0xb7, 0x47,
0xf2, 0xc9, 0xc5, 0x92, 0x6f, 0x0a, 0x97, 0x1a, 0xad, 0x5d, 0x4a, 0xe9, 0x18, 0x92, 0xd7, 0x71,
0x30, 0x24, 0x5a, 0xbb, 0x3b, 0xcc, 0xcc, 0x6f, 0x60, 0xb6, 0x93, 0x2a, 0xd7, 0x3b, 0x9b, 0xd6,
0x6b, 0x78, 0x5e, 0x4a, 0xe5, 0x17, 0x8d, 0x68, 0xd1, 0x59, 0xf0, 0xb8, 0xf6, 0x0e, 0x5f, 0xa1,
0x9d, 0x16, 0xbf, 0x80, 0xa7, 0x21, 0x8e, 0xac, 0xd0, 0x9b, 0xdc, 0x87, 0x3a, 0xf6, 0x07, 0x79,
0xc3, 0x6b, 0xc4, 0x31, 0xe6, 0xf9, 0xdf, 0x3a, 0x30, 0x0a, 0xe9, 0xc2, 0xf8, 0xdf, 0xcb, 0x68,
0xd4, 0x4e, 0x21, 0xc5, 0x5f, 0x08, 0x27, 0xd2, 0x96, 0x97, 0xa7, 0x96, 0x63, 0x6f, 0xb8, 0x69,
0x7c, 0x2f, 0xe0, 0xc4, 0xc7, 0xdb, 0x72, 0xf5, 0x79, 0x9c, 0x12, 0x7e, 0xf0, 0x7c, 0x09, 0xac,
0x32, 0xfa, 0x2f, 0x22, 0x73, 0x6d, 0x5f, 0xdf, 0x0f, 0x27, 0xc1, 0xd2, 0x78, 0xcf, 0xef, 0xe0,
0xc9, 0xa3, 0x8a, 0x35, 0x2c, 0xdd, 0x69, 0xb1, 0x74, 0x0c, 0xa3, 0xcc, 0x9b, 0x43, 0x78, 0xb5,
0x8a, 0x0d, 0xc7, 0x33, 0x27, 0x75, 0xf3, 0x56, 0x7b, 0x6d, 0x3e, 0x82, 0xc1, 0xef, 0xcb, 0xca,
0xed, 0xe7, 0x7f, 0xef, 0xc0, 0x33, 0x7f, 0x00, 0x7d, 0x08, 0xbc, 0xb1, 0x89, 0xb0, 0x95, 0x56,
0x56, 0x10, 0xd1, 0x48, 0xeb, 0x8c, 0x6e, 0xbd, 0x9a, 0xce, 0x68, 0x22, 0x4a, 0x61, 0x2c, 0xee,
0x19, 0x0e, 0x0b, 0x2a, 0x86, 0xc6, 0x4d, 0xb6, 0xae, 0x3b, 0x1e, 0x65, 0xec, 0xab, 0x82, 0xab,
0xd5, 0x86, 0xaf, 0xea, 0xc7, 0xb2, 0xd1, 0x91, 0x4f, 0xb4, 0x0d, 0x2d, 0xdf, 0xd5, 0x16, 0x77,
0xe6, 0x59, 0x86, 0xbc, 0x5f, 0x13, 0x6d, 0x50, 0x71, 0x50, 0x31, 0x49, 0x81, 0x68, 0x1f, 0xc4,
0x7e, 0xfe, 0x8f, 0x0e, 0x1c, 0xf9, 0xb8, 0x6f, 0xb8, 0xe1, 0xa5, 0x45, 0xd2, 0xa0, 0x57, 0xbe,
0x95, 0x9c, 0x31, 0x02, 0xf4, 0x86, 0x5e, 0x02, 0xac, 0xf0, 0x7a, 0x69, 0x2e, 0x6c, 0x46, 0x61,
0x4f, 0xae, 0x8e, 0xfd, 0x3c, 0x34, 0xdf, 0x3f, 0x49, 0xb4, 0x6a, 0x3e, 0x85, 0x7e, 0x01, 0x13,
0x3f, 0x18, 0xa9, 0x54, 0x4b, 0x4d, 0x17, 0x9a, 0x5c, 0x9d, 0xb4, 0x07, 0x08, 0x27, 0x32, 0x81,
0xfc, 0x30, 0x9d, 0x97, 0x10, 0x6d, 0xf3, 0xfc, 0xc1, 0x2f, 0xe8, 0xd3, 0x82, 0xa7, 0x7e, 0x41,
0x8b, 0x3c, 0x92, 0x31, 0xfa, 0xa0, 0x34, 0x7f, 0x05, 0xd3, 0x44, 0xe0, 0x07, 0xc2, 0x1b, 0xfb,
0x11, 0x37, 0x98, 0xff, 0x19, 0xa6, 0x6f, 0xe8, 0xe9, 0xfd, 0x28, 0x77, 0x34, 0x2e, 0x6d, 0x1a,
0x9e, 0x6e, 0x5f, 0xa6, 0xf1, 0xd2, 0xfa, 0x1d, 0x9a, 0x8f, 0xba, 0xde, 0xe1, 0xa3, 0x6e, 0xae,
0x61, 0x92, 0x88, 0x42, 0x70, 0x2b, 0xe8, 0x36, 0xff, 0xf7, 0xe2, 0xcf, 0xbf, 0x05, 0x76, 0xcb,
0xb7, 0xe2, 0x9d, 0xfe, 0xba, 0xe0, 0x2a, 0x13, 0x1f, 0x73, 0xa9, 0x19, 0x8c, 0x33, 0x5d, 0x56,
0x46, 0x58, 0x4b, 0xa7, 0x8f, 0x93, 0x46, 0x9f, 0x0b, 0x38, 0x6d, 0x6f, 0xd7, 0x74, 0xf1, 0x19,
0x8c, 0xb4, 0xf5, 0x45, 0x09, 0x37, 0xd1, 0x96, 0x6e, 0xf8, 0x4b, 0x38, 0x32, 0xfe, 0xc2, 0xde,
0xda, 0x6d, 0x97, 0xac, 0x95, 0x8a, 0x64, 0x62, 0x0e, 0xca, 0xfc, 0x4b, 0x38, 0xbd, 0x31, 0xfa,
0x5e, 0x2c, 0xf0, 0xf3, 0x0c, 0x91, 0x1b, 0xc3, 0x4b, 0xfe, 0x3f, 0x6a, 0xf7, 0x43, 0x17, 0xa2,
0x66, 0x01, 0x7b, 0xf1, 0x38, 0xa2, 0x0f, 0x9e, 0x59, 0x07, 0xe9, 0xa3, 0xa7, 0x37, 0xad, 0x5b,
0x47, 0x4f, 0x4f, 0xda, 0xcf, 0xe1, 0x58, 0xda, 0x74, 0x23, 0x96, 0x32, 0xb5, 0x9b, 0x8a, 0xde,
0x9e, 0x9e, 0xff, 0xd4, 0x92, 0xf6, 0x4e, 0x2c, 0xe5, 0xad, 0x07, 0x91, 0x96, 0xa4, 0x4d, 0x8b,
0x6d, 0x99, 0x56, 0xdc, 0x38, 0x49, 0x4c, 0xe0, 0x39, 0x7c, 0x2a, 0xed, 0x1f, 0xb6, 0xe5, 0x4d,
0x8d, 0xe2, 0xab, 0x2c, 0x6d, 0x6a, 0x04, 0xcf, 0xb5, 0x2a, 0x6a, 0x32, 0x07, 0x69, 0x93, 0x80,
0xb0, 0x5f, 0xc3, 0x59, 0xb5, 0xde, 0x5b, 0x99, 0xf1, 0xe2, 0xb0, 0x99, 0x8f, 0xcd, 0x4f, 0xeb,
0xb3, 0xda, 0xdc, 0x6c, 0x4a, 0xa1, 0xfe, 0x0a, 0xce, 0xe8, 0xf5, 0xb0, 0x8e, 0x17, 0x85, 0xc8,
0xdb, 0x14, 0xed, 0x69, 0xfd, 0x14, 0x5f, 0x93, 0x60, 0x6d, 0x78, 0xfa, 0xea, 0x87, 0x2e, 0x4c,
0xfc, 0xa8, 0x7d, 0xb5, 0x42, 0x26, 0xfb, 0x5d, 0x4d, 0x84, 0x81, 0xa7, 0x18, 0x6b, 0x8f, 0xa3,
0x6f, 0x9f, 0xd9, 0x67, 0x6d, 0xec, 0x7d, 0x42, 0x7b, 0x05, 0xe3, 0x7a, 0xe2, 0xd8, 0x69, 0x9d,
0xf3, 0xf6, 0x04, 0xce, 0x26, 0x1e, 0x25, 0x66, 0x44, 0xf7, 0x7a, 0xe2, 0x6a, 0xf7, 0xc7, 0x13,
0xf8, 0xd8, 0xfd, 0x1a, 0x8e, 0xda, 0x0d, 0xc8, 0xe2, 0xf0, 0x32, 0xff, 0xa8, 0xc7, 0x67, 0xb3,
0x1f, 0x5b, 0x9a, 0x18, 0x7f, 0x0b, 0xd3, 0xc7, 0xfd, 0xc5, 0x82, 0xf7, 0x87, 0xba, 0x6e, 0x16,
0x28, 0xac, 0x81, 0xef, 0x87, 0xf4, 0xef, 0xee, 0xcb, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xb9,
0xf7, 0xec, 0x82, 0xed, 0x0d, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
+11 -1
View File
@@ -10,6 +10,8 @@ message GuestDesc {
repeated Nic nics = 4;
repeated Nic nics_standby = 5;
repeated Disk disks = 6;
string Hypervisor = 7;
}
message Disk {
@@ -32,7 +34,6 @@ message Disk {
string dev = 17;
}
message Nic {
string mac = 1;
string ip = 2;
@@ -62,6 +63,14 @@ message Nic {
string name = 26;
}
message VDDKConInfo {
string host = 1;
int32 port = 2;
string user = 3;
string passwd = 4;
string vmref = 5;
}
message DeployInfo {
SSHKeys public_key = 1;
repeated DeployContent deploys = 2;
@@ -103,6 +112,7 @@ message DeployParams {
string disk_path = 1;
GuestDesc guest_desc = 2;
DeployInfo deploy_info = 3;
VDDKConInfo vddk_info = 4;
}
message ResizeFsParams {
@@ -16,17 +16,19 @@ package deployserver
import (
"context"
"errors"
"fmt"
"net"
"os"
"runtime/debug"
"strings"
"google.golang.org/grpc"
execlient "yunion.io/x/executor/client"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
comapi "yunion.io/x/onecloud/pkg/apis/compute"
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/cloudcommon/service"
"yunion.io/x/onecloud/pkg/hostman/diskutils"
@@ -43,21 +45,35 @@ import (
type DeployerServer struct{}
func (*DeployerServer) DeployGuestFs(ctx context.Context, req *deployapi.DeployParams,
) (*deployapi.DeployGuestFsResponse, error) {
) (res *deployapi.DeployGuestFsResponse, err error) {
// There will be some occasional unknown panic, so temporarily capture panic here.
defer func() {
if r := recover(); r != nil {
log.Errorf("DeployGuestFs: %s", r)
debug.PrintStack()
msg := "panic: "
if str, ok := r.(fmt.Stringer); ok {
msg += str.String()
}
res, err = nil, errors.Error(msg)
}
}()
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
var disk = diskutils.GetIDisk(req)
if len(req.GuestDesc.Hypervisor) == 0 {
req.GuestDesc.Hypervisor = comapi.HYPERVISOR_KVM
}
root := kvmDisk.MountKvmRootfs()
defer disk.Disconnect()
if !disk.Connect() {
log.Infof("Failed to connect %s disk", req.GuestDesc.Hypervisor)
return new(deployapi.DeployGuestFsResponse), errors.Error("disk connect failed")
}
root := disk.MountRootfs()
if root == nil {
log.Infof("Failed mounting rootfs for kvm disk")
return new(deployapi.DeployGuestFsResponse), nil
log.Infof("Failed mounting rootfs for %s disk", req.GuestDesc.Hypervisor)
return new(deployapi.DeployGuestFsResponse), errors.Error("rootfs mount failed")
}
defer kvmDisk.UmountKvmRootfs(root)
defer disk.UmountRootfs(root)
ret, err := guestfs.DoDeployGuestFs(root, req.GuestDesc, req.DeployInfo)
if err != nil {
@@ -75,7 +91,7 @@ func (*DeployerServer) ResizeFs(ctx context.Context, req *deployapi.ResizeFsPara
disk := diskutils.NewKVMGuestDisk(req.DiskPath)
defer disk.Disconnect()
if !disk.Connect() {
return new(deployapi.Empty), errors.New("resize fs disk connect failed")
return new(deployapi.Empty), errors.Error("resize fs disk connect failed")
}
root := disk.MountKvmRootfs()
@@ -166,7 +182,7 @@ func (*DeployerServer) ProbeImageInfo(ctx context.Context, req *deployapi.ProbeI
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")
return new(deployapi.ImageInfo), errors.Error("Disk connector failed to connect image")
}
// Fsck is executed during mount
+117
View File
@@ -0,0 +1,117 @@
// 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 storageman
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/multicloud/esxi"
)
type SAgentDisk struct {
SLocalDisk
}
func NewAgentDisk(storage IStorage, id string) *SAgentDisk {
return &SAgentDisk{*NewLocalDisk(storage, id)}
}
type PrepareSaveToGlanceParams struct {
TaskId string
DiskInfo jsonutils.JSONObject
}
func (sd *SAgentDisk) PrepareSaveToGlance(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
p, ok := params.(PrepareSaveToGlanceParams)
if !ok {
return nil, errors.Wrap(hostutils.ParamsError, "Resize params format error")
}
storage := sd.Storage.(*SAgentStorage)
return storage.PrepareSaveToGlance(ctx, p.TaskId, p.DiskInfo)
}
func (sd *SAgentDisk) ReSize(ctx context.Context, diskInfo interface{}) (jsonutils.JSONObject, error) {
body, ok := diskInfo.(*jsonutils.JSONDict)
if !ok {
return nil, errors.Wrap(hostutils.ParamsError, "PrepareSaveToGlance params format error")
}
// check parameters
params := []string{"size", "host_info", "vm_private_id", "disk_private_id"}
for _, param := range params {
if !body.Contains(param) {
return nil, httperrors.NewMissingParameterError(param)
}
}
type sResize struct {
SizeMb int64 `json:"size"`
HostInfo models.SVCenterAccessInfo
VMId string `json:"vm_private_id"`
DiskId string `json:"disk_private_id"`
}
resize := sResize{}
err := body.Unmarshal(&resize)
if err != nil {
return nil, errors.Wrapf(err, "%s: unmarshal to sResize", hostutils.ParamsError)
}
esxiClient, err := esxi.NewESXiClientFromAccessInfo(ctx, &resize.HostInfo)
if err != nil {
return nil, httperrors.NewInputParameterError("info of host_info error")
}
host, err := esxiClient.FindHostByIp(resize.HostInfo.PrivateId)
if err != nil {
return nil, errors.Wrapf(err, "fail to find host by ip %s", resize.HostInfo.PrivateId)
}
ivm, err := host.GetIVMById(resize.VMId)
if err != nil {
return nil, errors.Wrapf(err, "fail to find vm by ID %s", resize.VMId)
}
idisks, err := ivm.GetIDisks()
if err != nil {
return nil, errors.Wrapf(err, "fail to get idisks of vm %s", resize.VMId)
}
var (
idisk cloudprovider.ICloudDisk
hasDisk bool
)
for i := range idisks {
if idisks[i].GetId() == resize.DiskId {
idisk = idisks[i]
hasDisk = true
}
}
if !hasDisk {
return nil, errors.Wrapf(err, "no such disk %s", resize.DiskId)
}
url := idisk.GetAccessPath()
vm, disk := ivm.(*esxi.SVirtualMachine), idisk.(*esxi.SVirtualDisk)
online := jsonutils.QueryBoolean(body, "online", false)
if online {
esxiClient.DoExtendDiskOnline(vm, disk, resize.SizeMb)
} else {
esxiClient.ExtendDisk(url, resize.SizeMb)
}
desc := jsonutils.NewDict()
desc.Add(jsonutils.NewInt(resize.SizeMb), "disk_size")
return desc, nil
}
+1 -1
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
// +build linux,cgo
package storageman
+1 -1
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
// +build linux,cgo
package storageman
@@ -14,11 +14,217 @@
package storageman
// not need to impl, using esxi agent
import (
"context"
"fmt"
"path/filepath"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/multicloud/esxi"
)
type SAgentImageCacheManager struct {
storagemanager *SStorageManager
imageCacheManger IImageCacheManger
}
func NewAgentImageCacheManager(storagemanager *SStorageManager) *SAgentImageCacheManager {
return &SAgentImageCacheManager{storagemanager}
func NewAgentImageCacheManager(manger IImageCacheManger) *SAgentImageCacheManager {
return &SAgentImageCacheManager{manger}
}
type sImageCacheData struct {
ImageId string
HostId string
HostIp string
SrcHostIp string
SrcPath string
SrcDatastore models.SVCenterAccessInfo
Datastore models.SVCenterAccessInfo
Format string
IsForce bool
StoragecacheId string
}
func (c *SAgentImageCacheManager) PrefetchImageCache(ctx context.Context, data interface{}) (jsonutils.JSONObject, error) {
dataDict, ok := data.(*jsonutils.JSONDict)
if !ok {
return nil, errors.Wrap(hostutils.ParamsError, "PrefetchImageCache data format error")
}
idata := new(sImageCacheData)
err := dataDict.Unmarshal(idata)
if err != nil {
return nil, errors.Wrap(err, "%s: unmarshal to sImageCacheData error")
}
lockman.LockRawObject(ctx, idata.HostId, idata.ImageId)
defer lockman.ReleaseRawObject(ctx, idata.HostId, idata.ImageId)
if len(idata.SrcHostIp) != 0 {
return c.prefetchImageCacheByCopy(ctx, idata)
}
return c.prefetchImageCacheByUpload(ctx, idata, dataDict)
}
func (c *SAgentImageCacheManager) prefetchImageCacheByCopy(ctx context.Context, data *sImageCacheData) (jsonutils.JSONObject, error) {
client, err := esxi.NewESXiClientFromAccessInfo(ctx, &data.Datastore)
if err != nil {
return nil, err
}
dstHost, err := client.FindHostByIp(data.HostIp)
if err != nil {
return nil, err
}
dstDs, err := dstHost.FindDataStoreById(data.Datastore.PrivateId)
if err != nil {
return nil, err
}
srcHost, err := client.FindHostByIp(data.SrcHostIp)
if err != nil {
return nil, err
}
srcDs, err := srcHost.FindDataStoreById(data.SrcDatastore.PrivateId)
if err != nil {
return nil, err
}
srcPath := data.SrcPath[len(srcDs.GetUrl()):]
dstPath := fmt.Sprintf("image_cache/%s.vmdk", data.ImageId)
// check if dst vmdk has been existed
exists := false
log.Infof("check file: src=%s, dst=%s", srcPath, dstPath)
dstVmdkInfo, err := dstDs.GetVmdkInfo(ctx, dstPath)
if err != nil {
return nil, err
}
srcVmdkInfo, err := srcDs.GetVmdkInfo(ctx, srcPath)
if err != nil {
return nil, err
}
if dstVmdkInfo == srcVmdkInfo {
exists = true
}
dstUrl := dstDs.GetPathUrl(dstPath)
if !exists || data.IsForce {
_, err = dstDs.MakeDir(ctx, dstPath)
if err != nil {
return nil, errors.Wrap(err, "dstDs.MakeDir")
}
srcUrl := srcDs.GetPathUrl(srcPath)
log.Infof("Copy %s => %s", srcUrl, dstUrl)
err = client.CopyDisk(ctx, srcUrl, dstUrl, data.IsForce)
if err != nil {
return nil, errors.Wrap(err, "client.CopyDisk")
}
dstVmdkInfo, err = dstDs.GetVmdkInfo(ctx, dstPath)
if err != nil {
return nil, errors.Wrap(err, "dstDs.GetVmdkInfo")
}
}
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewInt(dstVmdkInfo.Size()), "size")
ret.Add(jsonutils.NewString(dstUrl), "path")
ret.Add(jsonutils.NewString(data.ImageId), "image_id")
_, err = hostutils.RemoteStoragecacheCacheImage(ctx, data.StoragecacheId, data.ImageId, "ready", dstUrl)
if err != nil {
return nil, err
}
return ret, nil
}
func (c *SAgentImageCacheManager) prefetchImageCacheByUpload(ctx context.Context, data *sImageCacheData,
origin *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
format := "vmdk"
localImage, err := c.imageCacheManger.PrefetchImageCache(ctx, origin)
if err != nil {
return nil, err
}
localImgPath, _ := localImage.GetString("path")
localImgSize, _ := localImage.Int("size")
client, err := esxi.NewESXiClientFromAccessInfo(ctx, &data.Datastore)
if err != nil {
return nil, errors.Wrap(err, "esxi.NewESXiClientFromJson")
}
host, err := client.FindHostByIp(data.HostIp)
if err != nil {
return nil, err
}
ds, err := host.FindDataStoreById(data.Datastore.PrivateId)
if err != nil {
return nil, errors.Wrap(err, "SHost.FindDataStoreById")
}
remotePath := fmt.Sprintf("image_cache/%s.%s", data.ImageId, format)
// check if dst vmdk is exist
exists := false
if format == "vmdk" {
err = ds.CheckVmdk(ctx, remotePath)
if err != nil {
log.Debugf("ds.CheckVmdk failed: %s", err)
} else {
exists = true
}
} else {
ret, err := ds.CheckFile(ctx, remotePath)
if err != nil {
log.Debugf("ds.CheckFile failed: %s", err)
} else {
if int64(ret.Size) == localImgSize {
// exist and same size
exists = true
}
}
}
log.Debugf("exist: %t, remotePath: %s", exists, remotePath)
if !exists || data.IsForce {
err := ds.ImportVMDK(ctx, localImgPath, remotePath, host)
//err := ds.ImportVMDK(ctx, localImgPath, host)
if err != nil {
return nil, errors.Wrap(err, "SDatastore.ImportTemplate")
}
}
remotePath = filepath.Join(ds.GetUrl(), remotePath)
remoteImg := localImage.(*jsonutils.JSONDict)
remoteImg.Add(jsonutils.NewString(remotePath), "path")
_, err = hostutils.RemoteStoragecacheCacheImage(ctx, data.StoragecacheId, data.ImageId, "ready", remotePath)
if err != nil {
return nil, err
}
log.Debugf("prefetchImageCacheByUpload over")
return remoteImg, nil
}
func (c *SAgentImageCacheManager) DeleteImageCache(ctx context.Context, data interface{}) (jsonutils.JSONObject, error) {
dataDict, ok := data.(*jsonutils.JSONDict)
if !ok {
return nil, errors.Wrap(hostutils.ParamsError, "DeleteImageCache data format error")
}
var (
imageID, _ = dataDict.GetString("image_id")
hostIP, _ = dataDict.GetString("host_ip")
dsInfo, _ = dataDict.Get("ds_info")
)
client, _, err := esxi.NewESXiClientFromJson(ctx, dsInfo)
if err != nil {
return nil, err
}
host, err := client.FindHostByIp(hostIP)
if err != nil {
return nil, err
}
dsID, _ := dsInfo.GetString("private_id")
ds, err := host.FindDataStoreById(dsID)
if err != nil {
return nil, err
}
remotePath := fmt.Sprintf("image_cache/%s.vmdk", imageID)
return nil, ds.Delete(ctx, remotePath)
}
@@ -162,5 +162,3 @@ func (c *SLocalImageCacheManager) PrefetchImageCache(ctx context.Context, data i
return nil, fmt.Errorf("Failed to fetch image %s", imageId)
}
}
// TODO: AgentImageCacheManager
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
// +build linux,cgo
package storageman
+564
View File
@@ -0,0 +1,564 @@
// 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 storageman
import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/seclib"
"yunion.io/x/pkg/util/timeutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/agent/iagent"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
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"
"yunion.io/x/onecloud/pkg/multicloud/esxi"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/qemuimg"
)
type SAgentStorage struct {
SLocalStorage
agent iagent.IAgent
}
func NewAgentStorage(manager *SStorageManager, agent iagent.IAgent, path string) *SAgentStorage {
s := &SAgentStorage{SLocalStorage: *NewLocalStorage(manager, path, 0)}
s.agent = agent
s.checkDirC(path)
return s
}
func (as *SAgentStorage) GetDiskById(diskId string) IDisk {
return NewAgentDisk(as, diskId)
}
func (as *SAgentStorage) CreateDiskByDiskInfo(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
createParams, ok := params.(*SDiskCreateByDiskinfo)
if !ok {
return nil, errors.Wrap(hostutils.ParamsError, "CreateDiskByDiskInfo params format error")
}
hd := SHostDatastore{}
err := createParams.DiskInfo.Unmarshal(&hd)
if err != nil {
return nil, errors.Wrap(hostutils.ParamsError, err.Error())
}
diskMeta, err := as.SLocalStorage.CreateDiskByDiskinfo(ctx, params)
if err != nil {
return nil, errors.Wrap(err, "as.SLocalStorage.CreateDiskByDiskinfo")
}
disk := as.GetDiskById(createParams.DiskId)
_, ds, err := as.getHostAndDatastore(ctx, hd)
if err != nil {
return nil, errors.Wrap(err, "as.getHostAndDatastore")
}
remotePath := "disks/" + createParams.DiskId
file, err := os.Open(disk.GetPath())
if err != nil {
return nil, errors.Wrap(err, "fail to open disk path")
}
defer file.Close()
err = ds.Upload(ctx, remotePath, file)
if err != nil {
return nil, errors.Wrap(err, "dataStore.Upload")
}
as.RemoveDisk(disk)
return diskMeta, nil
}
func (as *SAgentStorage) agentRebuildRoot(ctx context.Context, data jsonutils.JSONObject) error {
type sRebuildParam struct {
GuestExtId string
SHostDatastore
Desc struct {
Disks []struct {
DiskId string
ImagePath string
}
}
}
rp := sRebuildParam{}
err := data.Unmarshal(&rp)
if err != nil {
return errors.Wrap(err, hostutils.ParamsError.Error())
}
host, _, err := as.getHostAndDatastore(ctx, rp.SHostDatastore)
if err != nil {
return errors.Wrap(err, "as.getHostAndDatastore")
}
ivm, err := host.GetIVMById(rp.GuestExtId)
if err != nil {
return errors.Wrapf(err, "host.GetIVMById of id '%s'", rp.GuestExtId)
}
if len(rp.Desc.Disks) == 0 {
return errors.Wrap(hostutils.ParamsError, "agentRebuildRoot data.desc.disks is empty")
}
imagePath := rp.Desc.Disks[0].ImagePath
diskId := rp.Desc.Disks[0].DiskId
newPath, err := host.FileUrlPathToDsPath(imagePath)
if err != nil {
return err
}
vm := ivm.(*esxi.SVirtualMachine)
return vm.DoRebuildRoot(ctx, newPath, diskId)
}
func (as *SAgentStorage) agentCreateGuest(ctx context.Context, data *jsonutils.JSONDict) error {
hd := SHostDatastore{}
err := data.Unmarshal(&hd)
if err != nil {
return errors.Wrap(err, hostutils.ParamsError.Error())
}
host, ds, err := as.getHostAndDatastore(ctx, hd)
if err != nil {
return err
}
desc, _ := data.Get("desc")
descDict, ok := desc.(*jsonutils.JSONDict)
if !ok {
return errors.Wrap(hostutils.ParamsError, "agentCreateGuest data format error")
}
vm, err := host.DoCreateVM(ctx, ds, descDict)
if err != nil {
return errors.Wrap(err, "SHost.DoCreateVM")
}
/*
id, _ := data.GetString("guest_ext_id")
ivm, err := host.GetIVMById(id)
if err != nil {
return errors.Wrap(err, "SHost.GetIVMById")
}
*/
name, _ := descDict.GetString("name")
err = as.tryRenameVm(ctx, vm, name)
if err != nil {
return errors.Wrapf(err, "RenameVm name '%s'", name)
}
return nil
}
func (as *SAgentStorage) tryRenameVm(ctx context.Context, vm *esxi.SVirtualMachine, name string) error {
var (
tried = 0
err error
)
alterName := fmt.Sprintf("%s-%s", name, timeutils.ShortDate(time.Now()))
cands := []string{name, alterName}
for tried < 10 {
var n string
if tried < len(cands) {
n = cands[tried]
} else {
n = fmt.Sprintf("%s-%d", alterName, tried-len(cands)+1)
}
tried += 1
err = vm.DoRename(ctx, n)
if err == nil {
return nil
}
}
return err
}
func (as *SAgentStorage) AgentDeployGuest(ctx context.Context, data interface{}) (jsonutils.JSONObject, error) {
init := false
dataDict := data.(*jsonutils.JSONDict)
action, _ := dataDict.GetString("action")
if action == "create" {
err := as.agentCreateGuest(ctx, dataDict)
if err != nil {
return nil, errors.Wrap(err, "agentCreateGuest")
}
init = true
} else if action == "rebuild" {
err := as.agentRebuildRoot(ctx, dataDict)
if err != nil {
return nil, errors.Wrap(err, "agentRebuildRoot")
}
}
var (
hostIp, _ = dataDict.GetString("host_ip")
dsInfo, _ = dataDict.Get("datastore")
)
dc, info, err := esxi.NewESXiClientFromJson(ctx, dsInfo)
if err != nil {
return nil, errors.Wrap(err, "esxi.NewESXiClientFromJson")
}
host, err := dc.FindHostByIp(hostIp)
if err != nil {
return nil, errors.Wrap(err, "SDatacenter.FindHostByIp")
}
vmId, _ := dataDict.GetString("guest_ext_id")
realHost := host
ivm, err := host.GetIVMById(vmId)
if err == cloudprovider.ErrNotFound {
// reschedule by DRS, migrate to other host
siblingHosts, err := host.GetSiblingHosts()
if err != nil {
return nil, errors.Wrap(err, "SHost.GetSiblingHosts")
}
for _, sh := range siblingHosts {
ivm, err = host.GetIVMById(vmId)
if err == nil {
realHost = sh
break
}
}
}
if err != nil {
return nil, errors.Wrap(err, "SHost.GetIVMById")
}
if ivm == nil {
return nil, errors.Error(fmt.Sprintf("no such vm '%s'", ivm.GetId()))
}
vm := ivm.(*esxi.SVirtualMachine)
disks, err := vm.GetIDisks()
if err != nil {
return nil, errors.Wrap(err, "VM.GetIDisks")
}
if len(disks) == 0 {
return nil, errors.Error(fmt.Sprintf("no such disks for vm %s", vm.GetId()))
}
vmref := vm.GetMoid()
rootPath := disks[0].(*esxi.SVirtualDisk).GetFilename()
key := deployapi.SSHKeys{}
err = dataDict.Unmarshal(&key, "desc")
if err != nil {
return nil, errors.Wrapf(err, "%s: unmarshal to deployapi.SSHKeys", hostutils.ParamsError.Error())
}
deployArray := make([]*deployapi.DeployContent, 0)
if dataDict.Contains("deploys") {
err = dataDict.Unmarshal(&deployArray, "deploys")
if err != nil {
return nil, errors.Wrapf(err, "%s: unmarshal to array of deployapi.DeployContent", hostutils.ParamsError.Error())
}
}
resetPassword := jsonutils.QueryBoolean(dataDict, "reset_password", false)
passwd, _ := dataDict.GetString("password")
if resetPassword && len(passwd) == 0 {
passwd = seclib.RandomPassword(12)
}
log.Debugf("host: %s, port: %d, user: %s, passwd: %s", info.Host, info.Port, info.Account, info.Password)
vddkInfo := deployapi.VDDKConInfo{
Host: info.Host,
Port: int32(info.Port),
User: info.Account,
Passwd: info.Password,
Vmref: vmref,
}
guestDesc := deployapi.GuestDesc{}
err = dataDict.Unmarshal(&guestDesc, "desc")
if err != nil {
return nil, errors.Wrapf(err, "%s: unmarshal to guestDesc", hostutils.ParamsError.Error())
}
desc, _ := dataDict.Get("desc")
guestDesc.Hypervisor = api.HYPERVISOR_ESXI
deploy, err := deployclient.GetDeployClient().DeployGuestFs(ctx, &deployapi.DeployParams{
DiskPath: rootPath,
GuestDesc: &guestDesc,
DeployInfo: &deployapi.DeployInfo{
PublicKey: &key,
Deploys: deployArray,
Password: passwd,
IsInit: init,
},
VddkInfo: &vddkInfo,
})
if err != nil {
log.Errorf("DeployClient.DeployGuestFs: %s", err)
// if deploy fail, try customization
as.waitVmToolsVersion(ctx, vm)
err = vm.DoCustomize(ctx, desc)
if err != nil {
return nil, errors.Wrap(err, "VM.DoCustomize")
}
}
array := jsonutils.NewArray()
diskArray, _ := desc.GetArray("disks")
for idx, d := range disks {
disk := d.(*esxi.SVirtualDisk)
diskId, _ := diskArray[idx].GetString("disk_id")
diskDict := jsonutils.NewDict()
diskDict.Add(jsonutils.NewString(diskId), "disk_id")
diskDict.Add(jsonutils.NewString(disk.GetGlobalId()), "uuid")
diskDict.Add(jsonutils.NewInt(int64(disk.GetDiskSizeMB())), "size")
diskDict.Add(jsonutils.NewString(disk.GetFilename()), "path")
diskDict.Add(jsonutils.NewString(disk.GetCacheMode()), "cache_mode")
diskDict.Add(jsonutils.NewString(disk.GetDiskType()), "disk_type")
diskDict.Add(jsonutils.NewString(disk.GetDriver()), "driver")
array.Add(diskDict)
}
updated := jsonutils.NewDict()
updated.Add(array, "disks")
updated.Add(jsonutils.NewString(vm.GetGlobalId()), "uuid")
updated.Add(jsonutils.NewString(realHost.GetAccessIp()), "host_ip")
ret := jsonutils.Marshal(deploy)
ret.(*jsonutils.JSONDict).Update(updated)
return ret, nil
}
func (as *SAgentStorage) waitVmToolsVersion(ctx context.Context, vm *esxi.SVirtualMachine) {
timeout := 90 * time.Second
timeUpper := time.Now().Add(timeout)
for len(vm.GetToolsVersion()) == 0 && time.Now().Before(timeUpper) {
if vm.GetStatus() != api.VM_RUNNING {
vm.StartVM(ctx)
time.Sleep(5 * time.Second)
}
}
timeUpper = time.Now().Add(timeout)
for vm.GetStatus() == api.VM_RUNNING && time.Now().Before(timeUpper) {
vm.StopVM(ctx, true)
time.Sleep(5 * time.Second)
}
return
}
type SHostDatastore struct {
HostIp string
Datastore models.SVCenterAccessInfo
}
func (as *SAgentStorage) getHostAndDatastore(ctx context.Context, data SHostDatastore) (*esxi.SHost, *esxi.SDatastore, error) {
client, err := esxi.NewESXiClientFromAccessInfo(ctx, &data.Datastore)
if err != nil {
return nil, nil, errors.Wrap(err, "fail to generate client")
}
host, err := client.FindHostByIp(data.HostIp)
if err != nil {
return nil, nil, errors.Wrap(err, "fail to find host")
}
ds, err := host.FindDataStoreById(data.Datastore.PrivateId)
if err != nil {
return nil, nil, errors.Wrapf(err, "fail to find datastore")
}
return host, ds, nil
}
func (as *SAgentStorage) isExist(dir string) bool {
_, err := os.Stat(dir)
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func (as *SAgentStorage) checkDirC(dir string) error {
if as.isExist(dir) {
return nil
}
return os.MkdirAll(dir, 0770)
}
func (as *SAgentStorage) checkFileR(file string) error {
if !as.isExist(file) {
return nil
}
return os.Remove(file)
}
func (as *SAgentStorage) PrepareSaveToGlance(ctx context.Context, taskId string, diskInfo jsonutils.JSONObject) (
ret jsonutils.JSONObject, err error) {
type specStruct struct {
Vm models.SVCenterAccessInfo
Disk models.SVCenterAccessInfo
HostIp string
ImageId string
}
spec := specStruct{}
err = diskInfo.Unmarshal(&spec)
if err != nil {
return nil, errors.Wrap(hostutils.ParamsError, err.Error())
}
destDir := as.GetImgsaveBackupPath()
as.checkDirC(destDir)
backupPath := filepath.Join(destDir, fmt.Sprintf("%s.%s", spec.Vm.PrivateId, taskId))
defer as.checkFileR(backupPath)
client, err := esxi.NewESXiClientFromAccessInfo(ctx, &spec.Vm)
if err != nil {
return nil, errors.Wrap(err, "esxi.NewESXiClientFromJson")
}
host, err := client.FindHostByIp(spec.HostIp)
if err != nil {
return nil, errors.Wrapf(err, "ESXiClient.FindHostByIp of ip '%s'", spec.HostIp)
}
ivm, err := host.GetIVMById(spec.Vm.PrivateId)
if err != nil {
return nil, errors.Wrapf(err, "esxi.SHost.GetIVMById for '%s'", spec.Vm.PrivateId)
}
vm := ivm.(*esxi.SVirtualMachine)
idisk, err := vm.GetIDiskById(spec.Disk.PrivateId)
if err != nil {
return nil, errors.Wrapf(err, "esxi.SVirtualMachine for '%s'", spec.Disk.PrivateId)
}
disk := idisk.(*esxi.SVirtualDisk)
log.Infof("Export VM image to %s", backupPath)
err = vm.ExportTemplate(ctx, disk.GetIndex(), backupPath)
if err != nil {
return nil, errors.Wrap(err, "VM.ExportTemplate")
}
dict := jsonutils.NewDict()
dict.Add(jsonutils.NewString(backupPath), "backup")
return dict, nil
}
func (as *SAgentStorage) SaveToGlance(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) {
data, ok := params.(*jsonutils.JSONDict)
if !ok {
return nil, errors.Wrap(hostutils.ParamsError, "SaveToGlance params format error")
}
var (
imageId, _ = data.GetString("image_id")
imagePath, _ = data.GetString("image_path")
compress = jsonutils.QueryBoolean(data, "compress", true)
format, _ = data.GetString("format")
)
log.Debugf("image path: %s", imagePath)
if err := as.saveToGlance(ctx, imageId, imagePath, compress, format); err != nil {
log.Errorf("Save to glance failed: %s", err)
as.onSaveToGlanceFailed(ctx, imageId)
return nil, err
}
imagecacheManager := as.Manager.LocalStorageImagecacheManager
if len(imagecacheManager.GetId()) > 0 {
err := procutils.NewCommand("rm", "-f", imagePath).Run()
return nil, err
} else {
dstPath := path.Join(imagecacheManager.GetPath(), imageId)
if err := procutils.NewCommand("mv", imagePath, dstPath).Run(); err != nil {
log.Errorf("Fail to move saved image to cache: %s", err)
}
imagecacheManager.LoadImageCache(imageId)
_, err := hostutils.RemoteStoragecacheCacheImage(ctx,
imagecacheManager.GetId(), imageId, "ready", dstPath)
if err != nil {
log.Errorf("Fail to remote cache image: %s", err)
}
}
return nil, nil
}
func (as *SAgentStorage) saveToGlance(ctx context.Context, imageId, imagePath string,
compress bool, format string) error {
ret, err := deployclient.GetDeployClient().SaveToGlance(context.Background(),
&deployapi.SaveToGlanceParams{DiskPath: imagePath, Compress: compress})
if err != nil {
return errors.Wrap(err, "DeployClient.SaveToGlance")
}
if compress {
origin, err := qemuimg.NewQemuImage(imagePath)
if err != nil {
log.Errorln(err)
return errors.Wrap(err, "qemuimg.NewQemuImage")
}
if len(format) == 0 {
format = options.HostOptions.DefaultImageSaveFormat
}
if format == "qcow2" {
if err := origin.Convert2Qcow2(true); err != nil {
log.Errorln(err)
return err
}
} else {
if err := origin.Convert2Vmdk(true); err != nil {
log.Errorln(err)
return err
}
}
}
f, err := os.Open(imagePath)
if err != nil {
return err
}
defer f.Close()
finfo, err := f.Stat()
if err != nil {
return err
}
size := finfo.Size()
var params = jsonutils.NewDict()
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 {
params.Set("os_version", jsonutils.NewString(relInfo.Version))
}
if len(relInfo.Arch) > 0 {
params.Set("os_arch", jsonutils.NewString(relInfo.Arch))
}
if len(relInfo.Version) > 0 {
params.Set("os_language", jsonutils.NewString(relInfo.Language))
}
}
params.Set("image_id", jsonutils.NewString(imageId))
_, err = modules.Images.Upload(hostutils.GetImageSession(ctx, as.agent.GetZoneName()),
params, f, size)
if err != nil {
return errors.Wrap(err, "Images.Upload")
}
return nil
}
func (as *SAgentStorage) onSaveToGlanceFailed(ctx context.Context, imageId string) {
params := jsonutils.NewDict()
params.Set("status", jsonutils.NewString("killed"))
_, err := modules.Images.Update(hostutils.GetImageSession(ctx, as.agent.GetZoneName()),
imageId, params)
if err != nil {
log.Errorln(err)
}
}
+1 -1
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
// +build linux,cgo
package storageman
+18 -1
View File
@@ -175,7 +175,8 @@ func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool)
}
}
retVms := make([]cloudprovider.ICloudVM, 0)
// avoid applying new memory and copying
retVms := make([]cloudprovider.ICloudVM, 0, len(vms))
for i := 0; i < len(vms); i += 1 {
if all || !strings.HasPrefix(vms[i].Entity().Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) {
vmObj := NewVirtualMachine(dc.manager, &vms[i], dc)
@@ -187,6 +188,22 @@ func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool)
return retVms, nil
}
func (dc *SDatacenter) fetchDatastores(datastoreRefs []types.ManagedObjectReference) ([]cloudprovider.ICloudStorage, error) {
var dss []mo.Datastore
if datastoreRefs != nil {
err := dc.manager.references2Objects(datastoreRefs, DATASTORE_PROPS, &dss)
if err != nil {
return nil, errors.Wrap(err, "dc.manager.references2Objects")
}
}
retDatastores := make([]cloudprovider.ICloudStorage, 0, len(dss))
for i := range dss {
retDatastores = append(retDatastores, NewDatastore(dc.manager, &dss[i], dc))
}
return retDatastores, nil
}
func (dc *SDatacenter) scanNetworks() error {
if dc.inetworks == nil {
if dc.isDefaultDc() {
+1 -1
View File
@@ -43,7 +43,7 @@ func (dev *SVirtualDevice) getControllerKey() int32 {
return dev.dev.GetVirtualDevice().ControllerKey
}
func (dev *SVirtualDevice) getIndex() int {
func (dev *SVirtualDevice) GetIndex() int {
return dev.index
}
+144
View File
@@ -15,7 +15,12 @@
package esxi
import (
"fmt"
"reflect"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/pkg/errors"
)
func NewDiskDev(sizeMb int64, templatePath string, uuid string, index int32, key int32, controlKey int32) *types.VirtualDisk {
@@ -55,3 +60,142 @@ func addDevSpec(device types.BaseVirtualDevice) *types.VirtualDeviceConfigSpec {
spec.Device = device
return &spec
}
func NewSCSIDev(key, ctlKey int32, driver string) types.BaseVirtualDevice {
desc := types.Description{Label: "SCSI controller 0", Summary: "VMware virtual SCSI"}
if driver == "pvscsi" {
device := types.ParaVirtualSCSIController{}
device.DeviceInfo = &desc
device.Key = key
device.ControllerKey = ctlKey
device.SharedBus = "noSharing"
return &device
}
device := types.VirtualLsiLogicController{}
device.DeviceInfo = &desc
device.Key = key
device.ControllerKey = ctlKey
device.SharedBus = "noSharing"
return &device
}
func NewAHCIDev(key, ctlKey int32) types.BaseVirtualDevice {
device := types.VirtualAHCIController{}
device.DeviceInfo = &types.Description{Label: "SATA controller 0", Summary: "AHCI"}
device.ControllerKey = ctlKey
device.Key = key
return &device
}
func NewSVGADev(key, ctlKey int32) types.BaseVirtualDevice {
device := types.VirtualMachineVideoCard{}
device.DeviceInfo = &types.Description{Label: "Video card", Summary: "Video card"}
device.ControllerKey = ctlKey
device.Key = key
device.VideoRamSizeInKB = 16 * 1024
return &device
}
func NewIDEDev(key, index int32) types.BaseVirtualDevice {
device := types.VirtualIDEController{}
s := fmt.Sprintf("IDE %d", index)
device.DeviceInfo = &types.Description{Label: s, Summary: s}
device.Key = key + index
device.BusNumber = index
return &device
}
func NewCDROMDev(path string, key, ctlKey int32) types.BaseVirtualDevice {
device := types.VirtualCdrom{}
device.DeviceInfo = &types.Description{Label: "CD/DVD drive 1", Summary: "Local ISO Emulated CD-ROM"}
device.ControllerKey = ctlKey
device.Key = key
connectable := types.VirtualDeviceConnectInfo{AllowGuestControl: true, Status: "untried"}
if len(path) != 0 {
device.Backing = &types.VirtualCdromIsoBackingInfo{types.VirtualDeviceFileBackingInfo{FileName: path}}
connectable.StartConnected = true
} else {
device.Backing = &types.VirtualCdromRemoteAtapiBackingInfo{}
connectable.StartConnected = false
}
device.Connectable = &connectable
return &device
}
func NewVNICDev(host *SHost, mac, driver string, vlanId int32, key, ctlKey, index int32) (types.BaseVirtualDevice, error) {
desc := types.Description{Label: fmt.Sprintf("Network adapter %d", index+1), Summary: "VM Network"}
inet, err := host.FindNetworkByVlanID(vlanId)
if err != nil {
return nil, errors.Wrap(err, "SHost.FindNetworkByVlanID")
}
if inet == nil {
return nil, errors.Error(fmt.Sprintf("VLAN %d not found", vlanId))
}
var (
False = false
True = true
)
var backing types.BaseVirtualDeviceBackingInfo
switch inet.(type) {
case *SDistributedVirtualPortgroup:
net := inet.(*SDistributedVirtualPortgroup)
port, err := net.FindPort()
if err != nil {
return nil, errors.Wrap(err, "net.FindPort")
}
if port == nil {
return nil, errors.Error("no valid port on DVS, exhausted")
}
portCon := types.DistributedVirtualSwitchPortConnection{
PortgroupKey: port.PortgroupKey,
SwitchUuid: port.DvsUuid,
PortKey: port.Key,
}
backing = &types.VirtualEthernetCardDistributedVirtualPortBackingInfo{Port: portCon}
case *SNetwork:
monet := inet.(*SNetwork).getMONetwork()
backing = &types.VirtualEthernetCardNetworkBackingInfo{
VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
DeviceName: monet.Name,
UseAutoDetect: &False,
},
Network: &monet.Self,
}
default:
return nil, errors.Error(fmt.Sprintf("Unsuppport network type %s", reflect.TypeOf(inet).Name()))
}
connectable := types.VirtualDeviceConnectInfo{
StartConnected: true,
AllowGuestControl: true,
Connected: false,
Status: "untried",
}
nic := types.VirtualEthernetCard{
VirtualDevice: types.VirtualDevice{
DeviceInfo: &desc,
Backing: backing,
},
WakeOnLanEnabled: &True,
}
nic.Connectable = &connectable
nic.ControllerKey = ctlKey
nic.Key = key + index
if len(mac) != 0 {
nic.AddressType = "Manual"
nic.MacAddress = mac
} else {
nic.AddressType = "Generated"
}
if driver == "e1000" {
return &types.VirtualE1000{nic}, nil
}
return &types.VirtualVmxnet3{types.VirtualVmxnet{nic}}, nil
}
+415 -1
View File
@@ -21,11 +21,13 @@ import (
"strings"
"time"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/regutils"
@@ -34,7 +36,7 @@ import (
"yunion.io/x/onecloud/pkg/multicloud"
)
var HOST_SYSTEM_PROPS = []string{"name", "parent", "summary", "config", "hardware", "vm", "datastore"}
var HOST_SYSTEM_PROPS = []string{"name", "parent", "summary", "config", "hardware", "vm", "datastore", "network"}
type SHostStorageAdapterInfo struct {
Device string
@@ -89,6 +91,10 @@ type SHost struct {
storageCache *SDatastoreImageCache
vms []cloudprovider.ICloudVM
parent *mo.ComputeResource
networks []SNetwork
}
func NewHost(manager *SESXiClient, host *mo.HostSystem, dc *SDatacenter) *SHost {
@@ -587,6 +593,205 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr
return nil, cloudprovider.ErrNotImplemented
}
func (self *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, data *jsonutils.JSONDict) (*SVirtualMachine, error) {
var (
deviceChange = make([]types.BaseVirtualDeviceConfigSpec, 0, 5)
name string
osName = "Linux"
memoryMB int64 = 2048
numCPUs int32 = 2
bios string
)
if data.Contains("uuid") {
name, _ = data.GetString("uuid")
} else {
name, _ = data.GetString("name")
}
if data.Contains("os_name") {
osName, _ = data.GetString("os_name")
}
datastorePath := fmt.Sprintf("[%s] %s", ds.GetRelName(), name)
if data.Contains("mem") {
memoryMB, _ = data.Int("mem")
}
if data.Contains("cpu") {
cpunum, _ := data.Int("cpu")
numCPUs = int32(cpunum)
}
firmware := ""
if data.Contains("bios") {
bios, _ = data.GetString("bios")
}
if len(bios) != 0 {
if bios == "BIOS" {
firmware = "bios"
} else if bios == "UEFI" {
firmware = "efi"
}
}
guestId := "rhel6_64Guest"
if osName == "Windows" {
guestId = "windows7Server64Guest"
}
version := "vmx-10"
if self.isVersion50() {
version = "vmx-08"
}
uuid, _ := data.GetString("uuid")
spec := types.VirtualMachineConfigSpec{
Name: name,
Version: version,
Uuid: uuid,
GuestId: guestId,
NumCPUs: numCPUs,
MemoryMB: memoryMB,
Firmware: firmware,
}
spec.Files = &types.VirtualMachineFileInfo{
VmPathName: datastorePath,
}
deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0)))
deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1)))
deviceChange = append(deviceChange, addDevSpec(NewSVGADev(500, 100)))
disks, _ := data.GetArray("disks")
driver := "scsi"
if len(disks) > 0 {
driver, _ = disks[0].GetString("driver")
}
if driver == "scsi" || driver == "pvscsi" {
if self.isVersion50() {
driver = "scsi"
}
deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(1000, 100, driver)))
}
cdromPath := ""
if data.Contains("cdrom") {
tmp, _ := data.Get("cdrom")
cdromPath, _ = tmp.GetString("path")
}
var err error
if len(cdromPath) != 0 && !strings.HasPrefix(cdromPath, "[") {
cdromPath, err = self.FileUrlPathToDsPath(cdromPath)
if err != nil {
return nil, errors.Wrapf(err, "SHost.FileUrlPathToDsPath for cdrom path '%s'", cdromPath)
}
}
deviceChange = append(deviceChange, addDevSpec(NewCDROMDev(cdromPath, 16000, 201)))
var (
scsiIdx = 0
ideIdx = 0
index = 0
ctrlKey = 0
)
for _, disk := range disks {
imagePath, _ := disk.GetString("image_path")
var size int64 = 0
if len(imagePath) == 0 {
size, _ = disk.Int("size")
if size == 0 {
size = 30 * 1024
}
} else {
imagePath, err = self.FileUrlPathToDsPath(imagePath)
if err != nil {
return nil, errors.Wrapf(err, "SHost.FileUrlPathToDsPath for image path '%s'", imagePath)
}
}
uuid, _ := disk.GetString("disk_id")
driver := "scsi"
if disk.Contains("driver") {
driver, _ = disk.GetString("driver")
}
if driver == "scsi" || driver == "pvscsi" {
if self.isVersion50() {
driver = "scsi"
}
ctrlKey = 1000
index = scsiIdx
scsiIdx += 1
} else {
ctrlKey = 200 + ideIdx/2
index = ideIdx % 2
ideIdx += 1
}
log.Debugf("size: %d, image path: %s, uuid: %s, index: %d, ctrlKey: %d", size, imagePath, uuid, index, ctrlKey)
spec := addDevSpec(NewDiskDev(size, imagePath, uuid, int32(index), 2000, int32(ctrlKey)))
spec.FileOperation = "create"
deviceChange = append(deviceChange, spec)
}
nics, _ := data.GetArray("nics")
for _, nic := range nics {
index, _ := nic.Int("index")
mac, _ := nic.GetString("mac")
driver := "e1000"
if nic.Contains("driver") {
driver, _ = nic.GetString("driver")
}
if self.isVersion50() {
driver = "e1000"
}
var vlanId int64 = 1
if nic.Contains("vlan") {
vlanId, _ = nic.Int("vlan")
}
dev, err := NewVNICDev(self, mac, driver, int32(vlanId), 4000, 100, int32(index))
if err != nil {
return nil, errors.Wrap(err, "NewVNICDev")
}
deviceChange = append(deviceChange, addDevSpec(dev))
}
spec.DeviceChange = deviceChange
dc, err := self.GetDatacenter()
if err != nil {
return nil, errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", self.GetId())
}
// get vmFloder
folders, err := dc.getObjectDatacenter().Folders(ctx)
if err != nil {
return nil, errors.Wrap(err, "object.DataCenter.Folders")
}
vmFolder := folders.VmFolder
resourcePool, err := self.GetResourcePool()
if err != nil {
return nil, errors.Wrap(err, "SHost.GetResourcePool")
}
task, err := vmFolder.CreateVM(ctx, spec, resourcePool, self.GetoHostSystem())
if err != nil {
return nil, errors.Wrap(err, "VmFolder.Create")
}
info, err := task.WaitForResult(ctx, nil)
if err != nil {
return nil, errors.Wrap(err, "Task.WaitForResult")
}
var moVM mo.VirtualMachine
err = self.manager.reference2Object(info.Result.(types.ManagedObjectReference), VIRTUAL_MACHINE_PROPS, &moVM)
if err != nil {
return nil, errors.Wrap(err, "fail to fetch virtual machine just created")
}
return NewVirtualMachine(self.manager, &moVM, self.datacenter), nil
}
func (host *SHost) isVersion50() bool {
version := host.GetVersion()
if strings.HasPrefix(version, "5.") {
return true
}
return false
}
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
nics := host.getNicInfo()
inics := make([]cloudprovider.ICloudHostNetInterface, len(nics))
@@ -662,3 +867,212 @@ func (host *SHost) GetManagementServerIp() string {
func (host *SHost) IsManagedByVCenter() bool {
return len(host.getHostSystem().Summary.ManagementServerIp) > 0
}
func (host *SHost) FindDataStoreById(id string) (*SDatastore, error) {
datastores, err := host.GetDataStores()
if err != nil {
return nil, err
}
for i := range datastores {
if datastores[i].GetGlobalId() == id {
return datastores[i].(*SDatastore), nil
}
}
return nil, fmt.Errorf("no such datastore %s", id)
}
func (host *SHost) GetDataStores() ([]cloudprovider.ICloudStorage, error) {
err := host.fetchDatastores()
if err != nil {
return nil, err
}
return host.datastores, nil
}
func (host *SHost) fetchDatastores() error {
if host.datastores != nil {
return nil
}
dc, err := host.GetDatacenter()
if err != nil {
return err
}
MAX_TRIES := 3
for tried := 0; tried < MAX_TRIES; tried += 1 {
hostDss := host.getHostSystem().Datastore
if len(hostDss) == 0 {
// log.Errorf("host VMs are nil!!!!!")
return nil
}
dss, err := dc.fetchDatastores(hostDss)
if err != nil {
log.Errorf("dc.fetchVms fail %s", err)
time.Sleep(time.Second)
host.Refresh()
continue
}
host.datastores = dss
break
}
return nil
}
func (host *SHost) FileUrlPathToDsPath(path string) (string, error) {
var newPath string
dss, err := host.GetDataStores()
if err != nil {
return newPath, err
}
for _, ds := range dss {
rds := ds.(*SDatastore)
if strings.HasPrefix(path, rds.GetUrl()) {
newPath = fmt.Sprintf("[%s] %s", rds.GetRelName(), path[len(rds.GetUrl()):])
}
break
}
return newPath, nil
}
func (host *SHost) FindNetworkByVlanID(vlanID int32) (IVMNetwork, error) {
if vlanID > 1 && vlanID < 4095 {
return host.findVlanDVPG(int32(vlanID))
}
n, err := host.findNovlanDVPG()
if err != nil {
return nil, err
}
if n != nil {
return n, err
}
return host.findBasicNetwork()
}
func (host *SHost) findBasicNetwork() (*SNetwork, error) {
nets, err := host.GetNetwork()
if err != nil {
return nil, err
}
if len(nets) == 0 {
return nil, nil
}
return &nets[0], nil
}
func (host *SHost) GetNetwork() ([]SNetwork, error) {
if host.networks != nil {
return host.networks, nil
}
netMobs := host.getHostSystem().Network
moNets := make([]mo.Network, 0)
err := host.manager.references2Objects(netMobs, NETWORK_PROPS, &moNets)
if err != nil {
return nil, errors.Wrap(err, "references2Objects")
}
nets := make([]SNetwork, len(moNets))
for i := range moNets {
nets[i] = *NewNetwork(host.manager, &moNets[i], host.datacenter)
}
host.networks = nets
return host.networks, nil
}
func (host *SHost) findNovlanDVPG() (*SDistributedVirtualPortgroup, error) {
nets, err := host.datacenter.GetNetworks()
if err != nil {
return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks")
}
for _, net := range nets {
dvpg, ok := net.(*SDistributedVirtualPortgroup)
if !ok || !dvpg.ContainHost(host) || len(dvpg.GetActivePorts()) == 0 {
continue
}
nvlan := dvpg.GetVlanId()
if nvlan <= 1 || nvlan >= 4095 {
return dvpg, nil
}
}
return nil, nil
}
func (host *SHost) findVlanDVPG(vlanId int32) (*SDistributedVirtualPortgroup, error) {
nets, err := host.datacenter.GetNetworks()
if err != nil {
return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks")
}
for _, net := range nets {
dvpg, ok := net.(*SDistributedVirtualPortgroup)
if !ok || !dvpg.ContainHost(host) || len(dvpg.GetActivePorts()) == 0 {
continue
}
nvlan := dvpg.GetVlanId()
if nvlan == vlanId {
return dvpg, nil
}
}
return nil, nil
}
func (host *SHost) GetoHostSystem() *object.HostSystem {
return object.NewHostSystem(host.manager.client.Client, host.getHostSystem().Reference())
}
func (host *SHost) GetResourcePool() (*object.ResourcePool, error) {
var err error
if host.parent == nil {
host.parent, err = host.getResourcePool()
if err != nil {
return nil, err
}
}
return object.NewResourcePool(host.manager.client.Client, *host.parent.ResourcePool), nil
}
func (host *SHost) getResourcePool() (*mo.ComputeResource, error) {
var mcr *mo.ComputeResource
var parent interface{}
moHost := host.getHostSystem()
switch moHost.Parent.Type {
case "ComputeResource":
mcr = new(mo.ComputeResource)
parent = mcr
case "ClusterComputeResource":
mcc := new(mo.ClusterComputeResource)
mcr = &mcc.ComputeResource
parent = mcc
default:
return nil, errors.Error(fmt.Sprintf("unknown host parent type: %s", moHost.Parent.Type))
}
err := host.manager.reference2Object(*moHost.Parent, []string{"resourcePool"}, parent)
if err != nil {
return nil, errors.Wrap(err, "SESXiClient.reference2Object")
}
return mcr, nil
}
func (host *SHost) GetCluster() (*mo.ComputeResource, error) {
return host.getResourcePool()
}
func (host *SHost) GetSiblingHosts() ([]*SHost, error) {
rp, err := host.GetCluster()
if err != nil {
return nil, err
}
moHosts := make([]mo.HostSystem, 0, len(rp.Host))
err = host.manager.references2Objects(rp.Host, HOST_SYSTEM_PROPS, &moHosts)
if err != nil {
return nil, errors.Wrap(err, "SESXiClient.references2Objects")
}
ret := make([]*SHost, len(moHosts))
for i := range moHosts {
ret[i] = NewHost(host.manager, &moHosts[i], host.datacenter)
}
return ret, nil
}
+74
View File
@@ -0,0 +1,74 @@
// 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 esxi
import (
"github.com/vmware/govmomi/vim25/progress"
"yunion.io/x/log"
)
type logger struct {
name string
chid chan progress.Report
over chan struct{}
}
func (l *logger) Sink() chan<- progress.Report {
return l.chid
}
func (l *logger) End() {
close(l.over)
}
func newLeaseLogger(name string, cap int) *logger {
return &logger{
name: name,
chid: make(chan progress.Report, cap),
over: make(chan struct{}),
}
}
func (l *logger) Log() {
go func() {
var pre float32 = 0
log.Debugf("logger.Log...")
Loop:
for {
select {
case r, ok := <-l.chid:
if !ok {
break Loop
}
if r.Error() != nil {
log.Errorf("%s report, error: %s", l.name, r.Error())
break Loop
}
if r.Percentage() >= pre {
log.Debugf("%s report: speed: %s, percentage: %f%%", l.name, r.Detail(), pre)
pre += 10
}
if r.Percentage() >= 110 {
break Loop
}
case <-l.over:
break Loop
}
}
}()
}
+96
View File
@@ -26,15 +26,19 @@ import (
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/multicloud"
)
@@ -98,6 +102,34 @@ func NewESXiClient2(providerId string, providerName string, host string, port in
return cli, nil
}
func NewESXiClientFromJson(ctx context.Context, input jsonutils.JSONObject) (*SESXiClient, *models.SVCenterAccessInfo, error) {
accessInfo := new(models.SVCenterAccessInfo)
err := input.Unmarshal(accessInfo)
if err != nil {
return nil, nil, errors.Wrapf(err, "%s: unmarshal to SVCenterAccessInfo", hostutils.ParamsError)
}
c, err := NewESXiClientFromAccessInfo(ctx, accessInfo)
return c, accessInfo, err
}
func NewESXiClientFromAccessInfo(ctx context.Context, accessInfo *models.SVCenterAccessInfo) (*SESXiClient, error) {
if len(accessInfo.VcenterId) > 0 {
tmp, err := utils.DescryptAESBase64(accessInfo.VcenterId, accessInfo.Password)
if err == nil {
accessInfo.Password = tmp
}
}
client, err := NewESXiClient("", "", accessInfo.Host, accessInfo.Port, accessInfo.Account, accessInfo.Password)
if err != nil {
return nil, err
}
if ctx == nil {
ctx = context.Background()
}
client.context = ctx
return client, nil
}
func (cli *SESXiClient) getUrl() string {
if cli.port == 443 || cli.port == 0 {
return fmt.Sprintf("https://%s", cli.host)
@@ -419,3 +451,67 @@ func (cli *SESXiClient) GetCapabilities() []string {
}
return caps
}
func (cli *SESXiClient) FindVMByPrivateID(idstr string) (*SVirtualMachine, error) {
searchIndex := object.NewSearchIndex(cli.client.Client)
instanceUuid := true
vmRef, err := searchIndex.FindByUuid(cli.context, nil, idstr, true, &instanceUuid)
if err != nil {
return nil, errors.Wrap(err, "searchIndex.FindByUuid fail")
}
if vmRef == nil {
return nil, fmt.Errorf("cannot find %s", idstr)
}
var vm mo.VirtualMachine
err = cli.reference2Object(vmRef.Reference(), VIRTUAL_MACHINE_PROPS, &vm)
if err != nil {
return nil, errors.Wrap(err, "reference2Object fail")
}
return NewVirtualMachine(cli, &vm, nil), nil
}
func (cli *SESXiClient) DoExtendDiskOnline(_vm *SVirtualMachine, _disk *SVirtualDisk, newSizeMb int64) error {
disk := _disk.getVirtualDisk()
disk.CapacityInKB = newSizeMb * 1024
devSepc := types.VirtualDeviceConfigSpec{Operation: types.VirtualDeviceConfigSpecOperationEdit, Device: disk}
spec := types.VirtualMachineConfigSpec{DeviceChange: []types.BaseVirtualDeviceConfigSpec{&devSepc}}
vm := object.NewVirtualMachine(cli.client.Client, _vm.getVirtualMachine().Reference())
task, err := vm.Reconfigure(cli.context, spec)
if err != nil {
return errors.Wrapf(err, "vm reconfigure failed")
}
return task.Wait(cli.context)
}
func (cli *SESXiClient) ExtendDisk(url string, newSizeMb int64) error {
param := types.ExtendVirtualDisk_Task{
This: *cli.client.Client.ServiceContent.VirtualDiskManager,
Name: url,
NewCapacityKb: newSizeMb * 1024,
}
response, err := methods.ExtendVirtualDisk_Task(cli.context, cli.client, &param)
if err != nil {
return errors.Wrapf(err, "extend virtualdisk task failed")
}
log.Debugf("extend virtual disk task response: %s", response.Returnval.String())
return nil
}
func (cli *SESXiClient) CopyDisk(ctx context.Context, src, dst string, isForce bool) error {
dm := object.NewVirtualDiskManager(cli.client.Client)
task, err := dm.CopyVirtualDisk(ctx, src, nil, dst, nil, nil, isForce)
if err != nil {
return err
}
return task.Wait(ctx)
}
func (cli *SESXiClient) MoveDisk(ctx context.Context, src, dst string, isForce bool) error {
dm := object.NewVirtualDiskManager(cli.client.Client)
task, err := dm.MoveVirtualDisk(ctx, src, nil, dst, nil, isForce)
if err != nil {
return err
}
return task.Wait(ctx)
}
+130
View File
@@ -15,8 +15,13 @@
package esxi
import (
"strings"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/pkg/errors"
)
type IVMNetwork interface {
@@ -26,6 +31,7 @@ type IVMNetwork interface {
GetNumPorts() int32
GetActivePorts() []string
GetType() string
ContainHost(host *SHost) bool
}
const (
@@ -85,6 +91,17 @@ func (net *SNetwork) GetActivePorts() []string {
return nil
}
func (net *SNetwork) ContainHost(host *SHost) bool {
objs := net.getMONetwork().Host
moHost := host.getHostSystem()
for _, obj := range objs {
if obj.Value == moHost.Reference().Value {
return true
}
}
return false
}
func (net *SDistributedVirtualPortgroup) getMODVPortgroup() *mo.DistributedVirtualPortgroup {
return net.object.(*mo.DistributedVirtualPortgroup)
}
@@ -142,3 +159,116 @@ func (net *SDistributedVirtualPortgroup) GetActivePorts() []string {
}
return nil
}
func (net *SDistributedVirtualPortgroup) ContainHost(host *SHost) bool {
objs := net.getMODVPortgroup().Host
moHost := host.getHostSystem()
for _, obj := range objs {
if obj.Value == moHost.Reference().Value {
return true
}
}
return false
}
func (net *SDistributedVirtualPortgroup) Uplink() bool {
dvpg := net.getMODVPortgroup()
return *dvpg.Config.Uplink
}
func (net *SDistributedVirtualPortgroup) FindPort() (*types.DistributedVirtualPort, error) {
dvgp := net.getMODVPortgroup()
odvs := object.NewDistributedVirtualSwitch(net.manager.client.Client, *dvgp.Config.DistributedVirtualSwitch)
var (
False = false
True = true
)
criteria := types.DistributedVirtualSwitchPortCriteria{
Connected: &False,
Inside: &True,
PortgroupKey: []string{dvgp.Key},
}
ports, err := odvs.FetchDVPorts(net.manager.context, &criteria)
if err != nil {
return nil, errors.Wrap(err, "object.DVS.FetchDVPorts")
}
if len(ports) > 0 {
// release extra space timely
return &ports[:1][0], nil
}
return nil, nil
}
func (net *SDistributedVirtualPortgroup) AddHostToDVS(host *SHost) (err error) {
// get dvs
dvgp := net.getMODVPortgroup()
var s mo.DistributedVirtualSwitch
err = net.manager.reference2Object(*dvgp.Config.DistributedVirtualSwitch, []string{"config"}, &s)
if err != nil {
return errors.Wrapf(err, "fail to convert reference to object")
}
moHost := host.getHostSystem()
// check firstly
for _, host := range s.Config.GetDVSConfigInfo().Host {
if host.Config.Host.Value == moHost.Reference().Value {
// host is already a member of dvs
return nil
}
}
config := &types.DVSConfigSpec{ConfigVersion: s.Config.GetDVSConfigInfo().ConfigVersion}
backing := new(types.DistributedVirtualSwitchHostMemberPnicBacking)
pnics := moHost.Config.Network.Pnic
if len(pnics) == 0 {
return errors.Error("no pnic in this host")
}
// try one by one
// have some bug
for i := 0; i < len(pnics); i++ {
backing.PnicSpec = []types.DistributedVirtualSwitchHostMemberPnicSpec{
{
PnicDevice: pnics[i].Device,
},
}
config.Host = []types.DistributedVirtualSwitchHostMemberConfigSpec{
{
Operation: "add",
Host: moHost.Reference(),
Backing: backing,
},
}
var task *object.Task
dvs := object.NewDistributedVirtualSwitch(net.manager.client.Client, s.Reference())
task, err = dvs.Reconfigure(net.manager.context, config)
if err != nil {
return errors.Wrapf(err, "dvs.Reconfigure")
}
err = task.Wait(net.manager.context)
if err == nil {
return nil
}
if strings.Contains(err.Error(), "concurrent modification") {
i -= 1
}
}
return err
}
func FindVlanDistVswitch(nets []IVMNetwork, vlanID int32) IVMNetwork {
for _, net := range nets {
_, ok := net.(*SDistributedVirtualPortgroup)
if !ok {
continue
}
if len(net.GetActivePorts()) == 0 {
continue
}
nvlan := net.GetVlanId()
if nvlan == vlanID {
return net
}
}
return nil
}
+268
View File
@@ -15,20 +15,30 @@
package esxi
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"text/template"
"time"
"unicode"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/progress"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/jsonutils"
@@ -80,6 +90,10 @@ func (self *SDatastore) GetName() string {
return fmt.Sprintf("%s-%s", self.getVolumeType(), volName)
}
func (self *SDatastore) GetRelName() string {
return self.getDatastore().Info.GetDatastoreInfo().Name
}
func (self *SDatastore) GetCapacityMB() int64 {
moStore := self.getDatastore()
return moStore.Summary.Capacity / 1024 / 1024
@@ -701,6 +715,21 @@ func (self *SDatastore) RemoveDir(ctx context.Context, remotePath string) error
return dnm.DeleteDirectory(ctx, dcObj, remotePath)
}
// CheckDirC will check that Dir 'remotePath' is exist, if not, create one.
func (self *SDatastore) CheckDirC(remotePath string) error {
_, err := self.CheckFile(context.Background(), remotePath)
if err == nil {
return nil
}
if errors.Cause(err) != cloudprovider.ErrNotFound {
return err
}
m := object.NewFileManager(self.manager.client.Client)
path := fmt.Sprintf("[%s] %s", self.GetRelName(), remotePath)
return m.MakeDirectory(self.manager.context, path, self.datacenter.getObjectDatacenter(),
true)
}
func (self *SDatastore) IsSysDiskStore() bool {
return true
}
@@ -717,3 +746,242 @@ func (self *SDatastore) MoveVmdk(ctx context.Context, srcPath string, dstPath st
}
return task.Wait(ctx)
}
// domainName will abandon the rune which should't disapear
func (self *SDatastore) domainName(name string) string {
var b bytes.Buffer
for _, r := range name {
if b.Len() == 0 {
if unicode.IsLetter(r) {
b.WriteRune(r)
}
} else {
if unicode.IsDigit(r) || unicode.IsLetter(r) || r == '-' {
b.WriteRune(r)
}
}
}
return strings.TrimRight(b.String(), "-")
}
// ImportVMDK will upload local vmdk 'diskFile' to the 'remotePath' of remote datastore
func (self *SDatastore) ImportVMDK(ctx context.Context, diskFile, remotePath string, host *SHost) error {
name := fmt.Sprintf("yunioncloud.%s%d", self.domainName(remotePath), rand.Int())
vm, err := self.ImportVM(ctx, diskFile, name, host)
if err != nil {
return errors.Wrap(err, "SDatastore.ImportVM")
}
defer func() {
task, err := vm.Destroy(ctx)
if err != nil {
log.Errorf("vm.Destory: %s", err)
return
}
if err = task.Wait(ctx); err != nil {
log.Errorf("task.Wait: %s", err)
}
}()
// check if 'image_cache' is esixt
err = self.CheckDirC("image_cache")
if err != nil {
return errors.Wrap(err, "SDatastore.CheckDirC")
}
fm := self.getDatastoreObj().NewFileManager(self.datacenter.getObjectDatacenter(), true)
// if image_cache not exist
return fm.Move(ctx, fmt.Sprintf("[%s] %s/%s.vmdk", self.GetRelName(), name, name), fmt.Sprintf("[%s] %s",
self.GetRelName(), remotePath))
}
var (
ErrInvalidFormat = errors.Error("vmdk: invalid format (must be streamOptimized)")
)
// info is used to inspect a vmdk and generate an ovf template
type info struct {
Header struct {
MagicNumber uint32
Version uint32
Flags uint32
Capacity uint64
}
Capacity uint64
Size int64
Name string
ImportName string
}
// stat looks at the vmdk header to make sure the format is streamOptimized and
// extracts the disk capacity required to properly generate the ovf descriptor.
func stat(name string) (*info, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
var (
di info
buf bytes.Buffer
)
_, err = io.CopyN(&buf, f, int64(binary.Size(di.Header)))
fi, _ := f.Stat()
_ = f.Close()
if err != nil {
return nil, err
}
err = binary.Read(&buf, binary.LittleEndian, &di.Header)
if err != nil {
return nil, err
}
if di.Header.MagicNumber != 0x564d444b { // SPARSE_MAGICNUMBER
return nil, ErrInvalidFormat
}
if di.Header.Flags&(1<<16) == 0 { // SPARSEFLAG_COMPRESSED
// Needs to be converted, for example:
// vmware-vdiskmanager -r src.vmdk -t 5 dst.vmdk
// qemu-img convert -O vmdk -o subformat=streamOptimized src.vmdk dst.vmdk
return nil, ErrInvalidFormat
}
di.Capacity = di.Header.Capacity * 512 // VMDK_SECTOR_SIZE
di.Size = fi.Size()
di.Name = filepath.Base(name)
di.ImportName = strings.TrimSuffix(di.Name, ".vmdk")
return &di, nil
}
// ovf returns an expanded descriptor template
func (di *info) ovf() (string, error) {
var buf bytes.Buffer
tmpl, err := template.ParseFiles("/opt/yunion/share/vmware/ovf.xml")
if err != nil {
return "", err
}
err = tmpl.Execute(&buf, di)
if err != nil {
return "", err
}
return buf.String(), nil
}
// ImportParams contains the set of optional params to the Import function.
// Note that "optional" may depend on environment, such as ESX or vCenter.
type ImportParams struct {
Path string
Logger progress.Sinker
Type types.VirtualDiskType
Force bool
Datacenter *object.Datacenter
Pool *object.ResourcePool
Folder *object.Folder
Host *object.HostSystem
}
// ImportVM will import a vm by uploading a local vmdk
func (self *SDatastore) ImportVM(ctx context.Context, diskFile, name string, host *SHost) (*object.VirtualMachine, error) {
var (
c = self.manager.client.Client
datastore = self.getDatastoreObj()
)
m := ovf.NewManager(c)
disk, err := stat(diskFile)
if err != nil {
return nil, errors.Wrap(err, "stat")
}
disk.ImportName = name
// Expand the ovf template
descriptor, err := disk.ovf()
if err != nil {
return nil, errors.Wrap(err, "disk.ovf")
}
folders, err := self.datacenter.getObjectDatacenter().Folders(ctx)
if err != nil {
return nil, errors.Wrap(err, "Folders")
}
pool, err := host.GetResourcePool()
if err != nil {
return nil, errors.Wrap(err, "getResourcePool")
}
kind := types.VirtualDiskTypeThin
params := types.OvfCreateImportSpecParams{
DiskProvisioning: string(kind),
EntityName: disk.ImportName,
}
spec, err := m.CreateImportSpec(ctx, descriptor, pool, datastore, params)
if err != nil {
return nil, err
}
if spec.Error != nil {
return nil, errors.Error(spec.Error[0].LocalizedMessage)
}
lease, err := pool.ImportVApp(ctx, spec.ImportSpec, folders.VmFolder, host.GetoHostSystem())
if err != nil {
return nil, err
}
info, err := lease.Wait(ctx, spec.FileItem)
if err != nil {
return nil, err
}
f, err := os.Open(diskFile)
if err != nil {
return nil, err
}
lr := newLeaseLogger("upload vmdk", 5)
lr.Log()
defer lr.End()
opts := soap.Upload{
ContentLength: disk.Size,
Progress: lr,
}
u := lease.StartUpdater(ctx, info)
defer u.Done()
item := info.Items[0] // we only have 1 disk to upload
err = lease.Upload(ctx, item, f, opts)
_ = f.Close()
if err != nil {
return nil, errors.Wrap(err, "lease.Upload")
}
if err = lease.Complete(ctx); err != nil {
log.Debugf("lease complete error: %s, sleep 1s and try again", err)
time.Sleep(time.Second)
if err = lease.Complete(ctx); err != nil {
return nil, errors.Wrap(err, "lease.Complete")
}
}
return object.NewVirtualMachine(c, info.Entity), nil
}
+5 -1
View File
@@ -352,9 +352,13 @@ func (disk *SVirtualDisk) GetExpiredAt() time.Time {
}
func (disk *SVirtualDisk) Rebuild(ctx context.Context) error {
return disk.vm.rebuildDisk(ctx, disk)
return disk.vm.rebuildDisk(ctx, disk, "")
}
func (disk *SVirtualDisk) GetProjectId() string {
return ""
}
func (disk *SVirtualDisk) GetFilename() string {
return disk.getBackingInfo().GetFileName()
}
+177 -5
View File
@@ -24,6 +24,7 @@ import (
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/jsonutils"
@@ -36,8 +37,10 @@ import (
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
cloudtypes "yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "runtime", "summary", "config", "guest", "resourcePool", "layoutEx"}
@@ -160,7 +163,14 @@ func (self *SVirtualMachine) RebuildRoot(ctx context.Context, imageId string, pa
return "", cloudprovider.ErrNotImplemented
}
func (self *SVirtualMachine) rebuildDisk(ctx context.Context, disk *SVirtualDisk) error {
func (self *SVirtualMachine) DoRebuildRoot(ctx context.Context, imagePath string, uuid string) error {
if len(self.vdisks) == 0 {
return errors.ErrNotFound
}
return self.rebuildDisk(ctx, &self.vdisks[0], imagePath)
}
func (self *SVirtualMachine) rebuildDisk(ctx context.Context, disk *SVirtualDisk, imagePath string) error {
uuid := disk.GetId()
sizeMb := disk.GetDiskSizeMB()
index := disk.index
@@ -171,7 +181,7 @@ func (self *SVirtualMachine) rebuildDisk(ctx context.Context, disk *SVirtualDisk
if err != nil {
return err
}
return self.createDiskInternal(ctx, sizeMb, uuid, int32(index), diskKey, ctlKey)
return self.createDiskInternal(ctx, sizeMb, uuid, int32(index), diskKey, ctlKey, imagePath, false)
}
func (self *SVirtualMachine) UpdateVM(ctx context.Context, name string) error {
@@ -826,11 +836,12 @@ func (self *SVirtualMachine) CreateDisk(ctx context.Context, sizeMb int, uuid st
ctlKey += int32(index / 2)
}
return self.createDiskInternal(ctx, sizeMb, uuid, int32(index), diskKey, ctlKey)
return self.createDiskInternal(ctx, sizeMb, uuid, int32(index), diskKey, ctlKey, "", true)
}
func (self *SVirtualMachine) createDiskInternal(ctx context.Context, sizeMb int, uuid string, index int32, diskKey int32, ctlKey int32) error {
devSpec := NewDiskDev(int64(sizeMb), "", uuid, index, diskKey, ctlKey)
func (self *SVirtualMachine) createDiskInternal(ctx context.Context, sizeMb int, uuid string, index int32,
diskKey int32, ctlKey int32, imagePath string, check bool) error {
devSpec := NewDiskDev(int64(sizeMb), imagePath, uuid, index, diskKey, ctlKey)
spec := addDevSpec(devSpec)
spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationCreate
configSpec := types.VirtualMachineConfigSpec{}
@@ -846,6 +857,9 @@ func (self *SVirtualMachine) createDiskInternal(ctx context.Context, sizeMb int,
if err != nil {
return err
}
if !check {
return nil
}
oldDiskCnt := len(self.vdisks)
maxTries := 60
for tried := 0; tried < maxTries; tried += 1 {
@@ -906,3 +920,161 @@ func (self *SVirtualMachine) CheckFileInfo(ctx context.Context) error {
}
return nil
}
func (self *SVirtualMachine) DoRename(ctx context.Context, name string) error {
task, err := self.getVmObj().Rename(ctx, name)
if err != nil {
return errors.Wrap(err, "object.VirtualMachine.Rename")
}
return task.Wait(ctx)
}
func (self *SVirtualMachine) GetMoid() string {
return self.getVirtualMachine().Self.Value
}
func (self *SVirtualMachine) GetToolsVersion() string {
return self.getVirtualMachine().Guest.ToolsVersion
}
func (self *SVirtualMachine) DoCustomize(ctx context.Context, params jsonutils.JSONObject) error {
spec := new(types.CustomizationSpec)
ipSettings := new(types.CustomizationGlobalIPSettings)
domain := "local"
if params.Contains("domain") {
domain, _ = params.GetString("domain")
}
ipSettings.DnsSuffixList = []string{domain}
// deal nics
nics, _ := params.GetArray("nics")
serverNics := make([]cloudtypes.SServerNic, len(nics))
for i := range nics {
var nicType cloudtypes.SServerNic
nics[i].Unmarshal(&nicType)
serverNics[i] = nicType
}
// find dnsServerList
for i := range serverNics {
dnsList := netutils2.GetNicDns(&serverNics[i])
if len(dnsList) != 0 {
ipSettings.DnsServerList = dnsList
}
}
spec.GlobalIPSettings = *ipSettings
maps := make([]types.CustomizationAdapterMapping, 0, len(nics))
for _, nic := range serverNics {
conf := types.CustomizationAdapterMapping{}
conf.MacAddress = nic.Mac
if len(conf.MacAddress) == 0 {
conf.MacAddress = "9e:46:27:21:a2:b2"
}
conf.Adapter = types.CustomizationIPSettings{}
fixedIp := new(types.CustomizationFixedIp)
fixedIp.IpAddress = nic.Ip
if len(fixedIp.IpAddress) == 0 {
fixedIp.IpAddress = "10.168.26.23"
}
conf.Adapter.Ip = fixedIp
maskLen := nic.Masklen
if maskLen == 0 {
maskLen = 24
}
mask := netutils2.Netlen2Mask(maskLen)
conf.Adapter.SubnetMask = mask
if len(nic.Gateway) != 0 {
conf.Adapter.Gateway = []string{nic.Gateway}
}
dnsList := netutils2.GetNicDns(&nic)
if len(dnsList) != 0 {
conf.Adapter.DnsServerList = dnsList
dns := nic.Domain
if len(dns) == 0 {
dns = "local"
}
conf.Adapter.DnsDomain = dns
}
maps = append(maps, conf)
}
spec.NicSettingMap = maps
var (
osName = "Linux"
name = "yunionhost"
)
if params.Contains("os_name") {
osName, _ = params.GetString("os_name")
}
if params.Contains("name") {
name, _ = params.GetString("name")
}
if osName == "Linux" {
linuxPrep := types.CustomizationLinuxPrep{
HostName: &types.CustomizationFixedName{Name: name},
Domain: domain,
TimeZone: "Asia/Shanghai",
}
spec.Identity = &linuxPrep
} else {
sysPrep := types.CustomizationSysprep{
GuiUnattended: types.CustomizationGuiUnattended{
TimeZone: 210,
AutoLogon: false,
},
UserData: types.CustomizationUserData{
FullName: "Administrator",
OrgName: "Yunion",
ProductId: "",
ComputerName: &types.CustomizationFixedName{
Name: name,
},
},
Identification: types.CustomizationIdentification{},
}
spec.Identity = &sysPrep
}
task, err := self.getVmObj().Customize(ctx, *spec)
if err != nil {
return errors.Wrap(err, "object.VirtualMachine.Customize")
}
return task.Wait(ctx)
}
func (self *SVirtualMachine) ExportTemplate(ctx context.Context, idx int, diskPath string) error {
lease, err := self.getVmObj().Export(ctx)
if err != nil {
return errors.Wrap(err, "esxi.SVirtualMachine.DoExportTemplate")
}
info, err := lease.Wait(ctx, nil)
if err != nil {
return errors.Wrap(err, "lease.Wait")
}
u := lease.StartUpdater(ctx, info)
defer u.Done()
if idx >= len(info.Items) {
return errors.Error(fmt.Sprintf("No such Device whose index is %d", idx))
}
lr := newLeaseLogger("download vmdk", 5)
lr.Log()
defer lr.End()
log.Debugf("download to %s start...", diskPath)
err = lease.DownloadFile(ctx, diskPath, info.Items[idx], soap.Download{Progress: lr})
if err != nil {
return errors.Wrap(err, "lease.DownloadFile")
}
err = lease.Complete(ctx)
if err != nil {
return errors.Wrap(err, "lease.Complete")
}
log.Debugf("download to %s finish", diskPath)
return nil
}
+3 -10
View File
@@ -265,7 +265,7 @@ type SNetInterface struct {
Mask net.IPMask
Mac string
// Mtu int
Mtu int
}
var SECRET_PREFIX = "169.254"
@@ -318,6 +318,8 @@ func (n *SNetInterface) fetchConfig(expectIp string) {
return
}
n.Mtu = inter.MTU
n.Mac = inter.HardwareAddr.String()
addrs, err := inter.Addrs()
if err == nil {
@@ -336,15 +338,6 @@ func (n *SNetInterface) fetchConfig(expectIp string) {
}
}
// mtuStr, err := fileutils2.FileGetContents(fmt.Sprintf("/sys/class/net/%s/mtu", n.name))
// if err != nil {
// log.Errorln("Fail to read MTU for %s: %s", n.name, err)
// }
// n.Mtu, err = strconv.Atoi(mtuStr)
// if err != nil {
// log.Errorln("Fail to read MTU for %s: %s", n.name, err)
// }
}
func (n *SNetInterface) DisableGso() {
+78
View File
@@ -0,0 +1,78 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
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 ovf
/*
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_VirtualSystemSettingData.xsd
*/
type CIMVirtualSystemSettingData struct {
ElementName string `xml:"ElementName"`
InstanceID string `xml:"InstanceID"`
AutomaticRecoveryAction *uint8 `xml:"AutomaticRecoveryAction"`
AutomaticShutdownAction *uint8 `xml:"AutomaticShutdownAction"`
AutomaticStartupAction *uint8 `xml:"AutomaticStartupAction"`
AutomaticStartupActionDelay *string `xml:"AutomaticStartupActionDelay>Interval"`
AutomaticStartupActionSequenceNumber *uint16 `xml:"AutomaticStartupActionSequenceNumber"`
Caption *string `xml:"Caption"`
ConfigurationDataRoot *string `xml:"ConfigurationDataRoot"`
ConfigurationFile *string `xml:"ConfigurationFile"`
ConfigurationID *string `xml:"ConfigurationID"`
CreationTime *string `xml:"CreationTime"`
Description *string `xml:"Description"`
LogDataRoot *string `xml:"LogDataRoot"`
Notes []string `xml:"Notes"`
RecoveryFile *string `xml:"RecoveryFile"`
SnapshotDataRoot *string `xml:"SnapshotDataRoot"`
SuspendDataRoot *string `xml:"SuspendDataRoot"`
SwapFileDataRoot *string `xml:"SwapFileDataRoot"`
VirtualSystemIdentifier *string `xml:"VirtualSystemIdentifier"`
VirtualSystemType *string `xml:"VirtualSystemType"`
}
/*
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_ResourceAllocationSettingData.xsd
*/
type CIMResourceAllocationSettingData struct {
ElementName string `xml:"ElementName"`
InstanceID string `xml:"InstanceID"`
ResourceType *uint16 `xml:"ResourceType"`
OtherResourceType *string `xml:"OtherResourceType"`
ResourceSubType *string `xml:"ResourceSubType"`
AddressOnParent *string `xml:"AddressOnParent"`
Address *string `xml:"Address"`
AllocationUnits *string `xml:"AllocationUnits"`
AutomaticAllocation *bool `xml:"AutomaticAllocation"`
AutomaticDeallocation *bool `xml:"AutomaticDeallocation"`
Caption *string `xml:"Caption"`
Connection []string `xml:"Connection"`
ConsumerVisibility *uint16 `xml:"ConsumerVisibility"`
Description *string `xml:"Description"`
HostResource []string `xml:"HostResource"`
Limit *uint64 `xml:"Limit"`
MappingBehavior *uint `xml:"MappingBehavior"`
Parent *string `xml:"Parent"`
PoolID *string `xml:"PoolID"`
Reservation *uint64 `xml:"Reservation"`
VirtualQuantity *uint `xml:"VirtualQuantity"`
VirtualQuantityUnits *string `xml:"VirtualQuantityUnits"`
Weight *uint `xml:"Weight"`
}
+25
View File
@@ -0,0 +1,25 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
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 ovf provides functionality to unmarshal and inspect the structure
of an OVF file. It is not a complete implementation of the specification and
is intended to be used to import virtual infrastructure into vSphere.
For a complete specification of the OVF standard, refer to:
https://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.0.pdf
*/
package ovf
+99
View File
@@ -0,0 +1,99 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
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 ovf
import (
"bytes"
"fmt"
"github.com/vmware/govmomi/vim25/xml"
)
const (
ovfEnvHeader = `<Environment
xmlns="http://schemas.dmtf.org/ovf/environment/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
xmlns:ve="http://www.vmware.com/schema/ovfenv"
oe:id=""
ve:esxId="%s">`
ovfEnvPlatformSection = `<PlatformSection>
<Kind>%s</Kind>
<Version>%s</Version>
<Vendor>%s</Vendor>
<Locale>%s</Locale>
</PlatformSection>`
ovfEnvPropertyHeader = `<PropertySection>`
ovfEnvPropertyEntry = `<Property oe:key="%s" oe:value="%s"/>`
ovfEnvPropertyFooter = `</PropertySection>`
ovfEnvFooter = `</Environment>`
)
type Env struct {
XMLName xml.Name `xml:"http://schemas.dmtf.org/ovf/environment/1 Environment"`
ID string `xml:"id,attr"`
EsxID string `xml:"http://www.vmware.com/schema/ovfenv esxId,attr"`
Platform *PlatformSection `xml:"PlatformSection"`
Property *PropertySection `xml:"PropertySection"`
}
type PlatformSection struct {
Kind string `xml:"Kind"`
Version string `xml:"Version"`
Vendor string `xml:"Vendor"`
Locale string `xml:"Locale"`
}
type PropertySection struct {
Properties []EnvProperty `xml:"Property"`
}
type EnvProperty struct {
Key string `xml:"key,attr"`
Value string `xml:"value,attr"`
}
// Marshal marshals Env to xml by using xml.Marshal.
func (e Env) Marshal() (string, error) {
x, err := xml.Marshal(e)
if err != nil {
return "", err
}
return fmt.Sprintf("%s%s", xml.Header, x), nil
}
// MarshalManual manually marshals Env to xml suitable for a vApp guest.
// It exists to overcome the lack of expressiveness in Go's XML namespaces.
func (e Env) MarshalManual() string {
var buffer bytes.Buffer
buffer.WriteString(xml.Header)
buffer.WriteString(fmt.Sprintf(ovfEnvHeader, e.EsxID))
buffer.WriteString(fmt.Sprintf(ovfEnvPlatformSection, e.Platform.Kind, e.Platform.Version, e.Platform.Vendor, e.Platform.Locale))
buffer.WriteString(fmt.Sprintf(ovfEnvPropertyHeader))
for _, p := range e.Property.Properties {
buffer.WriteString(fmt.Sprintf(ovfEnvPropertyEntry, p.Key, p.Value))
}
buffer.WriteString(fmt.Sprintf(ovfEnvPropertyFooter))
buffer.WriteString(fmt.Sprintf(ovfEnvFooter))
return buffer.String()
}
+191
View File
@@ -0,0 +1,191 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
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 ovf
type Envelope struct {
References []File `xml:"References>File"`
// Package level meta-data
Annotation *AnnotationSection `xml:"AnnotationSection"`
Product *ProductSection `xml:"ProductSection"`
Network *NetworkSection `xml:"NetworkSection"`
Disk *DiskSection `xml:"DiskSection"`
OperatingSystem *OperatingSystemSection `xml:"OperatingSystemSection"`
Eula *EulaSection `xml:"EulaSection"`
VirtualHardware *VirtualHardwareSection `xml:"VirtualHardwareSection"`
ResourceAllocation *ResourceAllocationSection `xml:"ResourceAllocationSection"`
DeploymentOption *DeploymentOptionSection `xml:"DeploymentOptionSection"`
// Content: A VirtualSystem or a VirtualSystemCollection
VirtualSystem *VirtualSystem `xml:"VirtualSystem"`
}
type VirtualSystem struct {
Content
Annotation []AnnotationSection `xml:"AnnotationSection"`
Product []ProductSection `xml:"ProductSection"`
OperatingSystem []OperatingSystemSection `xml:"OperatingSystemSection"`
Eula []EulaSection `xml:"EulaSection"`
VirtualHardware []VirtualHardwareSection `xml:"VirtualHardwareSection"`
}
type File struct {
ID string `xml:"id,attr"`
Href string `xml:"href,attr"`
Size uint `xml:"size,attr"`
Compression *string `xml:"compression,attr"`
ChunkSize *int `xml:"chunkSize,attr"`
}
type Content struct {
ID string `xml:"id,attr"`
Info string `xml:"Info"`
Name *string `xml:"Name"`
}
type Section struct {
Required *bool `xml:"required,attr"`
Info string `xml:"Info"`
}
type AnnotationSection struct {
Section
Annotation string `xml:"Annotation"`
}
type ProductSection struct {
Section
Class *string `xml:"class,attr"`
Instance *string `xml:"instance,attr"`
Product string `xml:"Product"`
Vendor string `xml:"Vendor"`
Version string `xml:"Version"`
FullVersion string `xml:"FullVersion"`
ProductURL string `xml:"ProductUrl"`
VendorURL string `xml:"VendorUrl"`
AppURL string `xml:"AppUrl"`
Property []Property `xml:"Property"`
}
type Property struct {
Key string `xml:"key,attr"`
Type string `xml:"type,attr"`
Qualifiers *string `xml:"qualifiers,attr"`
UserConfigurable *bool `xml:"userConfigurable,attr"`
Default *string `xml:"value,attr"`
Password *bool `xml:"password,attr"`
Label *string `xml:"Label"`
Description *string `xml:"Description"`
Values []PropertyConfigurationValue `xml:"Value"`
}
type PropertyConfigurationValue struct {
Value string `xml:"value,attr"`
Configuration *string `xml:"configuration,attr"`
}
type NetworkSection struct {
Section
Networks []Network `xml:"Network"`
}
type Network struct {
Name string `xml:"name,attr"`
Description string `xml:"Description"`
}
type DiskSection struct {
Section
Disks []VirtualDiskDesc `xml:"Disk"`
}
type VirtualDiskDesc struct {
DiskID string `xml:"diskId,attr"`
FileRef *string `xml:"fileRef,attr"`
Capacity string `xml:"capacity,attr"`
CapacityAllocationUnits *string `xml:"capacityAllocationUnits,attr"`
Format *string `xml:"format,attr"`
PopulatedSize *int `xml:"populatedSize,attr"`
ParentRef *string `xml:"parentRef,attr"`
}
type OperatingSystemSection struct {
Section
ID int16 `xml:"id,attr"`
Version *string `xml:"version,attr"`
OSType *string `xml:"osType,attr"`
Description *string `xml:"Description"`
}
type EulaSection struct {
Section
License string `xml:"License"`
}
type VirtualHardwareSection struct {
Section
ID *string `xml:"id,attr"`
Transport *string `xml:"transport,attr"`
System *VirtualSystemSettingData `xml:"System"`
Item []ResourceAllocationSettingData `xml:"Item"`
}
type VirtualSystemSettingData struct {
CIMVirtualSystemSettingData
}
type ResourceAllocationSettingData struct {
CIMResourceAllocationSettingData
Required *bool `xml:"required,attr"`
Configuration *string `xml:"configuration,attr"`
Bound *string `xml:"bound,attr"`
}
type ResourceAllocationSection struct {
Section
Item []ResourceAllocationSettingData `xml:"Item"`
}
type DeploymentOptionSection struct {
Section
Configuration []DeploymentOptionConfiguration `xml:"Configuration"`
}
type DeploymentOptionConfiguration struct {
ID string `xml:"id,attr"`
Default *bool `xml:"default,attr"`
Label string `xml:"Label"`
Description string `xml:"Description"`
}
+103
View File
@@ -0,0 +1,103 @@
/*
Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved.
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 ovf
import (
"context"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type Manager struct {
types.ManagedObjectReference
c *vim25.Client
}
func NewManager(c *vim25.Client) *Manager {
return &Manager{*c.ServiceContent.OvfManager, c}
}
// CreateDescriptor wraps methods.CreateDescriptor
func (m *Manager) CreateDescriptor(ctx context.Context, obj mo.Reference, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
req := types.CreateDescriptor{
This: m.Reference(),
Obj: obj.Reference(),
Cdp: cdp,
}
res, err := methods.CreateDescriptor(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
// CreateImportSpec wraps methods.CreateImportSpec
func (m *Manager) CreateImportSpec(ctx context.Context, ovfDescriptor string, resourcePool mo.Reference, datastore mo.Reference, cisp types.OvfCreateImportSpecParams) (*types.OvfCreateImportSpecResult, error) {
req := types.CreateImportSpec{
This: m.Reference(),
OvfDescriptor: ovfDescriptor,
ResourcePool: resourcePool.Reference(),
Datastore: datastore.Reference(),
Cisp: cisp,
}
res, err := methods.CreateImportSpec(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
// ParseDescriptor wraps methods.ParseDescriptor
func (m *Manager) ParseDescriptor(ctx context.Context, ovfDescriptor string, pdp types.OvfParseDescriptorParams) (*types.OvfParseDescriptorResult, error) {
req := types.ParseDescriptor{
This: m.Reference(),
OvfDescriptor: ovfDescriptor,
Pdp: pdp,
}
res, err := methods.ParseDescriptor(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
// ValidateHost wraps methods.ValidateHost
func (m *Manager) ValidateHost(ctx context.Context, ovfDescriptor string, host mo.Reference, vhp types.OvfValidateHostParams) (*types.OvfValidateHostResult, error) {
req := types.ValidateHost{
This: m.Reference(),
OvfDescriptor: ovfDescriptor,
Host: host.Reference(),
Vhp: vhp,
}
res, err := methods.ValidateHost(ctx, m.c, &req)
if err != nil {
return nil, err
}
return &res.Returnval, nil
}
+35
View File
@@ -0,0 +1,35 @@
/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
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 ovf
import (
"io"
"github.com/vmware/govmomi/vim25/xml"
)
func Unmarshal(r io.Reader) (*Envelope, error) {
var e Envelope
dec := xml.NewDecoder(r)
err := dec.Decode(&e)
if err != nil {
return nil, err
}
return &e, nil
}
+1
View File
@@ -507,6 +507,7 @@ github.com/vmihailenco/msgpack/codes
github.com/vmware/govmomi
github.com/vmware/govmomi/nfc
github.com/vmware/govmomi/object
github.com/vmware/govmomi/ovf
github.com/vmware/govmomi/property
github.com/vmware/govmomi/session
github.com/vmware/govmomi/task