istio

Форк
0
136 строк · 3.9 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package ready
16

17
import (
18
	"context"
19
	"fmt"
20

21
	admin "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
22

23
	"istio.io/istio/pilot/cmd/pilot-agent/metrics"
24
	"istio.io/istio/pilot/cmd/pilot-agent/status/util"
25
)
26

27
// Probe for readiness.
28
type Probe struct {
29
	LocalHostAddr       string
30
	AdminPort           uint16
31
	receivedFirstUpdate bool
32
	// Indicates that Envoy is ready at least once so that we can cache and reuse that probe.
33
	atleastOnceReady bool
34
	Context          context.Context
35
	// NoEnvoy so we only check config status
36
	NoEnvoy bool
37
}
38

39
type Prober interface {
40
	// Check executes the probe and returns an error if the probe fails.
41
	Check() error
42
}
43

44
var _ Prober = &Probe{}
45

46
// Check executes the probe and returns an error if the probe fails.
47
func (p *Probe) Check() error {
48
	// First, check that Envoy has received a configuration update from Pilot.
49
	if err := p.checkConfigStatus(); err != nil {
50
		return err
51
	}
52
	return p.isEnvoyReady()
53
}
54

55
// checkConfigStatus checks to make sure initial configs have been received from Pilot.
56
func (p *Probe) checkConfigStatus() error {
57
	if p.NoEnvoy {
58
		// TODO some way to verify XDS proxy -> control plane works
59
		return nil
60
	}
61
	if p.receivedFirstUpdate {
62
		return nil
63
	}
64

65
	s, err := util.GetUpdateStatusStats(p.LocalHostAddr, p.AdminPort)
66
	if err != nil {
67
		return err
68
	}
69

70
	CDSUpdated := s.CDSUpdatesSuccess > 0
71
	LDSUpdated := s.LDSUpdatesSuccess > 0
72
	if CDSUpdated && LDSUpdated {
73
		p.receivedFirstUpdate = true
74
		return nil
75
	}
76

77
	if !CDSUpdated && !LDSUpdated {
78
		return fmt.Errorf("config not received from XDS server (is Istiod running?): %s", s.String())
79
	} else if s.LDSUpdatesRejection > 0 || s.CDSUpdatesRejection > 0 {
80
		return fmt.Errorf("config received from XDS server, but was rejected: %s", s.String())
81
	}
82
	return fmt.Errorf("config not fully received from XDS server: %s", s.String())
83
}
84

85
// isEnvoyReady checks to ensure that Envoy is in the LIVE state and workers have started.
86
func (p *Probe) isEnvoyReady() error {
87
	if p.NoEnvoy {
88
		return nil
89
	}
90
	if p.Context == nil {
91
		return p.checkEnvoyReadiness()
92
	}
93
	select {
94
	case <-p.Context.Done():
95
		return fmt.Errorf("server is not live, current state is: %s", admin.ServerInfo_DRAINING.String())
96
	default:
97
		return p.checkEnvoyReadiness()
98
	}
99
}
100

101
func (p *Probe) checkEnvoyReadiness() error {
102
	// If Envoy is ready at least once i.e. server state is LIVE and workers
103
	// have started, they will not go back in the life time of Envoy process.
104
	// They will only change at hot restart or health check fails. Since istio
105
	// does not use both of them, it is safe to cache this value. Since the
106
	// actual readiness probe goes via Envoy, it ensures that Envoy is actively
107
	// serving traffic and we can rely on that.
108
	if p.atleastOnceReady {
109
		return nil
110
	}
111

112
	err := checkEnvoyStats(p.LocalHostAddr, p.AdminPort)
113
	if err == nil {
114
		metrics.RecordStartupTime()
115
		p.atleastOnceReady = true
116
	}
117
	return err
118
}
119

120
// checkEnvoyStats actually executes the Stats Query on Envoy admin endpoint.
121
func checkEnvoyStats(host string, port uint16) error {
122
	state, ws, err := util.GetReadinessStats(host, port)
123
	if err != nil {
124
		return fmt.Errorf("failed to get readiness stats: %v", err)
125
	}
126

127
	if state != nil && admin.ServerInfo_State(*state) != admin.ServerInfo_LIVE {
128
		return fmt.Errorf("server is not live, current state is: %v", admin.ServerInfo_State(*state).String())
129
	}
130

131
	if !ws {
132
		return fmt.Errorf("workers have not yet started")
133
	}
134

135
	return nil
136
}
137

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.