github.com/vmware/govmomi@v0.37.2/vapi/appliance/simulator/simulator.go (about)

     1  /*
     2  Copyright (c) 2022 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  	"encoding/json"
    21  	"log"
    22  	"net/http"
    23  	"net/url"
    24  	"time"
    25  
    26  	"github.com/vmware/govmomi/simulator"
    27  	"github.com/vmware/govmomi/vapi/appliance/access/consolecli"
    28  	"github.com/vmware/govmomi/vapi/appliance/access/dcui"
    29  	"github.com/vmware/govmomi/vapi/appliance/access/shell"
    30  	"github.com/vmware/govmomi/vapi/appliance/access/ssh"
    31  	"github.com/vmware/govmomi/vapi/appliance/shutdown"
    32  	vapi "github.com/vmware/govmomi/vapi/simulator"
    33  )
    34  
    35  func init() {
    36  	simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) {
    37  		New(s.Listen).Register(s, r)
    38  	})
    39  }
    40  
    41  // Handler implements the Appliance API simulator
    42  type Handler struct {
    43  	URL            *url.URL
    44  	consolecli     consolecli.Access
    45  	dcui           dcui.Access
    46  	ssh            ssh.Access
    47  	shell          shell.Access
    48  	shutdownConfig shutdown.Config
    49  }
    50  
    51  // New creates a Handler instance
    52  func New(u *url.URL) *Handler {
    53  	return &Handler{
    54  		URL:            nil,
    55  		consolecli:     consolecli.Access{Enabled: false},
    56  		dcui:           dcui.Access{Enabled: false},
    57  		ssh:            ssh.Access{Enabled: false},
    58  		shell:          shell.Access{Enabled: false, Timeout: 0},
    59  		shutdownConfig: shutdown.Config{},
    60  	}
    61  }
    62  
    63  // Register Appliance Management API paths with the vapi simulator's http.ServeMux
    64  func (h *Handler) Register(s *simulator.Service, r *simulator.Registry) {
    65  	s.HandleFunc(consolecli.Path, h.consoleCLIAccess)
    66  	s.HandleFunc(dcui.Path, h.dcuiAccess)
    67  	s.HandleFunc(ssh.Path, h.sshAccess)
    68  	s.HandleFunc(shell.Path, h.shellAccess)
    69  	s.HandleFunc(shutdown.Path, h.shutdown)
    70  }
    71  
    72  func (h *Handler) decode(r *http.Request, w http.ResponseWriter, val interface{}) bool {
    73  	return Decode(r, w, val)
    74  }
    75  
    76  // Decode decodes the request Body into val, returns true on success, otherwise false.
    77  func Decode(request *http.Request, writer http.ResponseWriter, val interface{}) bool {
    78  	defer request.Body.Close()
    79  	err := json.NewDecoder(request.Body).Decode(val)
    80  	if err != nil {
    81  		log.Printf("%s %s: %s", request.Method, request.RequestURI, err)
    82  		return false
    83  	}
    84  	return true
    85  }
    86  
    87  func (h *Handler) consoleCLIAccess(writer http.ResponseWriter, request *http.Request) {
    88  	switch request.Method {
    89  	case http.MethodGet:
    90  		vapi.StatusOK(writer, h.consolecli.Enabled)
    91  	case http.MethodPut:
    92  		var input consolecli.Access
    93  		if h.decode(request, writer, &input) {
    94  			h.consolecli.Enabled = input.Enabled
    95  			writer.WriteHeader(http.StatusNoContent)
    96  		} else {
    97  			writer.WriteHeader(http.StatusInternalServerError)
    98  		}
    99  	default:
   100  		http.NotFound(writer, request)
   101  	}
   102  }
   103  
   104  func (h *Handler) dcuiAccess(writer http.ResponseWriter, request *http.Request) {
   105  	switch request.Method {
   106  	case http.MethodGet:
   107  		vapi.StatusOK(writer, h.dcui.Enabled)
   108  	case http.MethodPut:
   109  		var input dcui.Access
   110  		if h.decode(request, writer, &input) {
   111  			h.dcui.Enabled = input.Enabled
   112  			writer.WriteHeader(http.StatusNoContent)
   113  		} else {
   114  			writer.WriteHeader(http.StatusInternalServerError)
   115  		}
   116  	default:
   117  		http.NotFound(writer, request)
   118  	}
   119  }
   120  
   121  func (h *Handler) sshAccess(writer http.ResponseWriter, request *http.Request) {
   122  	switch request.Method {
   123  	case http.MethodGet:
   124  		vapi.StatusOK(writer, h.ssh.Enabled)
   125  	case http.MethodPut:
   126  		var input ssh.Access
   127  		if h.decode(request, writer, &input) {
   128  			h.ssh.Enabled = input.Enabled
   129  			writer.WriteHeader(http.StatusNoContent)
   130  		} else {
   131  			writer.WriteHeader(http.StatusInternalServerError)
   132  		}
   133  	default:
   134  		http.NotFound(writer, request)
   135  	}
   136  }
   137  
   138  func (h *Handler) shellAccess(writer http.ResponseWriter, request *http.Request) {
   139  	switch request.Method {
   140  	case http.MethodGet:
   141  		vapi.StatusOK(writer, h.shell)
   142  	case http.MethodPut:
   143  		var input shell.Access
   144  		if h.decode(request, writer, &input) {
   145  			h.shell.Enabled = input.Enabled
   146  			h.shell.Timeout = input.Timeout
   147  			writer.WriteHeader(http.StatusNoContent)
   148  		} else {
   149  			writer.WriteHeader(http.StatusInternalServerError)
   150  		}
   151  	default:
   152  		http.NotFound(writer, request)
   153  	}
   154  }
   155  
   156  func (h *Handler) shutdown(w http.ResponseWriter, r *http.Request) {
   157  	switch r.Method {
   158  	case http.MethodGet:
   159  		vapi.StatusOK(w, h.shutdownConfig)
   160  	case http.MethodPost:
   161  		switch r.URL.Query().Get(shutdown.Action) {
   162  		case shutdown.Cancel:
   163  			h.shutdownConfig.ShutdownTime = ""
   164  			h.shutdownConfig.Action = ""
   165  			h.shutdownConfig.Reason = ""
   166  			w.WriteHeader(http.StatusNoContent)
   167  		case shutdown.Reboot:
   168  			var spec shutdown.Spec
   169  			if h.decode(r, w, &spec) {
   170  				h.shutdownConfig.ShutdownTime = time.Now().UTC().Add(time.Duration(spec.Delay) * time.Minute).String()
   171  				h.shutdownConfig.Reason = spec.Reason
   172  				h.shutdownConfig.Action = shutdown.Reboot
   173  				w.WriteHeader(http.StatusNoContent)
   174  			}
   175  		case shutdown.PowerOff:
   176  			var spec shutdown.Spec
   177  			if h.decode(r, w, &spec) {
   178  				h.shutdownConfig.ShutdownTime = time.Now().UTC().Add(time.Duration(spec.Delay) * time.Minute).String()
   179  				h.shutdownConfig.Reason = spec.Reason
   180  				h.shutdownConfig.Action = shutdown.PowerOff
   181  				w.WriteHeader(http.StatusNoContent)
   182  			}
   183  		default:
   184  			http.NotFound(w, r)
   185  		}
   186  	default:
   187  		http.NotFound(w, r)
   188  	}
   189  }