github.com/grafana/pyroscope@v1.18.0/pkg/metastore/admin/metastore.nodes.gohtml (about) 1 <!DOCTYPE html> 2 <html data-bs-theme="dark"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 8 <title>Metastore Admin - Nodes</title> 9 10 <link rel="stylesheet" href="/static/bootstrap-5.3.3.min.css"> 11 <link rel="stylesheet" href="/static/bootstrap-icons-1.8.1.css"> 12 <link rel="stylesheet" href="/static/pyroscope-styles.css"> 13 <script src="/static/bootstrap-5.3.3.bundle.min.js"></script> 14 15 <style> 16 .card-detail-row { 17 display: flex; 18 margin-bottom: 0.5rem; 19 } 20 .card-detail-label { 21 flex: 0 0 20%; 22 font-weight: bold; 23 text-align: right; 24 padding-right: 1rem; 25 } 26 .card-detail-value { 27 flex: 0 0 80%; 28 } 29 @media (max-width: 768px) { 30 .card-detail-row { 31 flex-direction: column; 32 } 33 .card-detail-label { 34 text-align: left; 35 padding-right: 0; 36 margin-bottom: 0.25rem; 37 } 38 } 39 .card { 40 margin-bottom: 1rem; 41 } 42 </style> 43 </head> 44 <body> 45 <main> 46 <div class="container mt-5"> 47 <div class="header row border-bottom py-3 flex-column-reverse flex-sm-row"> 48 <div class="col-12 col-sm-9 text-center text-sm-start"> 49 <h1>Metastore: Grafana Pyroscope</h1> 50 </div> 51 <div class="col-12 col-sm-3 text-center text-sm-end mb-3 mb-sm-0"> 52 <a href="/"> 53 <img alt="Pyroscope logo" class="pyroscope-brand" src="/static/pyroscope-logo.png"> 54 </a> 55 </div> 56 </div> 57 <div class="row my-3"> 58 <h2> 59 Observed Leaders 60 <span 61 class="text-info ms-2" 62 data-bs-toggle="tooltip" 63 data-bs-placement="right" 64 title="Lists the leaders reported by individual Raft nodes, as well how many times each leader was observed. 65 In a healthy cluster this should show a single leader, though this may not be the case during leadership transitions."> 66 <i class="bi bi-info-circle"></i> 67 </span> 68 </h2> 69 {{ range $server, $count := .Raft.ObservedLeaders }} 70 <div class="col-12"> 71 <div class="alert alert-success" role="alert"> 72 <strong>{{ $server }}</strong> <span class="badge rounded-pill text-bg-info">{{ $count }}</span> 73 </div> 74 </div> 75 {{ end }} 76 </div> 77 78 <div class="row gy-4"> 79 <h2>Nodes</h2> 80 <form action="" method="POST"> 81 <input type="hidden" name="current-term" value="{{ .Raft.CurrentTerm }}"> 82 {{ $numNodes := .Raft.NumNodes }} 83 {{ range $index, $node := .Raft.Nodes }} 84 <div class="col-12"> 85 <div class="card"> 86 <div class="card-header"> 87 {{ $node.DiscoveryServerId }} 88 </div> 89 <div class="card-body"> 90 <div class="card-detail-row"> 91 <div class="card-detail-label">Discovery Server ID:</div> 92 <div class="card-detail-value">{{ $node.DiscoveryServerId }}</div> 93 </div> 94 <div class="card-detail-row"> 95 <div class="card-detail-label">Resolved Address:</div> 96 <div class="card-detail-value">{{ $node.ResolvedAddress }}</div> 97 </div> 98 <div class="card-detail-row"> 99 <div class="card-detail-label">Build Version:</div> 100 <div class="card-detail-value">{{ $node.BuildVersion }} (revision {{ $node.BuildRevision }})</div> 101 </div> 102 <hr/> 103 <div class="card-detail-row"> 104 <div class="card-detail-label">Raft Member:</div> 105 <div class="card-detail-value"> 106 {{ if $node.Member }} 107 <span class="badge text-bg-success">yes</span> ({{ $node.State }}) 108 {{ else }} 109 <span class="badge text-bg-warning">no</span> 110 {{ end }} 111 </div> 112 </div> 113 <div class="card-detail-row"> 114 <div class="card-detail-label">Raft Server ID:</div> 115 <div class="card-detail-value">{{ $node.RaftServerId }}</div> 116 </div> 117 <div class="card-detail-row"> 118 <div class="card-detail-label">Observed Leader:</div> 119 {{ $leaderId := $node.LeaderId }} 120 {{ if eq $leaderId ""}} 121 {{ $leaderId = "n/a "}} 122 {{ end }} 123 <div class="card-detail-value">{{ $leaderId }} (term {{ $node.CurrentTerm }})</div> 124 </div> 125 <div class="card-detail-row"> 126 <div class="card-detail-label">Commit / Applied / Last Index:</div> 127 <div class="card-detail-value">{{ $node.CommitIndex }} / {{ $node.AppliedIndex }} / {{ $node.LastIndex }}</div> 128 </div> 129 <div class="card-detail-row"> 130 <div class="card-detail-label">Peers:</div> 131 <div class="card-detail-value">{{ $node.NumPeers }} (config index {{ $node.ConfigIndex }})</div> 132 </div> 133 <div class="card-detail-row"> 134 <div class="card-detail-label">Stats:</div> 135 <div class="card-detail-value"> 136 <p class="d-inline-flex gap-1"> 137 <a class="btn btn-sm btn-info" data-bs-toggle="collapse" href="#stats-{{ $index }}" role="button" aria-expanded="false" aria-controls="stats-{{ $index }}"> 138 View 139 </a> 140 </p> 141 <div class="collapse" id="stats-{{ $index }}"> 142 <div class="card card-body"> 143 <table class="table-responsive"> 144 <tbody> 145 {{ range $k, $v := $node.Stats }} 146 <tr> 147 <td>{{ $k }}</td> 148 <td>{{ $v }}</td> 149 </tr> 150 {{ end }} 151 </tbody> 152 </table> 153 </div> 154 </div> 155 </div> 156 </div> 157 </div> 158 <div class="card-footer d-flex justify-content-between bg-transparent"> 159 <div> 160 {{ if not $node.Member }} 161 <button class="btn btn-warning" name="add" value="{{ $node.RaftServerId }}" type="submit">Join Cluster</button> 162 {{ end }} 163 {{ if and $node.Member (ne $node.State "Leader") }} 164 <button class="btn btn-warning me-2" name="promote" value="{{ $node.RaftServerId }}" type="submit">Promote</button> 165 {{ end }} 166 {{ if and (eq $node.State "Leader") (gt $numNodes 1) }} 167 <button class="btn btn-warning me-2" name="demote" value="{{ $node.RaftServerId }}" type="submit">Demote</button> 168 {{ end }} 169 </div> 170 {{ if and (and $node.Member (gt $numNodes 1)) (ne $node.State "Leader") }} 171 <div> 172 <button class="btn btn-danger center" name="remove" value="{{ $node.RaftServerId }}" type="submit">Leave Cluster</button> 173 </div> 174 {{ end }} 175 </div> 176 </div> 177 </div> 178 {{ end }} 179 </form> 180 </div> 181 182 <div class="row gy-4"> 183 <h2>Discovery</h2> 184 <div class="table-responsive"> 185 <table class="table table-bordered table-hover table-striped"> 186 <thead> 187 <tr> 188 <th>Server</th> 189 <th>Resolved Address</th> 190 </tr> 191 </thead> 192 193 <tbody> 194 {{ range .DiscoveredServers }} 195 <tr> 196 <td class="align-middle font-monospace small">{{ .Raft.ID }}</td> 197 <td class="align-middle font-monospace small">{{ .ResolvedAddress }}</td> 198 </tr> 199 {{ end }} 200 </tbody> 201 </table> 202 </div> 203 </div> 204 </div> 205 </main> 206 <footer class="footer mt-auto py-3"> 207 <div class="container"> 208 <small class="text-muted">Status @ {{ .Now.Format "2006-01-02 15:04:05.000" }}</small> 209 </div> 210 </footer> 211 <script type="text/javascript"> 212 const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]') 213 const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)) 214 </script> 215 </body> 216 </html>