github.com/vmware/govmomi@v0.51.0/vapi/vcenter/consumptiondomains/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  	"net/http"
     9  	"net/url"
    10  	"strings"
    11  
    12  	"github.com/vmware/govmomi/simulator"
    13  	vapi "github.com/vmware/govmomi/vapi/simulator"
    14  	"github.com/vmware/govmomi/vapi/vcenter/consumptiondomains/zones"
    15  )
    16  
    17  const (
    18  	zonesPath        = "/api/vcenter/consumption-domains/zones"
    19  	associationsPath = "/api/vcenter/consumption-domains/zones/cluster"
    20  )
    21  
    22  func init() {
    23  	simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) {
    24  		New(s.Listen).Register(s, r)
    25  	})
    26  }
    27  
    28  // ZoneData Helper type to store simulated entries
    29  type ZoneData struct {
    30  	Name         string
    31  	Id           string
    32  	Description  string
    33  	Associations []string
    34  }
    35  
    36  // Handler implements the Cluster Modules API simulator
    37  type Handler struct {
    38  	URL  *url.URL
    39  	data map[string]*ZoneData
    40  }
    41  
    42  // New creates a Handler instance
    43  func New(u *url.URL) *Handler {
    44  	return &Handler{
    45  		URL:  u,
    46  		data: make(map[string]*ZoneData),
    47  	}
    48  }
    49  
    50  // Register Consumption Domains API paths with the vapi simulator's http.ServeMux
    51  func (h *Handler) Register(s *simulator.Service, r *simulator.Registry) {
    52  	if r.IsVPX() {
    53  		s.HandleFunc(zonesPath, h.zones)
    54  		s.HandleFunc(zonesPath+"/", h.zones)
    55  		s.HandleFunc(associationsPath, h.associations)
    56  		s.HandleFunc(associationsPath+"/", h.associations)
    57  	}
    58  }
    59  
    60  func (h *Handler) zones(w http.ResponseWriter, r *http.Request) {
    61  	subpath := r.URL.Path[len(zonesPath):]
    62  	zoneId := strings.Replace(subpath, "/", "", -1)
    63  
    64  	switch r.Method {
    65  	case http.MethodGet:
    66  		if len(subpath) > 0 {
    67  			if d, ok := h.data[zoneId]; ok {
    68  				vapi.StatusOK(w, zones.ZoneInfo{Description: d.Description})
    69  				return
    70  			}
    71  			vapi.ApiErrorNotFound(w)
    72  		} else {
    73  			items := make([]zones.ListItem, len(h.data))
    74  			i := 0
    75  			for _, d := range h.data {
    76  				item := zones.ListItem{
    77  					Zone: d.Name,
    78  					Info: zones.ZoneInfo{
    79  						Description: d.Description,
    80  					},
    81  				}
    82  				items[i] = item
    83  				i++
    84  			}
    85  
    86  			result := zones.ListResult{Items: items}
    87  			vapi.StatusOK(w, result)
    88  		}
    89  	case http.MethodPost:
    90  		var spec zones.CreateSpec
    91  		if !vapi.Decode(r, w, &spec) {
    92  			vapi.ApiErrorGeneral(w)
    93  			return
    94  		}
    95  
    96  		newZone := ZoneData{
    97  			Name:         spec.Zone,
    98  			Description:  spec.Description,
    99  			Id:           spec.Zone,
   100  			Associations: make([]string, 0),
   101  		}
   102  		h.data[newZone.Id] = &newZone
   103  
   104  		vapi.StatusOK(w, newZone.Id)
   105  	case http.MethodDelete:
   106  		if _, ok := h.data[zoneId]; ok {
   107  			delete(h.data, zoneId)
   108  			vapi.StatusOK(w)
   109  			return
   110  		}
   111  		vapi.ApiErrorNotFound(w)
   112  	}
   113  }
   114  
   115  func (h *Handler) associations(w http.ResponseWriter, r *http.Request) {
   116  	subpath := r.URL.Path[len(associationsPath)+1:]
   117  	pathParts := strings.Split(subpath, "/")
   118  
   119  	if len(pathParts) != 2 || pathParts[1] != "associations" {
   120  		vapi.ApiErrorNotFound(w)
   121  		return
   122  	}
   123  
   124  	zoneId := pathParts[0]
   125  
   126  	switch r.Method {
   127  	case http.MethodGet:
   128  		if d, ok := h.data[zoneId]; ok {
   129  			vapi.StatusOK(w, d.Associations)
   130  			return
   131  		}
   132  	case http.MethodPost:
   133  		action := r.URL.Query().Get("action")
   134  
   135  		var clusterIds []string
   136  		if !vapi.Decode(r, w, &clusterIds) {
   137  			vapi.ApiErrorGeneral(w)
   138  			return
   139  		}
   140  
   141  		switch action {
   142  		case "add":
   143  			if d, ok := h.data[zoneId]; ok {
   144  				associations := append(d.Associations, clusterIds...)
   145  				d.Associations = associations
   146  				res := make(map[string]any)
   147  				res["success"] = true
   148  				vapi.StatusOK(w, res)
   149  				return
   150  			}
   151  			vapi.ApiErrorNotFound(w)
   152  		case "remove":
   153  			if d, ok := h.data[zoneId]; ok {
   154  				associations := make([]string, 0)
   155  
   156  				for _, a := range d.Associations {
   157  					found := false
   158  					for _, id := range clusterIds {
   159  						if a == id {
   160  							found = true
   161  						}
   162  					}
   163  
   164  					if !found {
   165  						associations = append(associations, a)
   166  					}
   167  				}
   168  
   169  				d.Associations = associations
   170  
   171  				vapi.StatusOK(w, nil)
   172  				return
   173  			}
   174  			vapi.ApiErrorNotFound(w)
   175  		default:
   176  			vapi.ApiErrorGeneral(w)
   177  		}
   178  	}
   179  }