mirror of
				https://github.com/prometheus/prometheus.git
				synced 2025-11-04 02:11:01 +01:00 
			
		
		
		
	This roughly comprises the following changes: - index target pools by job instead of scrape interval - make targets within a pool exchangable while preserving existing health state for targets - allow exchanging targets via HTTP API (PUT) - show target lists in /status (experimental, for own debug use)
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2013 Prometheus Team
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
// http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
package retrieval
 | 
						|
 | 
						|
import (
 | 
						|
	"github.com/prometheus/prometheus/retrieval/format"
 | 
						|
	"github.com/prometheus/prometheus/utility/test"
 | 
						|
	"sort"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
func testTargetPool(t test.Tester) {
 | 
						|
	type expectation struct {
 | 
						|
		size int
 | 
						|
	}
 | 
						|
 | 
						|
	type input struct {
 | 
						|
		address      string
 | 
						|
		scheduledFor time.Time
 | 
						|
	}
 | 
						|
 | 
						|
	type output struct {
 | 
						|
		address string
 | 
						|
	}
 | 
						|
 | 
						|
	var scenarios = []struct {
 | 
						|
		name    string
 | 
						|
		inputs  []input
 | 
						|
		outputs []output
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:    "empty",
 | 
						|
			inputs:  []input{},
 | 
						|
			outputs: []output{},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "single element",
 | 
						|
			inputs: []input{
 | 
						|
				{
 | 
						|
					address: "http://single.com",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			outputs: []output{
 | 
						|
				{
 | 
						|
					address: "http://single.com",
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "plural descending schedules",
 | 
						|
			inputs: []input{
 | 
						|
				{
 | 
						|
					address:      "http://plural-descending.com",
 | 
						|
					scheduledFor: time.Date(2013, 1, 4, 12, 0, 0, 0, time.UTC),
 | 
						|
				},
 | 
						|
				{
 | 
						|
					address:      "http://plural-descending.net",
 | 
						|
					scheduledFor: time.Date(2013, 1, 4, 11, 0, 0, 0, time.UTC),
 | 
						|
				},
 | 
						|
			},
 | 
						|
			outputs: []output{
 | 
						|
				{
 | 
						|
					address: "http://plural-descending.net",
 | 
						|
				},
 | 
						|
				{
 | 
						|
					address: "http://plural-descending.com",
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "plural ascending schedules",
 | 
						|
			inputs: []input{
 | 
						|
				{
 | 
						|
					address:      "http://plural-ascending.net",
 | 
						|
					scheduledFor: time.Date(2013, 1, 4, 11, 0, 0, 0, time.UTC),
 | 
						|
				},
 | 
						|
				{
 | 
						|
					address:      "http://plural-ascending.com",
 | 
						|
					scheduledFor: time.Date(2013, 1, 4, 12, 0, 0, 0, time.UTC),
 | 
						|
				},
 | 
						|
			},
 | 
						|
			outputs: []output{
 | 
						|
				{
 | 
						|
					address: "http://plural-ascending.net",
 | 
						|
				},
 | 
						|
				{
 | 
						|
					address: "http://plural-ascending.com",
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for i, scenario := range scenarios {
 | 
						|
		pool := TargetPool{}
 | 
						|
 | 
						|
		for _, input := range scenario.inputs {
 | 
						|
			target := target{
 | 
						|
				address:   input.address,
 | 
						|
				scheduler: literalScheduler(input.scheduledFor),
 | 
						|
			}
 | 
						|
 | 
						|
			pool.addTarget(&target)
 | 
						|
		}
 | 
						|
		sort.Sort(pool)
 | 
						|
 | 
						|
		if pool.Len() != len(scenario.outputs) {
 | 
						|
			t.Errorf("%s %d. expected TargetPool size to be %d but was %d", scenario.name, i, len(scenario.outputs), pool.Len())
 | 
						|
		} else {
 | 
						|
			for j, output := range scenario.outputs {
 | 
						|
				target := pool.targets[j]
 | 
						|
 | 
						|
				if target.Address() != output.address {
 | 
						|
					t.Errorf("%s %d.%d. expected Target address to be %s but was %s", scenario.name, i, j, output.address, target.Address())
 | 
						|
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if pool.Len() != len(scenario.outputs) {
 | 
						|
				t.Errorf("%s %d. expected to repopulated with %d elements, got %d", scenario.name, i, len(scenario.outputs), pool.Len())
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestTargetPool(t *testing.T) {
 | 
						|
	testTargetPool(t)
 | 
						|
}
 | 
						|
 | 
						|
func TestTargetPoolIterationWithUnhealthyTargetsFinishes(t *testing.T) {
 | 
						|
	pool := TargetPool{}
 | 
						|
	target := &target{
 | 
						|
		address:   "http://example.com/metrics.json",
 | 
						|
		scheduler: literalScheduler(time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC)),
 | 
						|
	}
 | 
						|
	pool.addTarget(target)
 | 
						|
 | 
						|
	done := make(chan bool)
 | 
						|
	go func() {
 | 
						|
		pool.runIteration(make(chan format.Result), time.Duration(0))
 | 
						|
		done <- true
 | 
						|
	}()
 | 
						|
 | 
						|
	select {
 | 
						|
	case <-done:
 | 
						|
		break
 | 
						|
	case <-time.After(time.Duration(1) * time.Second):
 | 
						|
		t.Fatalf("Targetpool iteration is stuck")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestTargetPoolReplaceTargets(t *testing.T) {
 | 
						|
	pool := TargetPool{}
 | 
						|
	oldTarget1 := &target{
 | 
						|
		address:   "http://example1.com/metrics.json",
 | 
						|
		scheduler: literalScheduler(time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC)),
 | 
						|
		state:     UNREACHABLE,
 | 
						|
	}
 | 
						|
	oldTarget2 := &target{
 | 
						|
		address:   "http://example2.com/metrics.json",
 | 
						|
		scheduler: literalScheduler(time.Date(7500, 1, 1, 0, 0, 0, 0, time.UTC)),
 | 
						|
		state:     UNREACHABLE,
 | 
						|
	}
 | 
						|
	newTarget1 := &target{
 | 
						|
		address:   "http://example1.com/metrics.json",
 | 
						|
		scheduler: literalScheduler(time.Date(5000, 1, 1, 0, 0, 0, 0, time.UTC)),
 | 
						|
		state:     ALIVE,
 | 
						|
	}
 | 
						|
	newTarget2 := &target{
 | 
						|
		address:   "http://example3.com/metrics.json",
 | 
						|
		scheduler: literalScheduler(time.Date(2500, 1, 1, 0, 0, 0, 0, time.UTC)),
 | 
						|
		state:     ALIVE,
 | 
						|
	}
 | 
						|
 | 
						|
	pool.addTarget(oldTarget1)
 | 
						|
	pool.addTarget(oldTarget2)
 | 
						|
 | 
						|
	pool.replaceTargets([]Target{newTarget1, newTarget2})
 | 
						|
	sort.Sort(pool)
 | 
						|
 | 
						|
	if pool.Len() != 2 {
 | 
						|
		t.Errorf("Expected 2 elements in pool, had %d", pool.Len())
 | 
						|
	}
 | 
						|
 | 
						|
	target1 := pool.targets[0].(*target)
 | 
						|
	if target1.state != newTarget1.state {
 | 
						|
		t.Errorf("Wrong first target returned from pool, expected %v, got %v", newTarget2, target1)
 | 
						|
	}
 | 
						|
	target2 := pool.targets[1].(*target)
 | 
						|
	if target2.state != oldTarget1.state {
 | 
						|
		t.Errorf("Wrong second target returned from pool, expected %v, got %v", oldTarget1, target2)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkTargetPool(b *testing.B) {
 | 
						|
	for i := 0; i < b.N; i++ {
 | 
						|
		testTargetPool(b)
 | 
						|
	}
 | 
						|
}
 |