1/*
2Copyright (c) 2017 VMware, Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package simulator
18
19import (
20	"strings"
21
22	"github.com/vmware/govmomi/simulator/esx"
23	"github.com/vmware/govmomi/vim25/methods"
24	"github.com/vmware/govmomi/vim25/mo"
25	"github.com/vmware/govmomi/vim25/soap"
26	"github.com/vmware/govmomi/vim25/types"
27)
28
29type Datacenter struct {
30	mo.Datacenter
31
32	isESX bool
33}
34
35// NewDatacenter creates a Datacenter and its child folders.
36func NewDatacenter(f *Folder) *Datacenter {
37	dc := &Datacenter{
38		isESX: f.Self == esx.RootFolder.Self,
39	}
40
41	if dc.isESX {
42		dc.Datacenter = esx.Datacenter
43	}
44
45	f.putChild(dc)
46
47	dc.createFolders()
48
49	return dc
50}
51
52// Create Datacenter Folders.
53// Every Datacenter has 4 inventory Folders: Vm, Host, Datastore and Network.
54// The ESX folder child types are limited to 1 type.
55// The VC folders have additional child types, including nested folders.
56func (dc *Datacenter) createFolders() {
57	folders := []struct {
58		ref   *types.ManagedObjectReference
59		name  string
60		types []string
61	}{
62		{&dc.VmFolder, "vm", []string{"VirtualMachine", "VirtualApp", "Folder"}},
63		{&dc.HostFolder, "host", []string{"ComputeResource", "Folder"}},
64		{&dc.DatastoreFolder, "datastore", []string{"Datastore", "StoragePod", "Folder"}},
65		{&dc.NetworkFolder, "network", []string{"Network", "DistributedVirtualSwitch", "Folder"}},
66	}
67
68	for _, f := range folders {
69		folder := &Folder{}
70		folder.Name = f.name
71
72		if dc.isESX {
73			folder.ChildType = f.types[:1]
74			folder.Self = *f.ref
75			Map.PutEntity(dc, folder)
76		} else {
77			folder.ChildType = f.types
78			e := Map.PutEntity(dc, folder)
79
80			// propagate the generated morefs to Datacenter
81			ref := e.Reference()
82			f.ref.Type = ref.Type
83			f.ref.Value = ref.Value
84		}
85	}
86
87	net := Map.Get(dc.NetworkFolder).(*Folder)
88
89	for _, ref := range esx.Datacenter.Network {
90		// Add VM Network by default to each Datacenter
91		network := &mo.Network{}
92		network.Self = ref
93		network.Name = strings.Split(ref.Value, "-")[1]
94		network.Entity().Name = network.Name
95		if !dc.isESX {
96			network.Self.Value = "" // we want a different moid per-DC
97		}
98
99		net.putChild(network)
100	}
101}
102
103func datacenterEventArgument(obj mo.Entity) *types.DatacenterEventArgument {
104	dc, ok := obj.(*Datacenter)
105	if !ok {
106		dc = Map.getEntityDatacenter(obj)
107	}
108	return &types.DatacenterEventArgument{
109		Datacenter:          dc.Self,
110		EntityEventArgument: types.EntityEventArgument{Name: dc.Name},
111	}
112}
113
114func (dc *Datacenter) PowerOnMultiVMTask(ctx *Context, req *types.PowerOnMultiVM_Task) soap.HasFault {
115	task := CreateTask(dc, "powerOnMultiVM", func(_ *Task) (types.AnyType, types.BaseMethodFault) {
116		if dc.isESX {
117			return nil, new(types.NotImplemented)
118		}
119
120		for _, ref := range req.Vm {
121			vm := Map.Get(ref).(*VirtualMachine)
122			Map.WithLock(vm, func() {
123				vm.PowerOnVMTask(ctx, &types.PowerOnVM_Task{})
124			})
125		}
126
127		return nil, nil
128	})
129
130	return &methods.PowerOnMultiVM_TaskBody{
131		Res: &types.PowerOnMultiVM_TaskResponse{
132			Returnval: task.Run(),
133		},
134	}
135}
136
137func (d *Datacenter) DestroyTask(req *types.Destroy_Task) soap.HasFault {
138	task := CreateTask(d, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
139		folders := []types.ManagedObjectReference{
140			d.VmFolder,
141			d.HostFolder,
142		}
143
144		for _, ref := range folders {
145			if len(Map.Get(ref).(*Folder).ChildEntity) != 0 {
146				return nil, &types.ResourceInUse{}
147			}
148		}
149
150		Map.Get(*d.Parent).(*Folder).removeChild(d.Self)
151
152		return nil, nil
153	})
154
155	return &methods.Destroy_TaskBody{
156		Res: &types.Destroy_TaskResponse{
157			Returnval: task.Run(),
158		},
159	}
160}
161