vitess.io/vitess@v0.16.2/go/vt/discovery/tablet_health.go (about)

     1  /*
     2  Copyright 2020 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 discovery
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"strings"
    23  
    24  	"vitess.io/vitess/go/vt/topo/topoproto"
    25  
    26  	"vitess.io/vitess/go/vt/vttablet/queryservice"
    27  
    28  	"google.golang.org/protobuf/proto"
    29  
    30  	"vitess.io/vitess/go/netutil"
    31  	"vitess.io/vitess/go/vt/proto/query"
    32  	"vitess.io/vitess/go/vt/proto/topodata"
    33  )
    34  
    35  // TabletHealth represents simple tablet health data that is returned to users of healthcheck.
    36  // No synchronization is required because we always return a copy.
    37  type TabletHealth struct {
    38  	Conn                 queryservice.QueryService
    39  	Tablet               *topodata.Tablet
    40  	Target               *query.Target
    41  	Stats                *query.RealtimeStats
    42  	PrimaryTermStartTime int64
    43  	LastError            error
    44  	Serving              bool
    45  }
    46  
    47  func (th *TabletHealth) MarshalJSON() ([]byte, error) {
    48  	return json.Marshal(&struct {
    49  		Key                                 string
    50  		Tablet                              *topodata.Tablet
    51  		Name                                string
    52  		Target                              *query.Target
    53  		Up                                  bool
    54  		Serving                             bool
    55  		PrimaryTermStartTime                int64
    56  		TabletExternallyReparentedTimestamp int64
    57  		Stats                               *query.RealtimeStats
    58  		LastError                           error
    59  	}{
    60  		// The Key and Name fields are fields that used to live in the legacy tablet health
    61  		// TODO: remove Key and Name in v15
    62  		Key:    TabletToMapKey(th.Tablet),
    63  		Tablet: th.Tablet,
    64  		Name:   topoproto.TabletAliasString(th.Tablet.Alias),
    65  		Target: th.Target,
    66  
    67  		// Setting Up to true to ensure backward compatibility
    68  		// TODO: remove Up in v15
    69  		Up: true,
    70  
    71  		Serving: th.Serving,
    72  
    73  		// We copy the PrimaryTermStartTime value onto TabletExternallyReparentedTimestamp to
    74  		// ensure backward compatibility.
    75  		// TODO: remove Up in v15
    76  		PrimaryTermStartTime:                th.PrimaryTermStartTime,
    77  		TabletExternallyReparentedTimestamp: th.PrimaryTermStartTime,
    78  
    79  		Stats:     th.Stats,
    80  		LastError: th.LastError,
    81  	})
    82  }
    83  
    84  // DeepEqual compares two TabletHealth. Since we include protos, we
    85  // need to use proto.Equal on these.
    86  func (th *TabletHealth) DeepEqual(other *TabletHealth) bool {
    87  	return proto.Equal(th.Tablet, other.Tablet) &&
    88  		proto.Equal(th.Target, other.Target) &&
    89  		th.Serving == other.Serving &&
    90  		th.PrimaryTermStartTime == other.PrimaryTermStartTime &&
    91  		proto.Equal(th.Stats, other.Stats) &&
    92  		((th.LastError == nil && other.LastError == nil) ||
    93  			(th.LastError != nil && other.LastError != nil && th.LastError.Error() == other.LastError.Error()))
    94  }
    95  
    96  // GetTabletHostPort formats a tablet host port address.
    97  func (th *TabletHealth) GetTabletHostPort() string {
    98  	hostname := th.Tablet.Hostname
    99  	vtPort := th.Tablet.PortMap["vt"]
   100  	return netutil.JoinHostPort(hostname, vtPort)
   101  }
   102  
   103  // GetHostNameLevel returns the specified hostname level. If the level does not exist it will pick the closest level.
   104  // This seems unused but can be utilized by certain url formatting templates. See getTabletDebugURL for more details.
   105  func (th *TabletHealth) GetHostNameLevel(level int) string {
   106  	hostname := th.Tablet.Hostname
   107  	chunkedHostname := strings.Split(hostname, ".")
   108  
   109  	if level < 0 {
   110  		return chunkedHostname[0]
   111  	} else if level >= len(chunkedHostname) {
   112  		return chunkedHostname[len(chunkedHostname)-1]
   113  	} else {
   114  		return chunkedHostname[level]
   115  	}
   116  }
   117  
   118  // getTabletDebugURL formats a debug url to the tablet.
   119  // It uses a format string that can be passed into the app to format
   120  // the debug URL to accommodate different network setups. It applies
   121  // the html/template string defined to a tabletHealthCheck object. The
   122  // format string can refer to members and functions of tabletHealthCheck
   123  // like a regular html/template string.
   124  //
   125  // For instance given a tablet with hostname:port of host.dc.domain:22
   126  // could be configured as follows:
   127  // http://{{.GetTabletHostPort}} -> http://host.dc.domain:22
   128  // https://{{.Tablet.Hostname}} -> https://host.dc.domain
   129  // https://{{.GetHostNameLevel 0}}.bastion.corp -> https://host.bastion.corp
   130  func (th *TabletHealth) getTabletDebugURL() string {
   131  	var buffer bytes.Buffer
   132  	_ = tabletURLTemplate.Execute(&buffer, th)
   133  	return buffer.String()
   134  }