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  }