github.com/vmware/govmomi@v0.43.0/vapi/cluster/simulator/simulator.go (about)

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