go.ligato.io/vpp-agent/v3@v3.5.0/plugins/govppmux/rest.go (about)

     1  //  Copyright (c) 2019 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  package govppmux
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"io"
    21  	"net/http"
    22  	"net/rpc"
    23  
    24  	"github.com/unrolled/render"
    25  	"go.ligato.io/cn-infra/v2/rpc/rest"
    26  )
    27  
    28  // registerHandlers registers all supported REST APIs.
    29  func (p *Plugin) registerHandlers(http rest.HTTPHandlers) {
    30  	if http == nil {
    31  		p.Log.Debug("No http handler provided, skipping registration of REST handlers")
    32  		return
    33  	}
    34  	http.RegisterHTTPHandler("/govppmux/stats", p.statsHandler, "GET")
    35  	http.RegisterHTTPHandler(rpc.DefaultRPCPath, p.proxyHandler, "CONNECT")
    36  	http.RegisterHTTPHandler("/vpp/command", p.cliCommandHandler, "POST")
    37  }
    38  
    39  func (p *Plugin) statsHandler(formatter *render.Render) http.HandlerFunc {
    40  	return func(w http.ResponseWriter, req *http.Request) {
    41  		if err := formatter.JSON(w, http.StatusOK, GetStats()); err != nil {
    42  			p.Log.Warnf("stats handler errored: %v", err)
    43  		}
    44  	}
    45  }
    46  
    47  func (p *Plugin) proxyHandler(_ *render.Render) http.HandlerFunc {
    48  	if !p.config.ProxyEnabled {
    49  		return func(w http.ResponseWriter, req *http.Request) {
    50  			http.Error(w, "VPP proxy not enabled", http.StatusServiceUnavailable)
    51  		}
    52  	}
    53  	return func(w http.ResponseWriter, req *http.Request) {
    54  		p.proxy.ServeHTTP(w, req)
    55  	}
    56  }
    57  
    58  func (p *Plugin) cliCommandHandler(formatter *render.Render) http.HandlerFunc {
    59  	return func(w http.ResponseWriter, req *http.Request) {
    60  		body, err := io.ReadAll(req.Body)
    61  		if err != nil {
    62  			errMsg := fmt.Sprintf("400 Bad request: failed to parse request body: %v", err)
    63  			_ = formatter.JSON(w, http.StatusBadRequest, errMsg)
    64  			return
    65  		}
    66  		var reqParam map[string]string
    67  
    68  		if err = json.Unmarshal(body, &reqParam); err != nil {
    69  			errMsg := fmt.Sprintf("400 Bad request: failed to unmarshall request body: %v\n", err)
    70  			_ = formatter.JSON(w, http.StatusBadRequest, errMsg)
    71  			return
    72  		}
    73  		command, ok := reqParam["vppclicommand"]
    74  		if !ok || command == "" {
    75  			errMsg := "400 Bad request: vppclicommand parameter missing or empty\n"
    76  			_ = formatter.JSON(w, http.StatusBadRequest, errMsg)
    77  			return
    78  		}
    79  
    80  		p.Log.Debugf("VPPCLI command: %v", command)
    81  		reply, err := p.vpeHandler.RunCli(req.Context(), command)
    82  		if err != nil {
    83  			errMsg := fmt.Sprintf("500 Internal server error: sending request failed: %v\n", err)
    84  			_ = formatter.JSON(w, http.StatusInternalServerError, errMsg)
    85  			return
    86  		}
    87  
    88  		p.Log.Debugf("VPPCLI response: %s", reply)
    89  		_ = formatter.JSON(w, http.StatusOK, reply)
    90  	}
    91  }