vitess.io/vitess@v0.16.2/go/vt/vtgate/debugenv.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     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 vtgate
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"html"
    23  	"net/http"
    24  	"strconv"
    25  	"text/template"
    26  	"time"
    27  
    28  	"vitess.io/vitess/go/acl"
    29  	"vitess.io/vitess/go/vt/discovery"
    30  	"vitess.io/vitess/go/vt/log"
    31  )
    32  
    33  var (
    34  	debugEnvHeader = []byte(`
    35  	<thead><tr>
    36  		<th>Variable Name</th>
    37  		<th>Value</th>
    38  		<th>Action</th>
    39  	</tr></thead>
    40  	`)
    41  	debugEnvRow = template.Must(template.New("debugenv").Parse(`
    42  	<tr><form method="POST">
    43  		<td>{{.VarName}}</td>
    44  		<td>
    45  			<input type="hidden" name="varname" value="{{.VarName}}"></input>
    46  			<input type="text" name="value" value="{{.Value}}"></input>
    47  		</td>
    48  		<td><input type="submit" name="Action" value="Modify"></input></td>
    49  	</form></tr>
    50  	`))
    51  	gridTable = []byte(`<!DOCTYPE html>
    52  	<style type="text/css">
    53  			table.gridtable {
    54  				font-family: verdana,arial,sans-serif;
    55  				font-size: 11px;
    56  				border-width: 1px;
    57  				border-collapse: collapse; table-layout:fixed; overflow: hidden;
    58  			}
    59  			table.gridtable th {
    60  				border-width: 1px;
    61  				padding: 8px;
    62  				border-style: solid;
    63  				background-color: #dedede;
    64  				white-space: nowrap;
    65  			}
    66  			table.gridtable td {
    67  				border-width: 1px;
    68  				padding: 5px;
    69  				border-style: solid;
    70  			}
    71  			table.gridtable th {
    72  				padding-left: 2em;
    73  				padding-right: 2em;
    74  			}
    75  	</style>
    76  	`)
    77  	startTable = []byte(`
    78  	<table class="gridtable">
    79  	`)
    80  	endTable = []byte(`
    81  	</table>
    82  	`)
    83  )
    84  
    85  type envValue struct {
    86  	VarName string
    87  	Value   string
    88  }
    89  
    90  func debugEnvHandler(vtg *VTGate, w http.ResponseWriter, r *http.Request) {
    91  	if err := acl.CheckAccessHTTP(r, acl.ADMIN); err != nil {
    92  		acl.SendError(w, err)
    93  		return
    94  	}
    95  
    96  	var msg string
    97  	if r.Method == "POST" {
    98  		varname := r.FormValue("varname")
    99  		value := r.FormValue("value")
   100  		setIntVal := func(f func(int)) {
   101  			ival, err := strconv.Atoi(value)
   102  			if err != nil {
   103  				msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err)
   104  				return
   105  			}
   106  			f(ival)
   107  			msg = fmt.Sprintf("Setting %v to: %v", varname, value)
   108  		}
   109  		setDurationVal := func(f func(time.Duration)) {
   110  			durationVal, err := time.ParseDuration(value)
   111  			if err != nil {
   112  				msg = fmt.Sprintf("Failed setting value for %v: %v", varname, err)
   113  				return
   114  			}
   115  			f(durationVal)
   116  			msg = fmt.Sprintf("Setting %v to: %v", varname, value)
   117  		}
   118  		switch varname {
   119  		case "discovery_low_replication_lag":
   120  			setDurationVal(discovery.SetLowReplicationLag)
   121  		case "discovery_high_replication_lag_minimum_serving":
   122  			setDurationVal(discovery.SetHighReplicationLagMinServing)
   123  		case "min_num_tablets":
   124  			setIntVal(discovery.SetMinNumTablets)
   125  		}
   126  	}
   127  
   128  	var vars []envValue
   129  	addIntVar := func(varname string, f func() int) {
   130  		vars = append(vars, envValue{
   131  			VarName: varname,
   132  			Value:   fmt.Sprintf("%v", f()),
   133  		})
   134  	}
   135  	addDurationVar := func(varname string, f func() time.Duration) {
   136  		vars = append(vars, envValue{
   137  			VarName: varname,
   138  			Value:   fmt.Sprintf("%v", f()),
   139  		})
   140  	}
   141  	addDurationVar("discovery_low_replication_lag", discovery.GetLowReplicationLag)
   142  	addDurationVar("discovery_high_replication_lag_minimum_serving", discovery.GetHighReplicationLagMinServing)
   143  	addIntVar("min_num_tablets", discovery.GetMinNumTablets)
   144  
   145  	format := r.FormValue("format")
   146  	if format == "json" {
   147  		mvars := make(map[string]string)
   148  		for _, v := range vars {
   149  			mvars[v.VarName] = v.Value
   150  		}
   151  		w.Header().Set("Content-Type", "application/json")
   152  		_ = json.NewEncoder(w).Encode(mvars)
   153  		return
   154  	}
   155  
   156  	w.Write(gridTable)
   157  	w.Write([]byte("<h3>Internal Variables</h3>\n"))
   158  	if msg != "" {
   159  		fmt.Fprintf(w, "<b>%s</b><br /><br />\n", html.EscapeString(msg))
   160  	}
   161  	w.Write(startTable)
   162  	w.Write(debugEnvHeader)
   163  	for _, v := range vars {
   164  		if err := debugEnvRow.Execute(w, v); err != nil {
   165  			log.Errorf("debugenv: couldn't execute template: %v", err)
   166  		}
   167  	}
   168  	w.Write(endTable)
   169  }