1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
21
admin "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
23
"istio.io/istio/pilot/cmd/pilot-agent/metrics"
24
"istio.io/istio/pilot/cmd/pilot-agent/status/util"
27
// Probe for readiness.
31
receivedFirstUpdate bool
32
// Indicates that Envoy is ready at least once so that we can cache and reuse that probe.
34
Context context.Context
35
// NoEnvoy so we only check config status
39
type Prober interface {
40
// Check executes the probe and returns an error if the probe fails.
44
var _ Prober = &Probe{}
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 {
52
return p.isEnvoyReady()
55
// checkConfigStatus checks to make sure initial configs have been received from Pilot.
56
func (p *Probe) checkConfigStatus() error {
58
// TODO some way to verify XDS proxy -> control plane works
61
if p.receivedFirstUpdate {
65
s, err := util.GetUpdateStatusStats(p.LocalHostAddr, p.AdminPort)
70
CDSUpdated := s.CDSUpdatesSuccess > 0
71
LDSUpdated := s.LDSUpdatesSuccess > 0
72
if CDSUpdated && LDSUpdated {
73
p.receivedFirstUpdate = true
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())
82
return fmt.Errorf("config not fully received from XDS server: %s", s.String())
85
// isEnvoyReady checks to ensure that Envoy is in the LIVE state and workers have started.
86
func (p *Probe) isEnvoyReady() error {
91
return p.checkEnvoyReadiness()
94
case <-p.Context.Done():
95
return fmt.Errorf("server is not live, current state is: %s", admin.ServerInfo_DRAINING.String())
97
return p.checkEnvoyReadiness()
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 {
112
err := checkEnvoyStats(p.LocalHostAddr, p.AdminPort)
114
metrics.RecordStartupTime()
115
p.atleastOnceReady = true
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)
124
return fmt.Errorf("failed to get readiness stats: %v", err)
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())
132
return fmt.Errorf("workers have not yet started")