11package xds
22
33import (
4+ _ "embed"
45 "fmt"
56 "net"
67 "time"
78
9+ accesslog "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3"
810 cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
911 core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
1012 endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
@@ -21,8 +23,15 @@ import (
2123 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
2224 "google.golang.org/protobuf/types/known/anypb"
2325 "google.golang.org/protobuf/types/known/durationpb"
26+ "google.golang.org/protobuf/types/known/wrapperspb"
2427)
2528
29+ //go:embed 503.html
30+ var error503HTML string
31+
32+ //go:embed 503-dashboard.html
33+ var error503DashboardHTML string
34+
2635type Protocol string
2736
2837const (
@@ -89,12 +98,112 @@ func (b *SnapshotBuilder) Build(routes []Route, httpsRedirect bool) (*cache.Snap
8998
9099 routerFilter , _ := anypb .New (& router.Router {})
91100
101+ statusCode503Filter := & accesslog.AccessLogFilter {
102+ FilterSpecifier : & accesslog.AccessLogFilter_StatusCodeFilter {
103+ StatusCodeFilter : & accesslog.StatusCodeFilter {
104+ Comparison : & accesslog.ComparisonFilter {
105+ Op : accesslog .ComparisonFilter_EQ ,
106+ Value : & core.RuntimeUInt32 {
107+ DefaultValue : 503 ,
108+ RuntimeKey : "local_reply_503" ,
109+ },
110+ },
111+ },
112+ },
113+ }
114+
115+ dashboardHostFilter := & accesslog.AccessLogFilter {
116+ FilterSpecifier : & accesslog.AccessLogFilter_OrFilter {
117+ OrFilter : & accesslog.OrFilter {
118+ Filters : []* accesslog.AccessLogFilter {
119+ {
120+ FilterSpecifier : & accesslog.AccessLogFilter_HeaderFilter {
121+ HeaderFilter : & accesslog.HeaderFilter {
122+ Header : & route.HeaderMatcher {
123+ Name : ":authority" ,
124+ HeaderMatchSpecifier : & route.HeaderMatcher_ExactMatch {
125+ ExactMatch : "localhost" ,
126+ },
127+ },
128+ },
129+ },
130+ },
131+ {
132+ FilterSpecifier : & accesslog.AccessLogFilter_HeaderFilter {
133+ HeaderFilter : & accesslog.HeaderFilter {
134+ Header : & route.HeaderMatcher {
135+ Name : ":authority" ,
136+ HeaderMatchSpecifier : & route.HeaderMatcher_ExactMatch {
137+ ExactMatch : "proxy.localhost" ,
138+ },
139+ },
140+ },
141+ },
142+ },
143+ {
144+ FilterSpecifier : & accesslog.AccessLogFilter_HeaderFilter {
145+ HeaderFilter : & accesslog.HeaderFilter {
146+ Header : & route.HeaderMatcher {
147+ Name : ":authority" ,
148+ HeaderMatchSpecifier : & route.HeaderMatcher_ExactMatch {
149+ ExactMatch : "proxy.internal" ,
150+ },
151+ },
152+ },
153+ },
154+ },
155+ },
156+ },
157+ },
158+ }
159+
160+ localReplyConfig := & hcm.LocalReplyConfig {
161+ Mappers : []* hcm.ResponseMapper {
162+ {
163+ Filter : & accesslog.AccessLogFilter {
164+ FilterSpecifier : & accesslog.AccessLogFilter_AndFilter {
165+ AndFilter : & accesslog.AndFilter {
166+ Filters : []* accesslog.AccessLogFilter {
167+ statusCode503Filter ,
168+ dashboardHostFilter ,
169+ },
170+ },
171+ },
172+ },
173+ StatusCode : wrapperspb .UInt32 (503 ),
174+ Body : & core.DataSource {
175+ Specifier : & core.DataSource_InlineString {InlineString : error503DashboardHTML },
176+ },
177+ BodyFormatOverride : & core.SubstitutionFormatString {
178+ ContentType : "text/html; charset=UTF-8" ,
179+ Format : & core.SubstitutionFormatString_TextFormat {
180+ TextFormat : "%LOCAL_REPLY_BODY%" ,
181+ },
182+ },
183+ },
184+ {
185+ Filter : statusCode503Filter ,
186+ StatusCode : wrapperspb .UInt32 (503 ),
187+ Body : & core.DataSource {
188+ Specifier : & core.DataSource_InlineString {InlineString : error503HTML },
189+ },
190+ BodyFormatOverride : & core.SubstitutionFormatString {
191+ ContentType : "text/html; charset=UTF-8" ,
192+ Format : & core.SubstitutionFormatString_TextFormat {
193+ TextFormat : "%LOCAL_REPLY_BODY%" ,
194+ },
195+ },
196+ },
197+ },
198+ }
199+
92200 httpsHcm := & hcm.HttpConnectionManager {
93201 CodecType : hcm .HttpConnectionManager_AUTO ,
94202 StatPrefix : "https_ingress" ,
95203 StreamIdleTimeout : durationpb .New (0 ),
96204 RequestTimeout : durationpb .New (0 ),
97205 RequestHeadersTimeout : durationpb .New (0 ),
206+ LocalReplyConfig : localReplyConfig ,
98207 RouteSpecifier : & hcm.HttpConnectionManager_Rds {
99208 Rds : & hcm.Rds {
100209 ConfigSource : & core.ConfigSource {
@@ -119,6 +228,7 @@ func (b *SnapshotBuilder) Build(routes []Route, httpsRedirect bool) (*cache.Snap
119228 StreamIdleTimeout : durationpb .New (0 ),
120229 RequestTimeout : durationpb .New (0 ),
121230 RequestHeadersTimeout : durationpb .New (0 ),
231+ LocalReplyConfig : localReplyConfig ,
122232 RouteSpecifier : & hcm.HttpConnectionManager_Rds {
123233 Rds : & hcm.Rds {
124234 ConfigSource : & core.ConfigSource {
@@ -387,6 +497,7 @@ func (b *SnapshotBuilder) Build(routes []Route, httpsRedirect bool) (*cache.Snap
387497 StreamIdleTimeout : durationpb .New (0 ),
388498 RequestTimeout : durationpb .New (0 ),
389499 RequestHeadersTimeout : durationpb .New (0 ),
500+ LocalReplyConfig : localReplyConfig ,
390501 RouteSpecifier : & hcm.HttpConnectionManager_Rds {
391502 Rds : & hcm.Rds {
392503 ConfigSource : & core.ConfigSource {
0 commit comments