Skip to content

Commit 770fcba

Browse files
authored
Merge pull request #1997 from dougm/issue-1996
govc: support raw object references in import.ova NetworkMapping
2 parents 776bf25 + 7cdad99 commit 770fcba

File tree

6 files changed

+166
-23
lines changed

6 files changed

+166
-23
lines changed

govc/importx/ovf.go

+33-19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"fmt"
2424
"path"
2525

26+
"github.com/vmware/govmomi/find"
2627
"github.com/vmware/govmomi/govc/cli"
2728
"github.com/vmware/govmomi/govc/flags"
2829
"github.com/vmware/govmomi/nfc"
@@ -163,34 +164,42 @@ func (cmd *ovfx) Map(op []Property) (p []types.KeyValue) {
163164
return
164165
}
165166

166-
func (cmd *ovfx) NetworkMap(e *ovf.Envelope) (p []types.OvfNetworkMapping) {
167+
func (cmd *ovfx) NetworkMap(e *ovf.Envelope) ([]types.OvfNetworkMapping, error) {
167168
ctx := context.TODO()
168169
finder, err := cmd.DatastoreFlag.Finder()
169170
if err != nil {
170-
return
171+
return nil, err
171172
}
172173

173-
networks := map[string]string{}
174-
175-
if e.Network != nil {
176-
for _, net := range e.Network.Networks {
177-
networks[net.Name] = net.Name
174+
var nmap []types.OvfNetworkMapping
175+
for _, m := range cmd.Options.NetworkMapping {
176+
if m.Network == "" {
177+
continue // Not set, let vSphere choose the default network
178178
}
179-
}
180179

181-
for _, net := range cmd.Options.NetworkMapping {
182-
networks[net.Name] = net.Network
183-
}
180+
var ref types.ManagedObjectReference
184181

185-
for src, dst := range networks {
186-
if net, err := finder.Network(ctx, dst); err == nil {
187-
p = append(p, types.OvfNetworkMapping{
188-
Name: src,
189-
Network: net.Reference(),
190-
})
182+
net, err := finder.Network(ctx, m.Network)
183+
if err != nil {
184+
switch err.(type) {
185+
case *find.NotFoundError:
186+
if !ref.FromString(m.Network) {
187+
return nil, err
188+
} // else this is a raw MO ref
189+
default:
190+
return nil, err
191+
}
192+
} else {
193+
ref = net.Reference()
191194
}
195+
196+
nmap = append(nmap, types.OvfNetworkMapping{
197+
Name: m.Name,
198+
Network: ref,
199+
})
192200
}
193-
return
201+
202+
return nmap, err
194203
}
195204

196205
func (cmd *ovfx) Import(fpath string) (*types.ManagedObjectReference, error) {
@@ -224,6 +233,11 @@ func (cmd *ovfx) Import(fpath string) (*types.ManagedObjectReference, error) {
224233
name = cmd.Name
225234
}
226235

236+
nmap, err := cmd.NetworkMap(e)
237+
if err != nil {
238+
return nil, err
239+
}
240+
227241
cisp := types.OvfCreateImportSpecParams{
228242
DiskProvisioning: cmd.Options.DiskProvisioning,
229243
EntityName: name,
@@ -233,7 +247,7 @@ func (cmd *ovfx) Import(fpath string) (*types.ManagedObjectReference, error) {
233247
DeploymentOption: cmd.Options.Deployment,
234248
Locale: "US"},
235249
PropertyMapping: cmd.Map(cmd.Options.PropertyMapping),
236-
NetworkMapping: cmd.NetworkMap(e),
250+
NetworkMapping: nmap,
237251
}
238252

239253
host, err := cmd.HostSystemIfSpecified()

govc/test/import.bats

+42
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,45 @@ load test_helper
148148
run govc import.vmdk -force "$GOVC_TEST_VMDK_SRC" "$name"
149149
assert_success # exists, but -force was used
150150
}
151+
152+
@test "import duplicate dvpg names" {
153+
vcsim_env
154+
155+
run govc dvs.create DVS1 # DVS0 already exists
156+
assert_success
157+
158+
run govc dvs.portgroup.add -dvs DVS0 -type ephemeral NSX-dvpg
159+
assert_success
160+
161+
run govc dvs.portgroup.add -dvs DVS1 -type ephemeral NSX-dvpg
162+
assert_success
163+
164+
ovf="$GOVC_IMAGES/$TTYLINUX_NAME.ovf"
165+
166+
spec=$(govc import.spec "$GOVC_IMAGES/$TTYLINUX_NAME.ovf")
167+
168+
run govc import.ovf -name ttylinux -options - "$ovf" <<<"$spec"
169+
assert_success # no network specified
170+
171+
options=$(jq ".NetworkMapping[].Network = \"enoent\"" <<<"$spec")
172+
173+
run govc import.ovf -options - "$ovf" <<<"$options"
174+
assert_failure # network not found
175+
176+
options=$(jq ".NetworkMapping[].Network = \"NSX-dvpg\"" <<<"$spec")
177+
178+
run govc import.ovf -options - "$ovf" <<<"$options"
179+
assert_failure # 2 networks have the same name
180+
181+
options=$(jq ".NetworkMapping[].Network = \"DVS0/NSX-dvpg\"" <<<"$spec")
182+
183+
run govc import.ovf -name ttylinux2 -options - "$ovf" <<<"$options"
184+
assert_success # switch_name/portgroup_name is unique
185+
186+
switch=$(govc find -i network -name DVS0)
187+
id=$(govc find -i network -config.distributedVirtualSwitch "$switch" -name NSX-dvpg)
188+
options=$(jq ".NetworkMapping[].Network = \"$id\"" <<<"$spec")
189+
190+
run govc import.ovf -options - "$ovf" <<<"$options"
191+
assert_success # using raw MO id
192+
}

govc/test/network.bats

+16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ load test_helper
3838

3939
run govc device.remove -vm $vm $eth0
4040
assert_failure "govc: device '$eth0' not found"
41+
42+
# Test PG's with the same name
43+
run govc dvs.create DVS1 # DVS0 already exists
44+
assert_success
45+
46+
run govc dvs.portgroup.add -dvs DVS0 -type ephemeral NSX-dvpg
47+
assert_success
48+
49+
run govc dvs.portgroup.add -dvs DVS1 -type ephemeral NSX-dvpg
50+
assert_success
51+
52+
run govc vm.network.add -vm $vm -net NSX-dvpg
53+
assert_failure # resolves to multiple networks
54+
55+
run govc vm.network.add -vm $vm -net DVS0/NSX-dvpg
56+
assert_success # switch_name/portgroup_name is unique
4157
}
4258

4359
@test "network change backing" {

govc/vm/network/add.go

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func (cmd *add) Description() string {
4747
4848
Examples:
4949
govc vm.network.add -vm $vm -net "VM Network" -net.adapter e1000e
50+
govc vm.network.add -vm $vm -net SwitchName/PortgroupName
5051
govc device.info -vm $vm ethernet-*`
5152
}
5253

list/lister.go

+65
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ func (l Lister) List(ctx context.Context) ([]Element, error) {
165165
return l.ListHostSystem(ctx)
166166
case "VirtualApp":
167167
return l.ListVirtualApp(ctx)
168+
case "VmwareDistributedVirtualSwitch", "DistributedVirtualSwitch":
169+
return l.ListDistributedVirtualSwitch(ctx)
168170
default:
169171
return nil, fmt.Errorf("cannot traverse type " + l.Reference.Type)
170172
}
@@ -497,6 +499,69 @@ func (l Lister) ListHostSystem(ctx context.Context) ([]Element, error) {
497499
return es, nil
498500
}
499501

502+
func (l Lister) ListDistributedVirtualSwitch(ctx context.Context) ([]Element, error) {
503+
ospec := types.ObjectSpec{
504+
Obj: l.Reference,
505+
Skip: types.NewBool(true),
506+
}
507+
508+
fields := []string{
509+
"portgroup",
510+
}
511+
512+
for _, f := range fields {
513+
tspec := types.TraversalSpec{
514+
Path: f,
515+
Skip: types.NewBool(false),
516+
Type: "DistributedVirtualSwitch",
517+
}
518+
519+
ospec.SelectSet = append(ospec.SelectSet, &tspec)
520+
}
521+
522+
childTypes := []string{
523+
"DistributedVirtualPortgroup",
524+
}
525+
526+
var pspecs []types.PropertySpec
527+
for _, t := range childTypes {
528+
pspec := types.PropertySpec{
529+
Type: t,
530+
}
531+
532+
if l.All {
533+
pspec.All = types.NewBool(true)
534+
} else {
535+
pspec.PathSet = []string{"name"}
536+
}
537+
538+
pspecs = append(pspecs, pspec)
539+
}
540+
541+
req := types.RetrieveProperties{
542+
SpecSet: []types.PropertyFilterSpec{
543+
{
544+
ObjectSet: []types.ObjectSpec{ospec},
545+
PropSet: pspecs,
546+
},
547+
},
548+
}
549+
550+
var dst []interface{}
551+
552+
err := l.retrieveProperties(ctx, req, &dst)
553+
if err != nil {
554+
return nil, err
555+
}
556+
557+
es := []Element{}
558+
for _, v := range dst {
559+
es = append(es, ToElement(v.(mo.Reference), l.Prefix))
560+
}
561+
562+
return es, nil
563+
}
564+
500565
func (l Lister) ListVirtualApp(ctx context.Context) ([]Element, error) {
501566
ospec := types.ObjectSpec{
502567
Obj: l.Reference,

simulator/dvs.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package simulator
1818

1919
import (
2020
"strconv"
21+
"strings"
2122

2223
"github.com/vmware/govmomi/vim25/methods"
2324
"github.com/vmware/govmomi/vim25/mo"
@@ -41,10 +42,14 @@ func (s *DistributedVirtualSwitch) AddDVPortgroupTask(ctx *Context, c *types.Add
4142
pg.Name = spec.Name
4243
pg.Entity().Name = pg.Name
4344

44-
if obj := Map.FindByName(pg.Name, f.ChildEntity); obj != nil {
45-
return nil, &types.DuplicateName{
46-
Name: pg.Name,
47-
Object: obj.Reference(),
45+
// Standard AddDVPortgroupTask() doesn't allow duplicate names, but NSX 3.0 does create some DVPGs with the same name.
46+
// Allow duplicate names using this prefix so we can reproduce and test this condition.
47+
if !strings.HasPrefix(pg.Name, "NSX-") {
48+
if obj := Map.FindByName(pg.Name, f.ChildEntity); obj != nil {
49+
return nil, &types.DuplicateName{
50+
Name: pg.Name,
51+
Object: obj.Reference(),
52+
}
4853
}
4954
}
5055

0 commit comments

Comments
 (0)