| 127 | } |
| 128 | |
| 129 | func (r *Ring) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
| 130 | if req.Method == http.MethodPost { |
| 131 | ingesterID := req.FormValue("forget") |
| 132 | if err := r.forget(req.Context(), ingesterID); err != nil { |
| 133 | level.Error(r.logger).Log("msg", "error forgetting instance", "err", err) |
| 134 | } |
| 135 | |
| 136 | // Implement PRG pattern to prevent double-POST and work with CSRF middleware. |
| 137 | // https://en.wikipedia.org/wiki/Post/Redirect/Get |
| 138 | |
| 139 | // http.Redirect() would convert our relative URL to absolute, which is not what we want. |
| 140 | // Browser knows how to do that, and it also knows real URL. Furthermore it will also preserve tokens parameter. |
| 141 | // Note that relative Location URLs are explicitly allowed by specification, so we're not doing anything wrong here. |
| 142 | w.Header().Set("Location", "#") |
| 143 | w.WriteHeader(http.StatusFound) |
| 144 | |
| 145 | return |
| 146 | } |
| 147 | |
| 148 | r.mtx.RLock() |
| 149 | defer r.mtx.RUnlock() |
| 150 | |
| 151 | ingesterIDs := []string{} |
| 152 | for id := range r.ringDesc.Ingesters { |
| 153 | ingesterIDs = append(ingesterIDs, id) |
| 154 | } |
| 155 | sort.Strings(ingesterIDs) |
| 156 | |
| 157 | storageLastUpdate := r.KVClient.LastUpdateTime(r.key) |
| 158 | var ingesters []ingesterDesc |
| 159 | numTokens, ownedByAz := r.countTokensByAz() |
| 160 | _, owned := r.countTokens() |
| 161 | |
| 162 | for _, id := range ingesterIDs { |
| 163 | ing := r.ringDesc.Ingesters[id] |
| 164 | heartbeatTimestamp := time.Unix(ing.Timestamp, 0) |
| 165 | state := ing.State.String() |
| 166 | if !r.IsHealthy(&ing, Reporting, storageLastUpdate) { |
| 167 | state = unhealthy |
| 168 | } |
| 169 | |
| 170 | // Format the registered timestamp. |
| 171 | registeredTimestamp := "" |
| 172 | if ing.RegisteredTimestamp != 0 { |
| 173 | registeredTimestamp = ing.GetRegisteredAt().String() |
| 174 | } |
| 175 | |
| 176 | var ownership float64 |
| 177 | var deltaOwnership float64 |
| 178 | |
| 179 | if r.cfg.ZoneAwarenessEnabled { |
| 180 | ownership = (float64(ownedByAz[id]) / float64(math.MaxUint32+1)) * 100 |
| 181 | expectedOwnership := 1 / float64(len(numTokens[ing.Zone])) * 100 |
| 182 | deltaOwnership = (1 - expectedOwnership/ownership) * 100 |
| 183 | } else { |
| 184 | ownership = (float64(owned[id]) / float64(math.MaxUint32+1)) * 100 |
| 185 | expectedOwnership := 1 / float64(len(owned)) * 100 |
| 186 | deltaOwnership = (1 - expectedOwnership/ownership) * 100 |