github.com/vmware/govmomi@v0.51.0/vapi/cluster/simulator/simulator.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package simulator 6 7 import ( 8 "context" 9 "net/http" 10 "net/url" 11 "path" 12 13 "github.com/google/uuid" 14 15 "github.com/vmware/govmomi" 16 "github.com/vmware/govmomi/simulator" 17 "github.com/vmware/govmomi/vapi/rest" 18 vapi "github.com/vmware/govmomi/vapi/simulator" 19 "github.com/vmware/govmomi/vim25/types" 20 21 "github.com/vmware/govmomi/vapi/cluster" 22 "github.com/vmware/govmomi/vapi/cluster/internal" 23 ) 24 25 func init() { 26 simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) { 27 New(r, s.Listen).Register(s, r) 28 }) 29 } 30 31 type module struct { 32 cluster.ModuleSummary 33 members map[string]bool 34 } 35 36 // Handler implements the Cluster Modules API simulator 37 type Handler struct { 38 Map *simulator.Registry 39 Modules map[string]module 40 URL *url.URL 41 } 42 43 // New creates a Handler instance 44 func New(r *simulator.Registry, u *url.URL) *Handler { 45 return &Handler{ 46 Map: r, 47 Modules: make(map[string]module), 48 URL: u, 49 } 50 } 51 52 // Register Cluster Modules API paths with the vapi simulator's http.ServeMux 53 func (h *Handler) Register(s *simulator.Service, r *simulator.Registry) { 54 if r.IsVPX() { 55 s.HandleFunc(rest.Path+internal.ModulesPath, h.modules) 56 s.HandleFunc(rest.Path+internal.ModulesPath+"/", h.modules) 57 s.HandleFunc(rest.Path+internal.ModulesVMPath+"/", h.modulesVM) 58 } 59 } 60 61 func (h *Handler) modules(w http.ResponseWriter, r *http.Request) { 62 switch r.Method { 63 case http.MethodGet: 64 var modules cluster.ModuleSummaryList 65 for _, s := range h.Modules { 66 modules.Summaries = append(modules.Summaries, s.ModuleSummary) 67 } 68 vapi.OK(w, modules) 69 case http.MethodPost: 70 var m internal.CreateModule 71 if vapi.Decode(r, w, &m) { 72 ref := types.ManagedObjectReference{Type: "ClusterComputeResource", Value: m.Spec.ID} 73 if h.Map.Get(ref) == nil { 74 vapi.BadRequest(w, "com.vmware.vapi.std.errors.invalid_argument") 75 return 76 } 77 78 id := uuid.New().String() 79 h.Modules[id] = module{ 80 cluster.ModuleSummary{ 81 Cluster: m.Spec.ID, 82 Module: id, 83 }, 84 make(map[string]bool), 85 } 86 vapi.OK(w, id) 87 } 88 case http.MethodDelete: 89 id := path.Base(r.URL.Path) 90 _, ok := h.Modules[id] 91 if !ok { 92 http.NotFound(w, r) 93 return 94 } 95 delete(h.Modules, id) 96 vapi.OK(w) 97 } 98 } 99 100 func (*Handler) action(r *http.Request) string { 101 return r.URL.Query().Get("action") 102 } 103 104 func (h *Handler) addMembers(members internal.ModuleMembers, m module) bool { 105 cluster := types.ManagedObjectReference{Type: "ClusterComputeResource", Value: m.Cluster} 106 c, err := govmomi.NewClient(context.Background(), h.URL, true) 107 if err != nil { 108 panic(err) 109 } 110 vms, err := internal.ClusterVM(c.Client, cluster) 111 if err != nil { 112 panic(err) 113 } 114 _ = c.Logout(context.Background()) 115 116 validVM := func(id string) bool { 117 for i := range vms { 118 if vms[i].Reference().Value == id { 119 return true 120 } 121 } 122 return false 123 } 124 125 for _, id := range members.VMs { 126 if m.members[id] { 127 return false 128 } 129 if !validVM(id) { 130 return false 131 } 132 m.members[id] = true 133 } 134 return true 135 } 136 137 func (h *Handler) removeMembers(members internal.ModuleMembers, m module) bool { 138 for _, id := range members.VMs { 139 if !m.members[id] { 140 return false 141 } 142 delete(m.members, id) 143 } 144 return true 145 } 146 147 func (h *Handler) modulesVM(w http.ResponseWriter, r *http.Request) { 148 p := path.Dir(r.URL.Path) 149 id := path.Base(p) 150 151 m, ok := h.Modules[id] 152 if !ok { 153 http.NotFound(w, r) 154 return 155 } 156 157 switch r.Method { 158 case http.MethodGet: 159 var members internal.ModuleMembers 160 for member := range m.members { 161 members.VMs = append(members.VMs, member) 162 } 163 vapi.OK(w, members) 164 case http.MethodPost: 165 action := h.addMembers 166 167 switch h.action(r) { 168 case "add": 169 case "remove": 170 action = h.removeMembers 171 default: 172 http.NotFound(w, r) 173 return 174 } 175 176 var status internal.Status 177 var members internal.ModuleMembers 178 if vapi.Decode(r, w, &members) { 179 status.Success = action(members, m) 180 vapi.OK(w, status) 181 } 182 } 183 }