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

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