diff --git a/pkg/multicloud/esxi/host.go b/pkg/multicloud/esxi/host.go index db647596a..5ce24c256 100644 --- a/pkg/multicloud/esxi/host.go +++ b/pkg/multicloud/esxi/host.go @@ -786,7 +786,7 @@ type SCreateVMParam struct { Cdrom SCdromInfo Disks []SDiskInfo Nics []jsonutils.JSONObject - ResourcePool string + ProjectId string InstanceSnapshotInfo SEsxiInstanceSnapshotInfo EnableEsxiSwap bool } @@ -1161,19 +1161,19 @@ func (host *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, params SCreat err = errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId()) return } - // get vmFloder - folders, err := dc.getObjectDatacenter().Folders(ctx) + + vmFolder, err := dc.GetFolder(params.ProjectId) if err != nil { - err = errors.Wrap(err, "object.DataCenter.Folders") + err = errors.Wrap(err, "GetFolder") return } - vmFolder := folders.VmFolder - resourcePool, err := host.SyncResourcePool(params.ResourcePool) + + pool, err := host.GetResourcePool() if err != nil { - err = errors.Wrap(err, "SyncResourcePool") + err = errors.Wrap(err, "GetResourcePool") return } - task, err := vmFolder.CreateVM(ctx, spec, resourcePool, host.GetHostSystem()) + task, err := vmFolder.CreateVM(ctx, spec, pool, host.GetHostSystem()) if err != nil { err = errors.Wrap(err, "VmFolder.Create") return @@ -1286,17 +1286,16 @@ func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot if err != nil { return nil, errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId()) } - // get vmFloder - folders, err := dc.getObjectDatacenter().Folders(ctx) + vmFolder, err := dc.GetFolder(params.ProjectId) if err != nil { - return nil, errors.Wrap(err, "object.DataCenter.Folders") + return nil, errors.Wrap(err, "GetFolder") } - resourcePool, err := host.SyncResourcePool(params.ResourcePool) + + resourcePool, err := host.GetResourcePool() if err != nil { - return nil, errors.Wrap(err, "SyncResourcePool") + return nil, errors.Wrap(err, "GetResourcePool") } - folderref := folders.VmFolder.Reference() poolref := resourcePool.Reference() hostref := host.GetHostSystem().Reference() tds, err := ds.getDatastoreObj(ctx) @@ -1304,8 +1303,9 @@ func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot return nil, errors.Wrapf(err, "getDatastoreObj") } dsref := tds.Reference() + vmFolderRef := vmFolder.Reference() relocateSpec := types.VirtualMachineRelocateSpec{ - Folder: &folderref, + Folder: &vmFolderRef, Pool: &poolref, Host: &hostref, Datastore: &dsref, @@ -1355,7 +1355,7 @@ func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot }) } cloneSpec.Config = &spec - task, err := ovm.Clone(ctx, folders.VmFolder, name, *cloneSpec) + task, err := ovm.Clone(ctx, vmFolder, name, *cloneSpec) if err != nil { return nil, errors.Wrap(err, "object.VirtualMachine.Clone") } diff --git a/pkg/multicloud/esxi/manager.go b/pkg/multicloud/esxi/manager.go index 923eab7a3..590421868 100644 --- a/pkg/multicloud/esxi/manager.go +++ b/pkg/multicloud/esxi/manager.go @@ -586,22 +586,6 @@ func findDatacenterByMoId(dcs []*SDatacenter, dcId string) (*SDatacenter, error) return nil, cloudprovider.ErrNotFound } -func (cli *SESXiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { - dcs, err := cli.GetDatacenters() - if err != nil { - return nil, errors.Wrap(err, "GetDatacenters") - } - ret := []cloudprovider.ICloudProject{} - for i := 0; i < len(dcs); i++ { - iprojects, err := dcs[i].GetResourcePools() - if err != nil { - return nil, errors.Wrap(err, "GetResourcePools") - } - ret = append(ret, iprojects...) - } - return ret, nil -} - func (cli *SESXiClient) FindHostByMoId(moId string) (cloudprovider.ICloudHost, error) { dcs, err := cli.GetDatacenters() if err != nil { diff --git a/pkg/multicloud/esxi/project.go b/pkg/multicloud/esxi/project.go new file mode 100644 index 000000000..8f36a8e36 --- /dev/null +++ b/pkg/multicloud/esxi/project.go @@ -0,0 +1,142 @@ +// 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" + + "github.com/vmware/govmomi/object" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/pkg/errors" +) + +type SProject struct { + multicloud.SProjectBase + multicloud.STagBase + + client *SESXiClient + folder *object.Folder + + Name string + Id string +} + +func (project *SProject) GetId() string { + return project.Id +} + +func (project *SProject) GetGlobalId() string { + return project.Id +} + +func (project *SProject) GetName() string { + return project.Name +} + +func (project *SProject) GetStatus() string { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (cli *SESXiClient) listAllFolders(ctx context.Context, folder *object.Folder, prefix string) ([]SProject, error) { + ret := []SProject{} + name, err := folder.ObjectName(ctx) + if err != nil { + return nil, errors.Wrap(err, "ObjectName") + } + if len(prefix) > 0 { + name = prefix + name + } + ret = append(ret, SProject{ + folder: folder, + Id: folder.Reference().Value, + Name: name, + }) + + children, err := folder.Children(ctx) + if err != nil { + return nil, errors.Wrap(err, "Children") + } + + for _, child := range children { + if subFolder, ok := child.(*object.Folder); ok { + folders, err := cli.listAllFolders(ctx, subFolder, name+"|") + if err != nil { + return nil, errors.Wrap(err, "listAllFolders") + } + ret = append(ret, folders...) + } + } + return ret, nil +} + +func (dc *SDatacenter) GetVMFolders() ([]SProject, error) { + vmFolders, err := dc.getObjectDatacenter().Folders(dc.manager.context) + if err != nil { + return nil, errors.Wrap(err, "Folders") + } + ret, err := dc.manager.listAllFolders(dc.manager.context, vmFolders.VmFolder, "") + if err != nil { + return nil, errors.Wrap(err, "listAllFolders") + } + return ret, nil +} + +func (dc *SDatacenter) GetFolder(folderId string) (*object.Folder, error) { + vmFolders, err := dc.getObjectDatacenter().Folders(dc.manager.context) + if err != nil { + return nil, errors.Wrap(err, "Folders") + } + ret, err := dc.manager.listAllFolders(dc.manager.context, vmFolders.VmFolder, "") + if err != nil { + return nil, errors.Wrap(err, "listAllFolders") + } + for i := range ret { + if ret[i].Id == folderId { + return ret[i].folder, nil + } + } + return vmFolders.VmFolder, nil +} + +func (cli *SESXiClient) GetVMFolders() ([]SProject, error) { + dcs, err := cli.GetDatacenters() + if err != nil { + return nil, errors.Wrap(err, "GetDatacenters") + } + ret := make([]SProject, 0) + for i := range dcs { + folders, err := dcs[i].GetVMFolders() + if err != nil { + return nil, errors.Wrap(err, "GetVMFolders") + } + ret = append(ret, folders...) + } + return ret, nil +} + +func (cli *SESXiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + projects, err := cli.GetVMFolders() + if err != nil { + return nil, errors.Wrap(err, "GetVMFolders") + } + ret := make([]cloudprovider.ICloudProject, 0) + for i := range projects { + projects[i].client = cli + ret = append(ret, &projects[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/esxi/shell/project.go b/pkg/multicloud/esxi/shell/project.go new file mode 100644 index 000000000..f5dfbada7 --- /dev/null +++ b/pkg/multicloud/esxi/shell/project.go @@ -0,0 +1,35 @@ +// 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 shell + +import ( + "yunion.io/x/pkg/util/printutils" + "yunion.io/x/pkg/util/shellutils" + + "yunion.io/x/cloudmux/pkg/multicloud/esxi" +) + +func init() { + type ProjectListOptions struct { + } + shellutils.R(&ProjectListOptions{}, "project-list", "List all projects", func(cli *esxi.SESXiClient, args *ProjectListOptions) error { + projects, err := cli.GetVMFolders() + if err != nil { + return err + } + printutils.PrintInterfaceList(projects, 0, 0, 0, []string{"Name", "Id"}) + return nil + }) +}