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>