...

Source file src/edge-infra.dev/pkg/sds/interlock/topic/host/vnc_state.go

Documentation: edge-infra.dev/pkg/sds/interlock/topic/host

     1  package host
     2  
     3  import (
     4  	"net/http"
     5  	"time"
     6  
     7  	"github.com/gin-gonic/gin"
     8  	"github.com/gin-gonic/gin/binding"
     9  
    10  	"edge-infra.dev/pkg/sds/interlock/topic"
    11  )
    12  
    13  // VNCStatus represents the status of a VNC request
    14  //
    15  // swagger:enum VNCStatus
    16  type VNCStatus string
    17  
    18  // VNC represents a VNC state for a request
    19  type VNC struct {
    20  	// RequestID is the ID of the VNC request
    21  	RequestID string `json:"requestId"`
    22  	// Status is the status of the VNC request
    23  	Status VNCStatus `json:"status"`
    24  	// Connections is the number of active connections on the VNC request
    25  	Connections int `json:"connections"`
    26  	// TimeStamp is the time when the VNC state was last updated
    27  	TimeStamp string `json:"timestamp"`
    28  }
    29  
    30  // VNC states is a slice of VNC objects
    31  //
    32  // swagger:model
    33  type VNCStates []VNC
    34  
    35  const (
    36  	Requested VNCStatus = "REQUESTED"
    37  	Accepted  VNCStatus = "ACCEPTED"
    38  	Suspended VNCStatus = "SUSPENDED"
    39  	Rejected  VNCStatus = "REJECTED"
    40  	Dropped   VNCStatus = "DROPPED"
    41  	Connected VNCStatus = "CONNECTED"
    42  )
    43  
    44  // VNCPost handles updates to the VNC state of the host node. Since the VNC field is a slice of objects,
    45  // the request ID is used to identify the VNC state that needs to be updated.
    46  func (h *Host) VNCPost(c *gin.Context) {
    47  	err := h.topic.UpdateState(
    48  		func(state interface{}) error {
    49  			var payload postVNCPayload
    50  			if err := c.ShouldBindWith(&payload, binding.JSON); err != nil {
    51  				return err
    52  			}
    53  			hostState := state.(*State)
    54  			updateStateVNC(hostState, payload)
    55  			c.JSON(http.StatusAccepted, state)
    56  			return nil
    57  		},
    58  	)
    59  	if err != nil {
    60  		topic.HandleBindingError(c, err)
    61  		return
    62  	}
    63  }
    64  
    65  // updateStateVNC updates the VNC state of the host node according to the following rules:
    66  // - if the request ID is not found in the host state it will add a new VNC state.
    67  // - if the request ID is found in the host state and the status is Dropped it will remove the VNC state.
    68  // - if the request ID is found in the host state and the status is not Dropped it will update the corresponding VNC state.
    69  // - if the request ID is not found and the payload status is Dropped it will be ignored
    70  func updateStateVNC(hostState *State, payload postVNCPayload) {
    71  	// Use payload timestamp if non-zero, otherwise use current time
    72  	timestamp := payload.TimeStamp
    73  	if timestamp.IsZero() {
    74  		timestamp = time.Now()
    75  	}
    76  
    77  	val := VNC{
    78  		RequestID:   payload.RequestID,
    79  		Status:      payload.Status,
    80  		Connections: payload.Connections,
    81  		TimeStamp:   timestamp.Format(time.RFC3339),
    82  	}
    83  
    84  	// Case where the VNC state already exists
    85  	for i, vnc := range hostState.VNC {
    86  		// Ignore this VNC entry if the request ID doesn't match
    87  		if vnc.RequestID != payload.RequestID {
    88  			continue
    89  		}
    90  		// Remove the VNC state if the status is Dropped
    91  		if payload.Status == Dropped {
    92  			hostState.VNC = removeVNC(hostState.VNC, i)
    93  			return
    94  		}
    95  		// Otherwise update the VNC state
    96  		hostState.VNC[i] = val
    97  		return
    98  	}
    99  	// Case where the VNC state doesn't exist
   100  	// return without adding a new VNC state if the status is Dropped
   101  	if payload.Status == Dropped {
   102  		return
   103  	}
   104  	// else add a new VNC state
   105  	hostState.VNC = append(hostState.VNC, val)
   106  }
   107  
   108  func removeVNC(vncs VNCStates, i int) VNCStates {
   109  	return append(vncs[:i], vncs[i+1:]...)
   110  }
   111  
   112  // VNCPut resets and replaces VNC state of the host node. All existing VNC states are removed and replaced
   113  // with any payload. An empty list or nil is valid and will just reset state. An empty payload is invalid.
   114  func (h *Host) VNCPut(c *gin.Context) {
   115  	err := h.topic.UpdateState(
   116  		func(state interface{}) error {
   117  			var payload putVNCPayloads
   118  			if err := c.ShouldBindWith(&payload, binding.JSON); err != nil {
   119  				return err
   120  			}
   121  			if err := payload.validateRequestIDs(); err != nil {
   122  				return err
   123  			}
   124  			hostState := state.(*State)
   125  			hostState.VNC = []VNC{}
   126  			for _, p := range payload {
   127  				hostState.VNC = append(hostState.VNC, VNC{
   128  					RequestID:   p.RequestID,
   129  					Status:      p.Status,
   130  					Connections: p.Connections,
   131  					TimeStamp:   p.TimeStamp.Format(time.RFC3339),
   132  				})
   133  			}
   134  			c.JSON(http.StatusAccepted, state)
   135  			return nil
   136  		},
   137  	)
   138  	if err != nil {
   139  		topic.HandleBindingError(c, err)
   140  		return
   141  	}
   142  }
   143  
   144  // Everything below this point is used for documentation purposes and exists for
   145  // the purpose of generating the swagger spec only.
   146  
   147  // The VNCPost parameters
   148  //
   149  // swagger:parameters VNCPost
   150  type VNCPostParams struct {
   151  	// in: body
   152  	Body postVNCPayload
   153  }
   154  
   155  // swagger:route POST /v1/host/vnc host VNCPost
   156  // Update the VNC state of the host node
   157  // responses:
   158  //   202: HostStateResponse
   159  //   400: ErrorResponse
   160  //   405: ErrorResponse
   161  //   500: ErrorResponse
   162  
   163  // The VNCPut parameters
   164  //
   165  // swagger:parameters VNCPut
   166  type VNCPutParams struct {
   167  	// in: body
   168  	Body putVNCPayloads
   169  }
   170  
   171  // swagger:route PUT /v1/host/vnc host VNCPut
   172  // Reset and replace the VNC state of the host node
   173  // responses:
   174  //   202: HostStateResponse
   175  //   400: ErrorResponse
   176  //   405: ErrorResponse
   177  //   500: ErrorResponse
   178  

View as plain text