github.com/vmware/govmomi@v0.43.0/simulator/dvs.go (about) 1 /* 2 Copyright (c) 2017 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package simulator 18 19 import ( 20 "fmt" 21 "strconv" 22 "strings" 23 24 "github.com/google/uuid" 25 26 "github.com/vmware/govmomi/vim25/methods" 27 "github.com/vmware/govmomi/vim25/mo" 28 "github.com/vmware/govmomi/vim25/soap" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 type DistributedVirtualSwitch struct { 33 mo.DistributedVirtualSwitch 34 35 types.FetchDVPortsResponse 36 } 37 38 func (s *DistributedVirtualSwitch) eventArgument() *types.DvsEventArgument { 39 return &types.DvsEventArgument{ 40 EntityEventArgument: types.EntityEventArgument{ 41 Name: s.Name, 42 }, 43 Dvs: s.Self, 44 } 45 } 46 47 func (s *DistributedVirtualSwitch) event() types.DvsEvent { 48 return types.DvsEvent{ 49 Event: types.Event{ 50 Datacenter: datacenterEventArgument(s), 51 Dvs: s.eventArgument(), 52 }, 53 } 54 } 55 56 func (s *DistributedVirtualSwitch) AddDVPortgroupTask(ctx *Context, c *types.AddDVPortgroup_Task) soap.HasFault { 57 task := CreateTask(s, "addDVPortgroup", func(t *Task) (types.AnyType, types.BaseMethodFault) { 58 f := ctx.Map.getEntityParent(s, "Folder").(*Folder) 59 60 portgroups := s.Portgroup 61 portgroupNames := s.Summary.PortgroupName 62 63 for _, spec := range c.Spec { 64 pg := &DistributedVirtualPortgroup{} 65 pg.Name = spec.Name 66 pg.Entity().Name = pg.Name 67 68 // Standard AddDVPortgroupTask() doesn't allow duplicate names, but NSX 3.0 does create some DVPGs with the same name. 69 // Allow duplicate names using this prefix so we can reproduce and test this condition. 70 if strings.HasPrefix(pg.Name, "NSX-") || spec.BackingType == string(types.DistributedVirtualPortgroupBackingTypeNsx) { 71 if spec.LogicalSwitchUuid == "" { 72 spec.LogicalSwitchUuid = uuid.New().String() 73 } 74 if spec.SegmentId == "" { 75 spec.SegmentId = fmt.Sprintf("/infra/segments/vnet_%s", uuid.New().String()) 76 } 77 78 } else { 79 if obj := ctx.Map.FindByName(pg.Name, f.ChildEntity); obj != nil { 80 return nil, &types.DuplicateName{ 81 Name: pg.Name, 82 Object: obj.Reference(), 83 } 84 } 85 } 86 87 folderPutChild(ctx, &f.Folder, pg) 88 89 pg.Key = pg.Self.Value 90 pg.Config = types.DVPortgroupConfigInfo{ 91 Key: pg.Key, 92 Name: pg.Name, 93 NumPorts: spec.NumPorts, 94 DistributedVirtualSwitch: &s.Self, 95 DefaultPortConfig: spec.DefaultPortConfig, 96 Description: spec.Description, 97 Type: spec.Type, 98 Policy: spec.Policy, 99 PortNameFormat: spec.PortNameFormat, 100 Scope: spec.Scope, 101 VendorSpecificConfig: spec.VendorSpecificConfig, 102 ConfigVersion: spec.ConfigVersion, 103 AutoExpand: spec.AutoExpand, 104 VmVnicNetworkResourcePoolKey: spec.VmVnicNetworkResourcePoolKey, 105 LogicalSwitchUuid: spec.LogicalSwitchUuid, 106 SegmentId: spec.SegmentId, 107 BackingType: spec.BackingType, 108 } 109 110 if pg.Config.LogicalSwitchUuid != "" { 111 if pg.Config.BackingType == "" { 112 pg.Config.BackingType = "nsx" 113 } 114 } 115 116 if pg.Config.DefaultPortConfig == nil { 117 pg.Config.DefaultPortConfig = &types.VMwareDVSPortSetting{ 118 Vlan: new(types.VmwareDistributedVirtualSwitchVlanIdSpec), 119 UplinkTeamingPolicy: &types.VmwareUplinkPortTeamingPolicy{ 120 Policy: &types.StringPolicy{ 121 Value: "loadbalance_srcid", 122 }, 123 ReversePolicy: &types.BoolPolicy{ 124 Value: types.NewBool(true), 125 }, 126 NotifySwitches: &types.BoolPolicy{ 127 Value: types.NewBool(true), 128 }, 129 RollingOrder: &types.BoolPolicy{ 130 Value: types.NewBool(true), 131 }, 132 }, 133 } 134 } 135 136 if pg.Config.Policy == nil { 137 pg.Config.Policy = &types.VMwareDVSPortgroupPolicy{ 138 DVPortgroupPolicy: types.DVPortgroupPolicy{ 139 BlockOverrideAllowed: true, 140 ShapingOverrideAllowed: false, 141 VendorConfigOverrideAllowed: false, 142 LivePortMovingAllowed: false, 143 PortConfigResetAtDisconnect: true, 144 NetworkResourcePoolOverrideAllowed: types.NewBool(false), 145 TrafficFilterOverrideAllowed: types.NewBool(false), 146 }, 147 VlanOverrideAllowed: false, 148 UplinkTeamingOverrideAllowed: false, 149 SecurityPolicyOverrideAllowed: false, 150 IpfixOverrideAllowed: types.NewBool(false), 151 } 152 } 153 154 for i := 0; i < int(spec.NumPorts); i++ { 155 pg.PortKeys = append(pg.PortKeys, strconv.Itoa(i)) 156 } 157 158 portgroups = append(portgroups, pg.Self) 159 portgroupNames = append(portgroupNames, pg.Name) 160 161 for _, h := range s.Summary.HostMember { 162 pg.Host = append(pg.Host, h) 163 164 host := ctx.Map.Get(h).(*HostSystem) 165 ctx.Map.AppendReference(ctx, host, &host.Network, pg.Reference()) 166 167 parent := ctx.Map.Get(*host.HostSystem.Parent) 168 computeNetworks := append(hostParent(&host.HostSystem).Network, pg.Reference()) 169 ctx.Map.Update(parent, []types.PropertyChange{ 170 {Name: "network", Val: computeNetworks}, 171 }) 172 } 173 174 ctx.postEvent(&types.DVPortgroupCreatedEvent{ 175 DVPortgroupEvent: pg.event(ctx), 176 }) 177 } 178 179 ctx.Map.Update(s, []types.PropertyChange{ 180 {Name: "portgroup", Val: portgroups}, 181 {Name: "summary.portgroupName", Val: portgroupNames}, 182 }) 183 184 return nil, nil 185 }) 186 187 return &methods.AddDVPortgroup_TaskBody{ 188 Res: &types.AddDVPortgroup_TaskResponse{ 189 Returnval: task.Run(ctx), 190 }, 191 } 192 } 193 194 func (s *DistributedVirtualSwitch) ReconfigureDvsTask(ctx *Context, req *types.ReconfigureDvs_Task) soap.HasFault { 195 task := CreateTask(s, "reconfigureDvs", func(t *Task) (types.AnyType, types.BaseMethodFault) { 196 spec := req.Spec.GetDVSConfigSpec() 197 198 members := s.Summary.HostMember 199 200 for _, member := range spec.Host { 201 h := ctx.Map.Get(member.Host) 202 if h == nil { 203 return nil, &types.ManagedObjectNotFound{Obj: member.Host} 204 } 205 206 host := h.(*HostSystem) 207 208 switch types.ConfigSpecOperation(member.Operation) { 209 case types.ConfigSpecOperationAdd: 210 if FindReference(s.Summary.HostMember, member.Host) != nil { 211 return nil, &types.AlreadyExists{Name: host.Name} 212 } 213 214 hostNetworks := append(host.Network, s.Portgroup...) 215 ctx.Map.Update(host, []types.PropertyChange{ 216 {Name: "network", Val: hostNetworks}, 217 }) 218 members = append(members, member.Host) 219 parent := ctx.Map.Get(*host.HostSystem.Parent) 220 221 var pgs []types.ManagedObjectReference 222 for _, ref := range s.Portgroup { 223 pg := ctx.Map.Get(ref).(*DistributedVirtualPortgroup) 224 pgs = append(pgs, ref) 225 226 pgHosts := append(pg.Host, member.Host) 227 ctx.Map.Update(pg, []types.PropertyChange{ 228 {Name: "host", Val: pgHosts}, 229 }) 230 231 cr := hostParent(&host.HostSystem) 232 if FindReference(cr.Network, ref) == nil { 233 computeNetworks := append(cr.Network, ref) 234 ctx.Map.Update(parent, []types.PropertyChange{ 235 {Name: "network", Val: computeNetworks}, 236 }) 237 } 238 } 239 240 ctx.postEvent(&types.DvsHostJoinedEvent{ 241 DvsEvent: s.event(), 242 HostJoined: *host.eventArgument(), 243 }) 244 case types.ConfigSpecOperationRemove: 245 for _, ref := range host.Vm { 246 vm := ctx.Map.Get(ref).(*VirtualMachine) 247 if pg := FindReference(vm.Network, s.Portgroup...); pg != nil { 248 return nil, &types.ResourceInUse{ 249 Type: pg.Type, 250 Name: pg.Value, 251 } 252 } 253 } 254 255 RemoveReference(&members, member.Host) 256 257 ctx.postEvent(&types.DvsHostLeftEvent{ 258 DvsEvent: s.event(), 259 HostLeft: *host.eventArgument(), 260 }) 261 case types.ConfigSpecOperationEdit: 262 return nil, &types.NotSupported{} 263 } 264 } 265 266 ctx.Map.Update(s, []types.PropertyChange{ 267 {Name: "summary.hostMember", Val: members}, 268 }) 269 270 ctx.postEvent(&types.DvsReconfiguredEvent{ 271 DvsEvent: s.event(), 272 ConfigSpec: spec, 273 }) 274 275 return nil, nil 276 }) 277 278 return &methods.ReconfigureDvs_TaskBody{ 279 Res: &types.ReconfigureDvs_TaskResponse{ 280 Returnval: task.Run(ctx), 281 }, 282 } 283 } 284 285 func (s *DistributedVirtualSwitch) FetchDVPorts(req *types.FetchDVPorts) soap.HasFault { 286 body := &methods.FetchDVPortsBody{} 287 body.Res = &types.FetchDVPortsResponse{ 288 Returnval: s.dvPortgroups(req.Criteria), 289 } 290 return body 291 } 292 293 func (s *DistributedVirtualSwitch) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault { 294 task := CreateTask(s, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { 295 // TODO: should return ResourceInUse fault if any VM is using a port on this switch 296 // and past that, remove refs from each host.Network, etc 297 f := ctx.Map.getEntityParent(s, "Folder").(*Folder) 298 folderRemoveChild(ctx, &f.Folder, s.Reference()) 299 ctx.postEvent(&types.DvsDestroyedEvent{DvsEvent: s.event()}) 300 return nil, nil 301 }) 302 303 return &methods.Destroy_TaskBody{ 304 Res: &types.Destroy_TaskResponse{ 305 Returnval: task.Run(ctx), 306 }, 307 } 308 } 309 310 func (s *DistributedVirtualSwitch) dvPortgroups(criteria *types.DistributedVirtualSwitchPortCriteria) []types.DistributedVirtualPort { 311 res := s.FetchDVPortsResponse.Returnval 312 if len(res) != 0 { 313 return res 314 } 315 316 for _, ref := range s.Portgroup { 317 pg := Map.Get(ref).(*DistributedVirtualPortgroup) 318 319 for _, key := range pg.PortKeys { 320 res = append(res, types.DistributedVirtualPort{ 321 DvsUuid: s.Uuid, 322 Key: key, 323 PortgroupKey: pg.Key, 324 Config: types.DVPortConfigInfo{ 325 Setting: pg.Config.DefaultPortConfig, 326 }, 327 }) 328 } 329 } 330 331 // filter ports by criteria 332 res = s.filterDVPorts(res, criteria) 333 334 return res 335 } 336 337 func (s *DistributedVirtualSwitch) filterDVPorts( 338 ports []types.DistributedVirtualPort, 339 criteria *types.DistributedVirtualSwitchPortCriteria, 340 ) []types.DistributedVirtualPort { 341 if criteria == nil { 342 return ports 343 } 344 345 ports = s.filterDVPortsByPortgroupKey(ports, criteria) 346 ports = s.filterDVPortsByPortKey(ports, criteria) 347 ports = s.filterDVPortsByConnected(ports, criteria) 348 349 return ports 350 } 351 352 func (s *DistributedVirtualSwitch) filterDVPortsByPortgroupKey( 353 ports []types.DistributedVirtualPort, 354 criteria *types.DistributedVirtualSwitchPortCriteria, 355 ) []types.DistributedVirtualPort { 356 if len(criteria.PortgroupKey) == 0 || criteria.Inside == nil { 357 return ports 358 } 359 360 // inside portgroup keys 361 if *criteria.Inside { 362 filtered := []types.DistributedVirtualPort{} 363 364 for _, p := range ports { 365 for _, pgk := range criteria.PortgroupKey { 366 if p.PortgroupKey == pgk { 367 filtered = append(filtered, p) 368 break 369 } 370 } 371 } 372 return filtered 373 } 374 375 // outside portgroup keys 376 filtered := []types.DistributedVirtualPort{} 377 378 for _, p := range ports { 379 found := false 380 for _, pgk := range criteria.PortgroupKey { 381 if p.PortgroupKey == pgk { 382 found = true 383 break 384 } 385 } 386 387 if !found { 388 filtered = append(filtered, p) 389 } 390 } 391 return filtered 392 } 393 394 func (s *DistributedVirtualSwitch) filterDVPortsByPortKey( 395 ports []types.DistributedVirtualPort, 396 criteria *types.DistributedVirtualSwitchPortCriteria, 397 ) []types.DistributedVirtualPort { 398 if len(criteria.PortKey) == 0 { 399 return ports 400 } 401 402 filtered := []types.DistributedVirtualPort{} 403 404 for _, p := range ports { 405 for _, pk := range criteria.PortKey { 406 if p.Key == pk { 407 filtered = append(filtered, p) 408 break 409 } 410 } 411 } 412 413 return filtered 414 } 415 416 func (s *DistributedVirtualSwitch) filterDVPortsByConnected( 417 ports []types.DistributedVirtualPort, 418 criteria *types.DistributedVirtualSwitchPortCriteria, 419 ) []types.DistributedVirtualPort { 420 if criteria.Connected == nil { 421 return ports 422 } 423 424 filtered := []types.DistributedVirtualPort{} 425 426 for _, p := range ports { 427 connected := p.Connectee != nil 428 if connected == *criteria.Connected { 429 filtered = append(filtered, p) 430 } 431 } 432 433 return filtered 434 }