зеркало из https://github.com/github/vitess-gh.git
Moving a few status functions to this source tree.
They allow the status page of vttablet to be better. Also testing this code in vtctld_test, so we make sure the templates work. And manual inspection works very well too.
This commit is contained in:
Родитель
f7df4e7e97
Коммит
905eb39851
|
@ -5,11 +5,20 @@ import (
|
|||
|
||||
"github.com/youtube/vitess/go/vt/health"
|
||||
"github.com/youtube/vitess/go/vt/servenv"
|
||||
_ "github.com/youtube/vitess/go/vt/status"
|
||||
"github.com/youtube/vitess/go/vt/tabletmanager"
|
||||
"github.com/youtube/vitess/go/vt/tabletserver"
|
||||
)
|
||||
|
||||
var (
|
||||
tabletTemplate = `
|
||||
Alias: {{github_com_youtube_vitess_vtctld_tablet .Alias.String}}<br>
|
||||
Keyspace: {{github_com_youtube_vitess_vtctld_keyspace .Keyspace}} Shard: {{github_com_youtube_vitess_vtctld_shard .Keyspace .Shard}}<br>
|
||||
Serving graph: {{github_com_youtube_vitess_vtctld_srv_keyspace .Alias.Cell .Keyspace}} {{github_com_youtube_vitess_vtctld_srv_shard .Alias.Cell .Keyspace .Shard}} {{github_com_youtube_vitess_vtctld_srv_type .Alias.Cell .Keyspace .Shard .Type}}<br>
|
||||
Replication graph: {{github_com_youtube_vitess_vtctld_replication .Alias.Cell .Keyspace .Shard}}<br>
|
||||
State: {{.State}}<br>
|
||||
`
|
||||
|
||||
healthTemplate = `
|
||||
<style>
|
||||
table {
|
||||
|
@ -85,6 +94,9 @@ func healthHTMLName() template.HTML {
|
|||
|
||||
func init() {
|
||||
servenv.OnRun(func() {
|
||||
servenv.AddStatusPart("Tablet", tabletTemplate, func() interface{} {
|
||||
return agent.Tablet()
|
||||
})
|
||||
if agent.IsRunningHealthCheck() {
|
||||
servenv.AddStatusFuncs(template.FuncMap{
|
||||
"github_com_youtube_vitess_health_html_name": healthHTMLName,
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
// Copyright 2012, Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package status defines a few useful functions for our binaries,
|
||||
// mainly to link the status page with a vtctld instance.
|
||||
package status
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/servenv"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
)
|
||||
|
||||
var (
|
||||
vtctldAddr = flag.String("vtctld_addr", "", "address of a vtctld instance")
|
||||
vtctldTopoExplorer = flag.String("vtctld_topo_explorer", "zk", "topo explorer to be used in status links")
|
||||
)
|
||||
|
||||
// MakeVtctldRedirect returns an absolute vtctld url that will
|
||||
// redirect to the page for the topology object specified in q.
|
||||
func MakeVtctldRedirect(text string, q map[string]string) template.HTML {
|
||||
query := url.Values{}
|
||||
for k, v := range q {
|
||||
query.Set(k, v)
|
||||
}
|
||||
url := "/explorers/redirect" + "?" + query.Encode()
|
||||
return VtctldLink(text, url)
|
||||
}
|
||||
|
||||
// VtctldLink returns the HTML to display a link to the fully
|
||||
// qualified vtctld url whose path is given as parameter.
|
||||
// If no vtctld_addr flag was passed in, we just return the text with no link.
|
||||
func VtctldLink(text, urlPath string) template.HTML {
|
||||
if *vtctldAddr == "" {
|
||||
return template.HTML(text)
|
||||
}
|
||||
var fullURL string
|
||||
if strings.HasSuffix(*vtctldAddr, "/") {
|
||||
fullURL = *vtctldAddr + urlPath
|
||||
} else {
|
||||
fullURL = *vtctldAddr + "/" + urlPath
|
||||
}
|
||||
|
||||
return template.HTML(fmt.Sprintf(`<a href="%v">%v</a>`, fullURL, text))
|
||||
}
|
||||
|
||||
// VtctldKeyspace returns the keyspace name, possibly linked to the
|
||||
// keyspace page in vtctld.
|
||||
func VtctldKeyspace(keyspace string) template.HTML {
|
||||
return MakeVtctldRedirect(keyspace,
|
||||
map[string]string{
|
||||
"type": "keyspace",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"keyspace": keyspace,
|
||||
})
|
||||
}
|
||||
|
||||
// VtctldShard returns the shard name, possibly linked to the shard
|
||||
// page in vtctld.
|
||||
func VtctldShard(keyspace, shard string) template.HTML {
|
||||
return MakeVtctldRedirect(shard, map[string]string{
|
||||
"type": "shard",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"keyspace": keyspace,
|
||||
"shard": shard,
|
||||
})
|
||||
}
|
||||
|
||||
// VtctldSrvKeyspace returns the keyspace name, possibly linked to the
|
||||
// SrvKeyspace page in vtctld.
|
||||
func VtctldSrvKeyspace(cell, keyspace string) template.HTML {
|
||||
return MakeVtctldRedirect(keyspace, map[string]string{
|
||||
"type": "srv_keyspace",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"cell": cell,
|
||||
"keyspace": keyspace,
|
||||
})
|
||||
}
|
||||
|
||||
// VtctldSrvShard returns the shard name, possibly linked to the
|
||||
// SrvShard page in vtctld.
|
||||
func VtctldSrvShard(cell, keyspace, shard string) template.HTML {
|
||||
return MakeVtctldRedirect(shard, map[string]string{
|
||||
"type": "srv_shard",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"cell": cell,
|
||||
"keyspace": keyspace,
|
||||
"shard": shard,
|
||||
})
|
||||
}
|
||||
|
||||
// VtctldSrvType returns the tablet type, possibly linked to the
|
||||
// EndPoints page in vtctld.
|
||||
func VtctldSrvType(cell, keyspace, shard string, tabletType topo.TabletType) template.HTML {
|
||||
return MakeVtctldRedirect(string(tabletType), map[string]string{
|
||||
"type": "srv_type",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"cell": cell,
|
||||
"keyspace": keyspace,
|
||||
"shard": shard,
|
||||
"tablet_type": string(tabletType),
|
||||
})
|
||||
}
|
||||
|
||||
// VtctldReplication returns 'cell/keyspace/shard', possibly linked to the
|
||||
// ShardReplication page in vtctld.
|
||||
func VtctldReplication(cell, keyspace, shard string) template.HTML {
|
||||
return MakeVtctldRedirect(fmt.Sprintf("%v/%v/%v", cell, keyspace, shard),
|
||||
map[string]string{
|
||||
"type": "replication",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"keyspace": keyspace,
|
||||
"shard": shard,
|
||||
"cell": cell,
|
||||
})
|
||||
}
|
||||
|
||||
// VtctldTablet returns the tablet alias, possibly linked to the
|
||||
// Tablet page in vtctld.
|
||||
func VtctldTablet(aliasName string) template.HTML {
|
||||
return MakeVtctldRedirect(aliasName, map[string]string{
|
||||
"type": "tablet",
|
||||
"explorer": *vtctldTopoExplorer,
|
||||
"alias": aliasName,
|
||||
})
|
||||
}
|
||||
|
||||
func init() {
|
||||
servenv.AddStatusFuncs(template.FuncMap{
|
||||
"github_com_youtube_vitess_vtctld_keyspace": VtctldKeyspace,
|
||||
"github_com_youtube_vitess_vtctld_shard": VtctldShard,
|
||||
"github_com_youtube_vitess_vtctld_srv_keyspace": VtctldSrvKeyspace,
|
||||
"github_com_youtube_vitess_vtctld_srv_shard": VtctldSrvShard,
|
||||
"github_com_youtube_vitess_vtctld_srv_type": VtctldSrvType,
|
||||
"github_com_youtube_vitess_vtctld_replication": VtctldReplication,
|
||||
"github_com_youtube_vitess_vtctld_tablet": VtctldTablet,
|
||||
})
|
||||
}
|
|
@ -287,7 +287,8 @@ class Tablet(object):
|
|||
wait_for_state="SERVING", customrules=None,
|
||||
schema_override=None, cert=None, key=None, ca_cert=None,
|
||||
repl_extra_flags={}, sensitive_mode=False,
|
||||
target_tablet_type=None, lameduck_period=None):
|
||||
target_tablet_type=None, lameduck_period=None,
|
||||
extra_args=None):
|
||||
"""
|
||||
Starts a vttablet process, and returns it.
|
||||
The process is also saved in self.proc, so it's easy to kill as well.
|
||||
|
@ -335,6 +336,8 @@ class Tablet(object):
|
|||
'-allowed_replication_lag', '30'])
|
||||
if lameduck_period:
|
||||
args.extend(['-lameduck-period', lameduck_period])
|
||||
if extra_args:
|
||||
args.extend(extra_args)
|
||||
|
||||
stderr_fd = open(os.path.join(self.tablet_dir, "vttablet.stderr"), "w")
|
||||
# increment count only the first time
|
||||
|
|
|
@ -17,11 +17,12 @@ shard_0_spare = tablet.Tablet()
|
|||
# range 80 - ""
|
||||
shard_1_master = tablet.Tablet()
|
||||
shard_1_replica = tablet.Tablet()
|
||||
|
||||
# not assigned
|
||||
idle = tablet.Tablet()
|
||||
scrap = tablet.Tablet()
|
||||
assigned = [shard_0_master, shard_0_replica, shard_1_master, shard_1_replica]
|
||||
tablets = assigned + [idle, scrap, shard_0_spare]
|
||||
# all tablets
|
||||
tablets = [shard_0_master, shard_0_replica, shard_1_master, shard_1_replica,
|
||||
idle, scrap, shard_0_spare]
|
||||
|
||||
|
||||
class VtctldError(Exception): pass
|
||||
|
@ -58,9 +59,13 @@ class Vtctld(object):
|
|||
self.proc = utils.run_bg(args, stderr=stderr_fd)
|
||||
return self.proc
|
||||
|
||||
def process_args(self):
|
||||
return ['-vtctld_addr', 'http://localhost:%u/' % self.port]
|
||||
|
||||
|
||||
vtctld = Vtctld()
|
||||
|
||||
|
||||
def setUpModule():
|
||||
try:
|
||||
environment.topo_server_setup()
|
||||
|
@ -73,6 +78,7 @@ def setUpModule():
|
|||
tearDownModule()
|
||||
raise
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
if utils.options.skip_teardown:
|
||||
return
|
||||
|
@ -95,7 +101,7 @@ class TestVtctld(unittest.TestCase):
|
|||
utils.run_vtctl('CreateKeyspace test_keyspace')
|
||||
|
||||
shard_0_master.init_tablet( 'master', 'test_keyspace', '-80')
|
||||
shard_0_replica.init_tablet('replica', 'test_keyspace', '-80')
|
||||
shard_0_replica.init_tablet('spare', 'test_keyspace', '-80')
|
||||
shard_0_spare.init_tablet('spare', 'test_keyspace', '-80')
|
||||
shard_1_master.init_tablet( 'master', 'test_keyspace', '80-')
|
||||
shard_1_replica.init_tablet('replica', 'test_keyspace', '80-')
|
||||
|
@ -104,21 +110,28 @@ class TestVtctld(unittest.TestCase):
|
|||
|
||||
utils.run_vtctl('RebuildKeyspaceGraph test_keyspace', auto_log=True)
|
||||
|
||||
for t in assigned:
|
||||
for t in [shard_0_master, shard_1_master, shard_1_replica]:
|
||||
t.create_db('vt_test_keyspace')
|
||||
t.start_vttablet()
|
||||
t.start_vttablet(extra_args=vtctld.process_args())
|
||||
shard_0_replica.create_db('vt_test_keyspace')
|
||||
shard_0_replica.start_vttablet(extra_args=vtctld.process_args(),
|
||||
target_tablet_type='replica',
|
||||
wait_for_state='NOT_SERVING')
|
||||
|
||||
for t in scrap, idle, shard_0_spare:
|
||||
t.start_vttablet(wait_for_state='NOT_SERVING')
|
||||
t.start_vttablet(wait_for_state='NOT_SERVING',
|
||||
extra_args=vtctld.process_args())
|
||||
|
||||
scrap.scrap()
|
||||
|
||||
for t in [shard_0_master, shard_0_replica, shard_0_spare,
|
||||
shard_1_master, shard_1_replica, idle, scrap]:
|
||||
t.reset_replication()
|
||||
utils.run_vtctl('ReparentShard -force test_keyspace/-80 ' + shard_0_master.tablet_alias, auto_log=True)
|
||||
utils.run_vtctl('ReparentShard -force test_keyspace/80- ' + shard_1_master.tablet_alias, auto_log=True)
|
||||
|
||||
utils.run_vtctl('ReparentShard -force test_keyspace/-80 ' +
|
||||
shard_0_master.tablet_alias, auto_log=True)
|
||||
utils.run_vtctl('ReparentShard -force test_keyspace/80- ' +
|
||||
shard_1_master.tablet_alias, auto_log=True)
|
||||
shard_0_replica.wait_for_vttablet_state('SERVING')
|
||||
|
||||
# run checks now before we start the tablets
|
||||
utils.validate_topology()
|
||||
|
@ -130,7 +143,8 @@ class TestVtctld(unittest.TestCase):
|
|||
def test_assigned(self):
|
||||
logging.debug("test_assigned: %s", str(self.data))
|
||||
self.assertItemsEqual(self.data["Assigned"].keys(), ["test_keyspace"])
|
||||
self.assertItemsEqual(self.data["Assigned"]["test_keyspace"].keys(), ["-80", "80-"])
|
||||
self.assertItemsEqual(self.data["Assigned"]["test_keyspace"].keys(),
|
||||
["-80", "80-"])
|
||||
|
||||
def test_not_assigned(self):
|
||||
self.assertEqual(len(self.data["Idle"]), 1)
|
||||
|
@ -159,12 +173,21 @@ class TestVtctld(unittest.TestCase):
|
|||
self.assertEqual(urllib2.urlopen(base + '/explorers/redirect?type=replication&explorer=zk&keyspace=test_keyspace&shard=-80&cell=test_nj').geturl(),
|
||||
base + '/zk/test_nj/vt/replication/test_keyspace/-80')
|
||||
|
||||
|
||||
def test_serving_graph(self):
|
||||
self.assertItemsEqual(self.serving_data.keys(), ["test_keyspace"])
|
||||
self.assertItemsEqual(self.serving_data["test_keyspace"].keys(), ["-80", "80-"])
|
||||
self.assertItemsEqual(self.serving_data["test_keyspace"]["-80"].keys(), ["master", "replica"])
|
||||
self.assertEqual(len(self.serving_data["test_keyspace"]["-80"]["master"]), 1)
|
||||
self.assertItemsEqual(self.serving_data["test_keyspace"].keys(),
|
||||
["-80", "80-"])
|
||||
self.assertItemsEqual(self.serving_data["test_keyspace"]["-80"].keys(),
|
||||
["master", "replica"])
|
||||
self.assertEqual(len(self.serving_data["test_keyspace"]["-80"]["master"]),
|
||||
1)
|
||||
|
||||
def test_tablet_status(self):
|
||||
# the vttablet that has a health check has a bit more, so using it
|
||||
shard_0_replica_status = shard_0_replica.get_status()
|
||||
self.assertIn('Polling health information from MySQLReplicationLag(allowedLag=30)', shard_0_replica_status)
|
||||
self.assertIn('Alias: <a href="http://localhost:', shard_0_replica_status)
|
||||
self.assertIn('</html>', shard_0_replica_status)
|
||||
|
||||
if __name__ == '__main__':
|
||||
utils.main()
|
||||
|
|
Загрузка…
Ссылка в новой задаче